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