JdbcTemplate使用小结

Java框架

浏览数:251

2019-3-22

  org.springframework.jdbc.core.JdbcTemplate.query(String sql, Object[] args, RowMapper<StaffUnionVO> rowMapper) throws DataAccessException

1.自定义rowMapper

public class StaffUnionVO implements RowMapper<StaffUnionVO>, Serializable {
    private static final long serialVersionUID = 1544023434308856628L;

    public StaffUnionVO() {
    }
  private String code;// 员工编码
  
    private String name;// 员工姓名

  
  public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }private boolean isExistColumn(ResultSet rs, String columnName) {
        try {
            if (rs.findColumn(columnName) > 0) {
                return true;
            }
        } catch (SQLException e) {
            return false;
        }

        return false;
    }

    @Override
    public StaffUnionVO mapRow(ResultSet rs, int row) throws SQLException {
        StaffUnionVO vo = new StaffUnionVO();     
 
    if (isExistColumn(rs, "code")) vo.setCode(rs.getString("code"));
    if (isExistColumn(rs, "name")) vo.setName(rs.getString("name"));
  
    return vo; } }

  示例: List<StaffUnionVO> vos = JdbcTemplate.query(sql, new Object[0], new StaffUnionVO() );

 

2.使用BeanPropertyRowMapper

public class StaffUnionVO implements Serializable {
    private static final long serialVersionUID = 1544023434308856628L;

    public StaffUnionVO() {
    }

    private String code;// 员工编码

    private String name;// 员工姓名

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

  示例:List<StaffUnionVO> vos = JdbcTemplate.query(sql, new Object[0], BeanPropertyRowMapper.newInstance(StaffUnionVO.class));

 

  看一下 BeanPropertyRowMapper.java 的源码,可以学到不少东西。

/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/
package org.springframework.jdbc.core;

import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public class BeanPropertyRowMapper<T> implements RowMapper<T> {
    protected final Log logger = LogFactory.getLog(super.getClass());
    private Class<T> mappedClass;
    private boolean checkFullyPopulated = false;

    private boolean primitivesDefaultedForNullValue = false;
    private Map<String, PropertyDescriptor> mappedFields;
    private Set<String> mappedProperties;

    public BeanPropertyRowMapper() {
    }

    public BeanPropertyRowMapper(Class<T> mappedClass) {
        initialize(mappedClass);
    }

    public BeanPropertyRowMapper(Class<T> mappedClass, boolean checkFullyPopulated) {
        initialize(mappedClass);
        this.checkFullyPopulated = checkFullyPopulated;
    }

    public void setMappedClass(Class<T> mappedClass) {
        if (this.mappedClass == null) {
            initialize(mappedClass);
        } else if (!(this.mappedClass.equals(mappedClass)))
            throw new InvalidDataAccessApiUsageException(
                    new StringBuilder().append("The mapped class can not be reassigned to map to ").append(mappedClass)
                            .append(" since it is already providing mapping for ").append(this.mappedClass).toString());
    }

    protected void initialize(Class<T> mappedClass) {
        this.mappedClass = mappedClass;
        this.mappedFields = new HashMap();
        this.mappedProperties = new HashSet();
        PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
        for (PropertyDescriptor pd : pds)
            if (pd.getWriteMethod() != null) {
                this.mappedFields.put(pd.getName().toLowerCase(), pd);
                String underscoredName = underscoreName(pd.getName());
                if (!(pd.getName().toLowerCase().equals(underscoredName))) {
                    this.mappedFields.put(underscoredName, pd);
                }
                this.mappedProperties.add(pd.getName());
            }
    }
  //在大写的字符前加入下滑线
    private String underscoreName(String name) {
        if (!(StringUtils.hasLength(name))) {
            return "";
        }
        StringBuilder result = new StringBuilder();
        result.append(name.substring(0, 1).toLowerCase());
        for (int i = 1; i < name.length(); ++i) {
            String s = name.substring(i, i + 1);
            String slc = s.toLowerCase();
            if (!(s.equals(slc))) {
                result.append("_").append(slc);
            } else {
                result.append(s);
            }
        }
        return result.toString();
    }

    public final Class<T> getMappedClass() {
        return this.mappedClass;
    }

    public void setCheckFullyPopulated(boolean checkFullyPopulated) {
        this.checkFullyPopulated = checkFullyPopulated;
    }

    public boolean isCheckFullyPopulated() {
        return this.checkFullyPopulated;
    }

    public void setPrimitivesDefaultedForNullValue(boolean primitivesDefaultedForNullValue) {
        this.primitivesDefaultedForNullValue = primitivesDefaultedForNullValue;
    }

    public boolean isPrimitivesDefaultedForNullValue() {
        return this.primitivesDefaultedForNullValue;
    }

    public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
        Assert.state(this.mappedClass != null, "Mapped class was not specified");
        Object mappedObject = BeanUtils.instantiate(this.mappedClass);
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
        initBeanWrapper(bw);

        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();
        Set populatedProperties = (isCheckFullyPopulated()) ? new HashSet() : null;//稀少的特性

        for (int index = 1; index <= columnCount; ++index) {
            String column = JdbcUtils.lookupColumnName(rsmd, index);
            PropertyDescriptor pd = (PropertyDescriptor) this.mappedFields
                    .get(column.replaceAll(" ", "").toLowerCase());
            if (pd == null)
                continue;
            try {
                Object value = getColumnValue(rs, index, pd);
                if ((this.logger.isDebugEnabled()) && (rowNumber == 0))
                    this.logger.debug(
                            new StringBuilder().append("Mapping column '").append(column).append("' to property '")
                                    .append(pd.getName()).append("' of type ").append(pd.getPropertyType()).toString());
                try {
                    bw.setPropertyValue(pd.getName(), value);
                } catch (TypeMismatchException e) {
                    if ((value == null) && (this.primitivesDefaultedForNullValue)) {
                        this.logger.debug(new StringBuilder().append("Intercepted TypeMismatchException for row ")
                                .append(rowNumber).append(" and column '").append(column).append("' with value ")
                                .append(value).append(" when setting property '").append(pd.getName())
                                .append("' of type ").append(pd.getPropertyType()).append(" on object: ")
                                .append(mappedObject).toString());
                    } else {
                        throw e;
                    }
                }
                if (populatedProperties != null) {
                    populatedProperties.add(pd.getName());
                }
            } catch (NotWritablePropertyException ex) {
                throw new DataRetrievalFailureException(new StringBuilder().append("Unable to map column ")
                        .append(column).append(" to property ").append(pd.getName()).toString(), ex);
            }

        }

        if ((populatedProperties != null) && (!(populatedProperties.equals(this.mappedProperties)))) {
            throw new InvalidDataAccessApiUsageException(new StringBuilder()
                    .append("Given ResultSet does not contain all fields necessary to populate object of class [")
                    .append(this.mappedClass).append("]: ").append(this.mappedProperties).toString());
        }

        return mappedObject;
    }

    protected void initBeanWrapper(BeanWrapper bw) {
    }

    protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException {
        return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
    }

    public static <T> BeanPropertyRowMapper<T> newInstance(Class<T> mappedClass) {
        BeanPropertyRowMapper newInstance = new BeanPropertyRowMapper();
        newInstance.setMappedClass(mappedClass);
        return newInstance;
    }
}

  1.通过PropertyDescriptor反映射调用set和get方法

  2.HashSet、TreeSet equals方法

  AbstractSet.java

  public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Set)) return false; Collection<?> c = (Collection<?>) o; if (c.size() != size()) return false; try { return containsAll(c); } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } }

 

  3.BeanPropertyRowMapper checkFullyPopulated 默认是false,这样的话如果 sql结果集中的字段 和 DTO 字段不匹配,就会抛异常。可以手动设置这个值。

  4.PO BO VO DTO POJO DAO概念及其作用(附转换图)

 


版权声明:本文原创发表于博客园,作者为小眼儿。本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。