SpringBoot JDBC 源码分析之——NamedParameterJdbcTemplate 查询数据返回bean对象
1,NamedParameterJdbcTemplate 查询列表
- /***测试***/
- 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 替换成 ?
源码:getPreparedStatementCreator 方法。 所以最后还是调用 JdbcTemplate 模板。
3,按源码一直走下去。下面是一个抽象类实现的模板方法。
- /**
- * 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 类,也就是用这个类来装载返回的数据。
一开始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.
- /**
- * 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 。
- /**
- * 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;
- }
总结: 因为源码就是这样写死的。所以要约定装配实体类。
SpringBoot JDBC 源码分析之——NamedParameterJdbcTemplate 查询数据返回bean对象的更多相关文章
- Solr4.8.0源码分析(5)之查询流程分析总述
Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...
- Mybatis源码分析--关联表查询及延迟加载原理(二)
在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...
- 【原创】005 | 搭上SpringBoot请求处理源码分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析S ...
- HDFS源码分析心跳汇报之数据块汇报
在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...
- Django之DRF源码分析(二)---数据校验部分
Django之DRF源码分析(二)---数据校验部分 is_valid() 源码 def is_valid(self, raise_exception=False): assert not hasat ...
- 【原创】002 | 搭上SpringBoot事务源码分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍** 该趟专车是开往Spring Boot事务源码分析的专车 专车问题 为 ...
- Spring源码分析(十八)创建bean
本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.创建bean的实例 1. autowireConstructor 2 ...
- HDFS源码分析心跳汇报之数据块增量汇报
在<HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程>一文中,我们详细了解了数据节点DataNode周期性发送心跳给名字节点NameNode的BPServiceAct ...
- 源码分析:Exchanger之数据交换器
简介 Exchanger是Java5 开始引入的一个类,它允许两个线程之间交换持有的数据.当Exchanger在一个线程中调用exchange方法之后,会阻塞等待另一个线程调用同样的exchange方 ...
随机推荐
- Sitecore CMS中查看标准字段
什么是标准字段? 标准字段是字段及其字段组的集合,用于包含有关Sitecore中项目的可配置元数据.Sitecore中继承自“标准模板”模板的任何项目都将包含这些字段. 可以在“标准模板”模板项找到/ ...
- IOS 开发体验测试问题
1.键盘收起体验 a. 文本键盘会收起,但是表情包.添加视频的键盘不会收起: b. 在会话场景中,同时进行一个点击输入框,一个向下滑,输入框中的聚焦的竖直细线不会消失:
- this上下文一致
什么是this对象 先来说说什么是this对象吧,每个函数在调用的时候都会自动获取两个特殊变量:this和arguments对象.this值具体是指哪个对象是和该函数的执行环境相关的.如果是作为对象的 ...
- Linux基础命令---添加用户useradd
useradd 创建新的系统用户,useradd指令只能以管理员的身份运行,创建的用户都在“/etc/passwd”文件中.当不加-D参数,useradd指令使用命令列来指定新帐号的设定值and使用系 ...
- 【JavaScript 6连载】五、继承的概念
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- html div重叠问题,原因分析和处理
1.现象 <!DOCTYPE html > <html> <head> <meta http-equiv="Content-Type" c ...
- jenkins3
Jenkins是基于java开发的. GitHub Git (熟练使用) Doocker (了解) Jenkins (熟练使用) Django (熟练使用) Angularjs (了解) Sentry ...
- 新做了块avr开发板--tft屏研究用
2010-05-04 14:03:00 测试效果不错,使用也方便.
- QT -- plan
QT -- 跨平台的 C++ 图形用户界面 应用程序框架 GUI介绍框架项目文件 .pro第一个QT (hello QT)父窗口 和 子窗口的区别(控件,部件,构件)信号 和 槽(信号的处理 ...
- Codeforces 237A - Free Cash
题目链接:http://codeforces.com/problemset/problem/237/A Valera runs a 24/7 fast food cafe. He magically ...