本文主要介绍下spring jdbc的RowMapper

RowMapper

spring-jdbc-4.3.10.RELEASE-sources.jar!/org/springframework/jdbc/core/RowMapper.java

public interface RowMapper<T> {/*** Implementations must implement this method to map each row of data* in the ResultSet. This method should not call {@code next()} on* the ResultSet; it is only supposed to map values of the current row.* @param rs the ResultSet to map (pre-initialized for the current row)* @param rowNum the number of the current row* @return the result object for the current row* @throws SQLException if a SQLException is encountered getting* column values (that is, there's no need to catch SQLException)*/T mapRow(ResultSet rs, int rowNum) throws SQLException;}复制代码

spring定义了这个RowMapper,来让应用去自定义数据库结果集与实体的映射,这样来把变化的部分隔离出去

ColumnMapRowMapper

spring-jdbc-4.3.7.RELEASE-sources.jar!/org/springframework/jdbc/core/ColumnMapRowMapper.java

public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {@Overridepublic Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {ResultSetMetaData rsmd = rs.getMetaData();int columnCount = rsmd.getColumnCount();Map<String, Object> mapOfColValues = createColumnMap(columnCount);for (int i = 1; i <= columnCount; i++) {String key = getColumnKey(JdbcUtils.lookupColumnName(rsmd, i));Object obj = getColumnValue(rs, i);mapOfColValues.put(key, obj);}return mapOfColValues;}/*** Create a Map instance to be used as column map.* <p>By default, a linked case-insensitive Map will be created.* @param columnCount the column count, to be used as initial* capacity for the Map* @return the new Map instance* @see org.springframework.util.LinkedCaseInsensitiveMap*/protected Map<String, Object> createColumnMap(int columnCount) {return new LinkedCaseInsensitiveMap<Object>(columnCount);}/*** Determine the key to use for the given column in the column Map.* @param columnName the column name as returned by the ResultSet* @return the column key to use* @see java.sql.ResultSetMetaData#getColumnName*/protected String getColumnKey(String columnName) {return columnName;}/*** Retrieve a JDBC object value for the specified column.* <p>The default implementation uses the {@code getObject} method.* Additionally, this implementation includes a "hack" to get around Oracle* returning a non standard object for their TIMESTAMP datatype.* @param rs is the ResultSet holding the data* @param index is the column index* @return the Object returned* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue*/protected Object getColumnValue(ResultSet rs, int index) throws SQLException {return JdbcUtils.getResultSetValue(rs, index);}}复制代码

将结果集映射为map

SingleColumnRowMapper

spring-jdbc-4.3.10.RELEASE-sources.jar!/org/springframework/jdbc/core/SingleColumnRowMapper.java

public class SingleColumnRowMapper<T> implements RowMapper<T> {private Class<?> requiredType;/*** Create a new {@code SingleColumnRowMapper} for bean-style configuration.* @see #setRequiredType*/public SingleColumnRowMapper() {}/*** Create a new {@code SingleColumnRowMapper}.* <p>Consider using the {@link #newInstance} factory method instead,* which allows for specifying the required type once only.* @param requiredType the type that each result object is expected to match*/public SingleColumnRowMapper(Class<T> requiredType) {setRequiredType(requiredType);}/*** Set the type that each result object is expected to match.* <p>If not specified, the column value will be exposed as* returned by the JDBC driver.*/public void setRequiredType(Class<T> requiredType) {this.requiredType = ClassUtils.resolvePrimitiveIfNecessary(requiredType);}/*** Extract a value for the single column in the current row.* <p>Validates that there is only one column selected,* then delegates to {@code getColumnValue()} and also* {@code convertValueToRequiredType}, if necessary.* @see java.sql.ResultSetMetaData#getColumnCount()* @see #getColumnValue(java.sql.ResultSet, int, Class)* @see #convertValueToRequiredType(Object, Class)*/@Override@SuppressWarnings("unchecked")public T mapRow(ResultSet rs, int rowNum) throws SQLException {// Validate column count.ResultSetMetaData rsmd = rs.getMetaData();int nrOfColumns = rsmd.getColumnCount();if (nrOfColumns != 1) {throw new IncorrectResultSetColumnCountException(1, nrOfColumns);}// Extract column value from JDBC ResultSet.Object result = getColumnValue(rs, 1, this.requiredType);if (result != null && this.requiredType != null && !this.requiredType.isInstance(result)) {// Extracted value does not match already: try to convert it.try {return (T) convertValueToRequiredType(result, this.requiredType);}catch (IllegalArgumentException ex) {throw new TypeMismatchDataAccessException("Type mismatch affecting row number " + rowNum + " and column type '" +rsmd.getColumnTypeName(1) + "': " + ex.getMessage());}}return (T) result;}/*** Retrieve a JDBC object value for the specified column.* <p>The default implementation calls* {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}.* If no required type has been specified, this method delegates to* {@code getColumnValue(rs, index)}, which basically calls* {@code ResultSet.getObject(index)} but applies some additional* default conversion to appropriate value types.* @param rs is the ResultSet holding the data* @param index is the column index* @param requiredType the type that each result object is expected to match* (or {@code null} if none specified)* @return the Object value* @throws SQLException in case of extraction failure* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)* @see #getColumnValue(java.sql.ResultSet, int)*/protected Object getColumnValue(ResultSet rs, int index, Class<?> requiredType) throws SQLException {if (requiredType != null) {return JdbcUtils.getResultSetValue(rs, index, requiredType);}else {// No required type specified -> perform default extraction.return getColumnValue(rs, index);}}/*** Retrieve a JDBC object value for the specified column, using the most* appropriate value type. Called if no required type has been specified.* <p>The default implementation delegates to {@code JdbcUtils.getResultSetValue()},* which uses the {@code ResultSet.getObject(index)} method. Additionally,* it includes a "hack" to get around Oracle returning a non-standard object for* their TIMESTAMP datatype. See the {@code JdbcUtils#getResultSetValue()}* javadoc for details.* @param rs is the ResultSet holding the data* @param index is the column index* @return the Object value* @throws SQLException in case of extraction failure* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int)*/protected Object getColumnValue(ResultSet rs, int index) throws SQLException {return JdbcUtils.getResultSetValue(rs, index);}/*** Convert the given column value to the specified required type.* Only called if the extracted column value does not match already.* <p>If the required type is String, the value will simply get stringified* via {@code toString()}. In case of a Number, the value will be* converted into a Number, either through number conversion or through* String parsing (depending on the value type).* @param value the column value as extracted from {@code getColumnValue()}* (never {@code null})* @param requiredType the type that each result object is expected to match* (never {@code null})* @return the converted value* @see #getColumnValue(java.sql.ResultSet, int, Class)*/@SuppressWarnings("unchecked")protected Object convertValueToRequiredType(Object value, Class<?> requiredType) {if (String.class == requiredType) {return value.toString();}else if (Number.class.isAssignableFrom(requiredType)) {if (value instanceof Number) {// Convert original Number to target Number class.return NumberUtils.convertNumberToTargetClass(((Number) value), (Class<Number>) requiredType);}else {// Convert stringified value to target Number class.return NumberUtils.parseNumber(value.toString(),(Class<Number>) requiredType);}}else {throw new IllegalArgumentException("Value [" + value + "] is of type [" + value.getClass().getName() +"] and cannot be converted to required type [" + requiredType.getName() + "]");}}/*** Static factory method to create a new {@code SingleColumnRowMapper}* (with the required type specified only once).* @param requiredType the type that each result object is expected to match* @since 4.1*/public static <T> SingleColumnRowMapper<T> newInstance(Class<T> requiredType) {return new SingleColumnRowMapper<T>(requiredType);}}复制代码

映射单个字段,比如count(*)这种

BeanPropertyRowMapper

spring-jdbc-4.3.7.RELEASE-sources.jar!/org/springframework/jdbc/core/BeanPropertyRowMapper.java

public class BeanPropertyRowMapper<T> implements RowMapper<T> {
//...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());}}}@Overridepublic 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 foundif (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;}
}复制代码

初始化构造map的时候,存的key是下划线的
如果数据库字段命名跟实体类一致,或者是下划线变驼峰的这种,那么可以直接使用这个

实例

  • 使用BeanPropertyRowMapper的版本

    public Book findById(Integer id){return jdbcTemplate.query("select * from book where book_id=?",new Object[]{id},new BeanPropertyRowMapper<Book>(Book.class)).get(0);}复制代码
  • 不使用BeanPropertyRowMapper的版本

    public Book findById2(Integer id){return jdbcTemplate.query("select * from book where book_id=?",new Object[]{id},new RowMapper<Book>() {@Overridepublic Book mapRow(ResultSet rs, int rowNum) throws SQLException {Book book = new Book();book.setBookId(rs.getInt("book_id"));book.setTitle(rs.getString("title"));book.setCreatedAt(rs.getTimestamp("created_at"));return book;}}).get(0);}复制代码

有没有发现使用了BeanPropertyRowMapper更为简洁。

聊聊spring jdbc的RowMapper相关推荐

  1. Java EE---通过Spring JDBC实现数据库的增、删、改、查

    Spring JDBC之update.query方法 1.项目清单 2.全部代码 2.1.student 2.2.stuDao 2.3.applicationContext.xml 2.4.test ...

  2. Spring JDBC详解

    <Spring JDBC详解> 本文旨在讲述Spring JDBC模块的用法.Spring JDBC模块是Spring框架的基础模块之一. 一.概述 在Spring JDBC模块中,所有的 ...

  3. 使用Spring JDBC框架连接并操作数据库

    在前一篇博文JAVA通过JDBC连接并操作MySQL数据库中,我们知道如何通过JDBC连接并操作数据库,但是请看程序,整个程序连接数据库和关闭数据库占了很大一部分代码量,而且每次我们执行一下数据库操作 ...

  4. Spring JDBC-使用Spring JDBC获取本地连接对象以及操作BLOB/CLOB类型数据

    概述 如何获取本地数据连接 示例从DBCP数据源中获取Oracle的本地连接对象 相关接口操作 LobCreator LobHandler 插入LOB类型的数据 以块数据的方式读取LOB数据 以流数据 ...

  5. Spring JDBC-使用Spring JDBC访问数据库

    概述 使用Spring JDBC 基本的数据操作 更改数据 返回数据库表的自增主键值 批量更改数据 查询数据 使用RowCallbackHandler处理结果集 使用RowMapperT处理结果集 R ...

  6. Spring JDBC整合

    1.首先导入包: 2.然后建立数据库表 CREATE DATABASE day36; USE day36; CREATE TABLE t_user( id INT PRIMARY KEY, NAME ...

  7. 使用Spring JDBC进行数据访问 (JdbcTemplate/NamedParameterJdbcTemplate/SimpleJdbcTemplate/SimpleJdbcCall/Stor)

    http://www.cnblogs.com/webcc/archive/2012/04/11/2442680.html 使用Spring JDBC进行数据访问 11.1. 简介 Spring JDB ...

  8. Spring JDBC 框架一个最简单的Hello World级别的例子

    本地安装mySQL数据库社区版,如果不知道如何安装,可以查看我这篇文章: MySQL社区版的下载和安装 https://blog.csdn.net/i042416/article/details/10 ...

  9. Spring JDBC的学习

    文章目录 介绍 使用步骤 常用方法 示例代码 介绍 所谓 Spring JDBC,是 Spring 框架对 JDBC 的简单封装.提供了一个 JdbcTemplate 对象简化 JDBC 的开发. 使 ...

最新文章

  1. 数据蒋堂 | 大数据计算语法的SQL化
  2. Java7之线程池ForkJoinPool
  3. SpringBoot中通过@Value获取自定义配置的值
  4. BZOJ 3990: [SDOI2015]排序(搜索+剪枝)
  5. 企业级服务器固态硬盘,用户如何选择企业级SSD?_Intel服务器CPU_企业存储技术与评测-中关村在线...
  6. 【收集】Python 微优化
  7. 理论基础 —— 队列
  8. 蚂蚁金服 AntV 开源地理可视化引擎 L7 2.0 发布
  9. 这可能是目前最全的Redis高可用技术解决方案总结
  10. 南京工程学院《DSP技术及应用》期末试卷
  11. LayUI树形表格treetable使用详解
  12. 大学群管机器人的建设畅想
  13. sass(css) 分层构架
  14. 数字货币智能合约:分析以太坊信标链
  15. 中国网络游戏未来发展方向
  16. 在搜索框里添加放大镜的图标,且显示提示信息
  17. java stream转byte[ ]
  18. 一些API函数(Console居多)Console API
  19. 西安电子科大计算机学院院长,董伟生 | 个人信息 | 西安电子科技大学个人主页...
  20. fopen函数的打开模式

热门文章

  1. 哈希算法和时间复杂度
  2. 在Microsoft Edge兼容模式打开Internet Explorer站点(永久)
  3. Matlab系列之二维图形(上)
  4. FFmpeg命令行实现两路/多路视频拼接 合并 合成 同时播放
  5. 一台计算机中 虚拟机数量取决于,虚拟机对电脑伤害大吗
  6. VMwar 不支持Intel VT-x,但Intel VT-x处于禁用状态
  7. sqlite 数据库查询姓氏人口
  8. 【spring-boot-雷神】4、开发小技巧(2021-10-29
  9. IBDP学生如何申请中国香港的大学?
  10. JVM详解【三】JVM的内存结构