- 浏览: 778774 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
萨琳娜啊:
Java读源码之Netty深入剖析网盘地址:https://p ...
Netty源码学习-FileRegion -
飞天奔月:
写得有趣 ^_^
那一年你定义了一个接口 -
GoldRoger:
第二个方法很好
java-判断一个自然数是否是某个数的平方。当然不能使用开方运算 -
bylijinnan:
<script>alert("close ...
自己动手实现Java Validation -
paul920531:
39行有个bug:"int j=new Random ...
java-蓄水池抽样-要求从N个元素中随机的抽取k个元素,其中N无法确定
Spring JdbcTemplate的batch操作最后还是利用了JDBC提供的方法,Spring只是做了一下改造和封装
JDBC的batch操作:
String sql = "INSERT INTO CUSTOMER " + "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)"; List<Customer> customers = getCustomersToInsert(); PreparedStatement pstmt = conn.prepareStatement(sql); //默认情况下auto-commit=true,会认为一个statement就是一个transaction。批量操作中要执行多个statement,因此要设置为false conn.setAutoCommit(false); for (Customer customer : customers) { pstmt.setLong(1, customer.getCustId()); pstmt.setString(2, customer.getName()); pstmt.setInt(3, customer.getAge() ); pstmt.addBatch(); } int[] count = stmt.executeBatch(); conn.commit();
分析上述代码可知,实际应用中只有两部分是会变的:一是sql语句,二是要插入的数据
Spring做的工作就是把“变”与“不变”的部分抽离开来
sql语句就作为一个String类型的参数传递好了,而插入数据的写入提取为BatchPreparedStatementSetter接口:
class MyBatchPreparedStatementSetter implements BatchPreparedStatementSetter{ private List<Customer> customers; public MyBatchPreparedStatementSetter(List<Customer> customers) { this.customers = customers; } @Override public void setValues(PreparedStatement ps, int i) throws SQLException { Customer customer = customers.get(i); ps.setLong(1, customer.getCustId()); ps.setString(2, customer.getName()); ps.setInt(3, customer.getAge() ); } @Override public int getBatchSize() { return customers.size(); } }
BatchPreparedStatementSetter通常是以匿名内部类的形式出现(模板模式):
String sql = ...; List<Customer> customers = ...; getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { Customer customer = customers.get(i); ps.setLong(1, customer.getCustId()); ps.setString(2, customer.getName()); ps.setInt(3, customer.getAge() ); } @Override public int getBatchSize() { return customers.size(); } });
接下来就是“不变”的部分了,开启PreparedStatement并执行batch操作:
JdbcTemplate的batchUpdate方法:
public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss) throws DataAccessException { return execute(sql, new PreparedStatementCallback<int[]>() { public int[] doInPreparedStatement(PreparedStatement ps) throws SQLException { try { int batchSize = pss.getBatchSize(); InterruptibleBatchPreparedStatementSetter ipss = (pss instanceof InterruptibleBatchPreparedStatementSetter ? (InterruptibleBatchPreparedStatementSetter) pss : null); if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) { for (int i = 0; i < batchSize; i++) { pss.setValues(ps, i); if (ipss != null && ipss.isBatchExhausted(i)) { break; } ps.addBatch(); } return ps.executeBatch(); } else { List<Integer> rowsAffected = new ArrayList<Integer>(); for (int i = 0; i < batchSize; i++) { pss.setValues(ps, i); if (ipss != null && ipss.isBatchExhausted(i)) { break; } rowsAffected.add(ps.executeUpdate()); } int[] rowsAffectedArray = new int[rowsAffected.size()]; for (int i = 0; i < rowsAffectedArray.length; i++) { rowsAffectedArray[i] = rowsAffected.get(i); } return rowsAffectedArray; } } finally { if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } }); }
可以看到pss.setValues(ps, i)、ps.addBatch() ps.executeBatch()等操作,是跟JDBC的一样
而且它还判断了如果不支持批量操作,则一条一条地执行
重点在PreparedStatementCallback:也是以匿名内部类的形式提供,它定义的doInPreparedStatement在execute方法中回调:
public <T> T execute(String sql, PreparedStatementCallback<T> action) throws DataAccessException { return execute(new SimplePreparedStatementCreator(sql), action); }
这一步,sql作为参数,利用PreparedStatementCreator来创建PreparedStatement
SimplePreparedStatementCreator的createPreparedStatement方法:
public PreparedStatement createPreparedStatement(Connection con) throws SQLException { return con.prepareStatement(this.sql); }
public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException { Connection con = DataSourceUtils.getConnection(getDataSource()); PreparedStatement ps = null; try { Connection conToUse = con; if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) { conToUse = this.nativeJdbcExtractor.getNativeConnection(con); } ps = psc.createPreparedStatement(conToUse); applyStatementSettings(ps); PreparedStatement psToUse = ps; if (this.nativeJdbcExtractor != null) { psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps); } T result = action.doInPreparedStatement(psToUse); handleWarnings(ps); return result; } //omitted }
这个execute方法主要就是创建PreparedStatement并回调PreparedStatementCallback的doInPreparedStatement方法,简单理解为:
Connection con = DataSourceUtils.getConnection(getDataSource()); PreparedStatement ps = null; try { ps = psc.createPreparedStatement(con); T result = action.doInPreparedStatement(ps); return result; }
其中为什么要用到nativeJdbcExtractor,官方文档是这样:
Sometimes you need to access vendor specific JDBC methods that differ from the standard JDBC API. This can be problematic if you are running in an application server or with a DataSource that wraps the Connection, Statement and ResultSet objects with its own wrapper objects. To gain access to the native objects you can configure yourJdbcTemplate or OracleLobHandler with a NativeJdbcExtractor.
因此,主要是为了取得原始的、标准的Connection, Statement and ResultSet(而不是经过包装之后的)
最后梳理一下思路,以sql语句和待插入数据(customers)这两个变量为线索:
首先,sql语句,最后会通过它创建一个PreparedStatement
其次,把数据写入的设置提取为一个接口,使用时创建匿名内部类,也就是说数据由BatchPreparedStatementSetter持有
再者,PreparedStatementCallback持有BatchPreparedStatementSetter(也就持有了数据),那它还需要有一个PreparedStatement
来执行batch操作。那这个PreparedStatement怎么提供呢?在execute方法里面回调时提供
还有一个问题,为什么在Spring JdbcTemplate的batchUpdate中,没有看到conn.setAutoCommit(false)的操作?
这是因为Spring有它自己的事务管理机制
如果你配置了JDBC的事务管理,那么DataSourceTransactionManager会自动设置
DataSourceTransactionManagerr的doBegin方法:
if (con.getAutoCommit()) { txObject.setMustRestoreAutoCommit(true); if (logger.isDebugEnabled()) { logger.debug("Switching JDBC Connection [" + con + "] to manual commit"); } con.setAutoCommit(false); }
发表评论
-
深入纠结maven的资源过滤
2016-05-13 21:47 7126关于maven的资源过滤,官方文档有个例子: <pro ... -
自己动手实现Java Validation
2015-09-18 20:37 10084参数检查用得最多的是J ... -
BeanUtils.copyProperties使用笔记
2015-07-06 22:17 32568BeanUtils.copyProperties VS Pro ... -
重新发明轮子——解析xml并实例化类
2015-03-11 21:00 1764需求如图: 说明: bl ... -
Haproxy+Keepalived高可用双机单活
2015-01-06 17:37 6590我们的应用MyApp不支持集群,但要求双机单活(两台机器:ma ... -
返回null还是empty
2014-05-16 15:35 100第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:34 2276第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:34 152第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:34 114第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:33 100第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
Spring源码学习-XML 配置方式的IoC容器启动过程分析
2014-05-15 18:46 1456以FileSystemXmlApplicationContex ... -
Spring源码学习-JdbcTemplate queryForObject
2014-05-09 19:45 2989JdbcTemplate中有两个可能会混淆的queryForO ... -
Spring源码学习-PropertyPlaceholderHelper
2014-04-25 18:47 2595今天在看Spring 3.0.0.RELEASE的源码,发现P ... -
J2EE设计模式-Intercepting Filter
2013-11-27 16:56 1502Intercepting Filter类似于职责链模式 有两种 ... -
Spring中JdbcDaoSupport的DataSource注入问题
2013-11-19 17:04 3870参考以下两篇文章: http://www.mkyong.com ... -
CAS实现单点登录(SSO)
2013-07-29 18:08 1443参考以下两篇文章,对原作者表示感谢: http://blog. ... -
《重构,改善现有代码的设计》第八章 Duplicate Observed Data
2012-12-04 20:34 1469import java.awt.Color; impor ... -
org.apache.tools.zip实现文件的压缩和解压,支持中文
2012-08-08 19:32 5059刚开始用java.util.Zip,发 ...
相关推荐
spring-jdbcTemplate实例工程
使用spring+springmvc+jdbcTemplate 数据库使用orcal、redis 完成一个webdemo
NULL 博文链接:https://rayfuxk.iteye.com/blog/2286519
spring中使用JdbcTemplate操作数据库crud,一图详解(脑图)
Spring-JdbcTemplate
Spring4--3.jdbcTemplate事务
spring-jdbc-5.2.7.RELEASE.jar,JdbcTemplate所需要的jar包。
spring-jdbc-4.2.4.RELEASE.jar,spring-tx-4.2.4.RELEASE.jar,jdbcTemplate使用的jar包
本资源是一个完整的通过Servlet-Service-Dao-JdbcTemplate访问MySQL数据库的JavaWeb Project,可以直接导入到Eclipse中进行调试运行,注意默认编译器是JDK1.8。
Spring-With-JdbcTemplate 使用JdbcTemplate完成CRUD操作的完整代码弹簧需要执行哪些操作从GitHub上导入Eclipse进行Maven安装(Git Pull)#Create DB 删除数据库manishjdbc; 创建数据库manishjdbc; 使用...
一个简单的spring的jdbcTemplate扩展
spring持久层,建立持久数据库,spring-jdbc(jdbctemplate)所需jar包 spring持久层,建立持久数据库,spring-jdbc(jdbctemplate)所需jar包
SSH笔记-Spring JdbcTemplate,使用JdbcTemplate对数据库进行操作,使用具名参数和JDBC模板,简化操作
jdbc批量方法。多个sql语句可以一起执行
springMVC配置jdbcTemplate连接oracle数据库 所需要的jar包
spring 封装了 RedisTemplate,JdbcTemplate 对象来进行对redis,jdbc的各种操作进行简化
主要使用Spring MVC框架,实现jdbcTemplate核心组件,利用注解,实现与数据库的连接
Spirng对JDBC进行过良好的封装,通过提供相应的模板和辅助类,在相当的程度上降低了我们对JDBC操作的复杂性。并且JDBC封装类库可以脱离Spring Conterxt独立使用。也就是说,即使系统没有采用Spring作为结构性框架,...
Spring Security 3.1 +Spring +Servlet+JdbcTemplate 自己找的资料,并开发成功