SpringBoot JDBC 源码分析之——NamedParameterJdbcTemplate 查询数据返回bean对象

1,NamedParameterJdbcTemplate 查询列表java

/***测试***/

    public void   queyBeanTest(){
        String s = "select * from PT_USER ";

        List<PtUser> list = namedJdbcTemplate.query(s, new BeanPropertyRowMapper<PtUser>(PtUser.class));


        System.out.println(list);

    }

  

2,若是有参数,期间会把  参数绑定的 例如: :name 替换成 sql

源码:getPreparedStatementCreator 方法。 因此最后仍是调用  JdbcTemplate  模板。数据库

3,按源码一直走下去。下面是一个抽象类实现的模板方法。app

/** * Query using a prepared statement, allowing for a PreparedStatementCreator * and a PreparedStatementSetter. Most other query methods use this method, * but application code will always work with either a creator or a setter. * @param psc Callback handler that can create a PreparedStatement given a * Connection * @param pss object that knows how to set values on the prepared statement. * If this is null, the SQL will be assumed to contain no bind parameters. * @param rse object that will extract results. * @return an arbitrary result object, as returned by the ResultSetExtractor * @throws DataAccessException if there is any problem */
    public <T> T query( PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws DataAccessException { Assert.notNull(rse, "ResultSetExtractor must not be null"); logger.debug("Executing prepared SQL query"); return execute(psc, new PreparedStatementCallback<T>() { @Override public T doInPreparedStatement(PreparedStatement ps) throws SQLException { ResultSet rs = null; try { if (pss != null) { pss.setValues(ps); } rs = ps.executeQuery(); ResultSet rsToUse = rs; if (nativeJdbcExtractor != null) { rsToUse = nativeJdbcExtractor.getNativeResultSet(rs); } return rse.extractData(rsToUse); } finally { JdbcUtils.closeResultSet(rs); if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } }); }

4,由于一开始 咱们 用的 BeanPropertyRowMapper 类,也就是用这个类来装载返回的数据。ide

  一开始new 的时候会初始化方法。测试

  

/** * Create a new {@code BeanPropertyRowMapper}, accepting unpopulated * properties in the target bean. * <p>Consider using the {@link #newInstance} factory method instead, * which allows for specifying the mapped type once only. * @param mappedClass the class that each row should be mapped to */
    public BeanPropertyRowMapper(Class<T> mappedClass) { initialize(mappedClass); }

这个方法,实际上是把实体类的属性拆分了来存的,例如:userName 存为user_name.this

/** * Initialize the mapping metadata for the given class. * @param mappedClass the mapped class */
    protected void initialize(Class<T> mappedClass) { this.mappedClass = mappedClass; this.mappedFields = new HashMap<String, PropertyDescriptor>(); this.mappedProperties = new HashSet<String>(); PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass); for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() != null) { this.mappedFields.put(lowerCaseName(pd.getName()), pd); String underscoredName = underscoreName(pd.getName()); if (!lowerCaseName(pd.getName()).equals(underscoredName)) { this.mappedFields.put(underscoredName, pd); } this.mappedProperties.add(pd.getName()); } } }

 

  下面这个方法是最终实现,会把数据库的字段都转成小写。因此也支持Oracle 。spa

/** * Extract the values for all columns in the current row. * <p>Utilizes public setters and result set metadata. * @see java.sql.ResultSetMetaData */ @Override public T mapRow(ResultSet rs, int rowNumber) throws SQLException { Assert.state(this.mappedClass != null, "Mapped class was not specified"); T mappedObject = BeanUtils.instantiateClass(this.mappedClass); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject); initBeanWrapper(bw); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); Set<String> populatedProperties = (isCheckFullyPopulated() ? new HashSet<String>() : null); for (int index = 1; index <= columnCount; index++) { String column = JdbcUtils.lookupColumnName(rsmd, index); String field = lowerCaseName(column.replaceAll(" ", "")); PropertyDescriptor pd = this.mappedFields.get(field); if (pd != null) { try { Object value = getColumnValue(rs, index, pd); if (rowNumber == 0 && logger.isDebugEnabled()) { logger.debug("Mapping column '" + column + "' to property '" + pd.getName() +
                                "' of type '" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "'"); } try { bw.setPropertyValue(pd.getName(), value); } catch (TypeMismatchException ex) { if (value == null && this.primitivesDefaultedForNullValue) { if (logger.isDebugEnabled()) { logger.debug("Intercepted TypeMismatchException for row " + rowNumber +
                                        " and column '" + column + "' with null value when setting property '" + pd.getName() + "' of type '" + ClassUtils.getQualifiedName(pd.getPropertyType()) +
                                        "' on object: " + mappedObject, ex); } } else { throw ex; } } if (populatedProperties != null) { populatedProperties.add(pd.getName()); } } catch (NotWritablePropertyException ex) { throw new DataRetrievalFailureException( "Unable to map column '" + column + "' to property '" + pd.getName() + "'", ex); } } else { // No PropertyDescriptor found
                if (rowNumber == 0 && logger.isDebugEnabled()) { logger.debug("No property found for column '" + column + "' mapped to field '" + field + "'"); } } } if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) { throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields " +
                    "necessary to populate object of class [" + this.mappedClass.getName() + "]: " +
                    this.mappedProperties); } return mappedObject; }

总结: 由于源码就是这样写死的。因此要约定装配实体类。debug

相关文章
相关标签/搜索