- 浏览: 148343 次
- 性别:
- 来自: 北京
最新评论
-
pandengzhegt:
好牛!正需要!谢谢了!
JPA 2.0 中的动态类型安全查询 -
yanlp:
万分的感谢。
仿google 的输入提示框 -
huangwenji6111:
可谓良师,在此拜谢!受益匪浅!
hibernate lazy -
jwx0925:
不错!mark!
hibernate对象状态 -
leftstick:
大有裨益,谢了!
hibernate lazy
JdbcTemplate与事务
上例中的JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还无法保证数据操作的原子性(要么全部生效,要么全部无效),如:
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'");
由 于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库中”erica”对应的记录已经被更新,如果第二个操作失败,我们 无法使得整个事务回滚到最初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致致命错误。
为了实现数据操作的原子性,我们需要在程序中引入事务逻辑,在JdbcTemplate中引入事务机制,在Spring中有两种方式:
1. 代码控制的事务管理
2. 参数化配置的事务管理
下面就这两种方式进行介绍。
代码控制的事务管理
首先,进行以下配置,假设配置文件为(Application-Context.xml):
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>
配置中包含了三个节点:
Ø dataSource
这里我们采用了apache dhcp组件提供的DataSource实现,并为其配置了
JDBC驱动、数据库URL、用户名和密码等参数。
Ø transactionManager
针对JDBC DataSource类型的数据源,我们选用了
DataSourceTransactionManager
作为事务管理组件。
如果需要使用基于容器的数据源(JNDI),我们可以采用如下配置:
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTrans
actionManager"
/>
Ø userDAO
申明了一个UserDAO Bean,并为其指定了dataSource和
transactionManger资源。
UserDAO对应的代码如下:
public class UserDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');");
jt.update(
"insert into users (id,username) values(2,
'erica');");
return null;
}
});
}
}
可 以看到,在insertUser方法中,我们引入了一个新的模板 类:org.springframework.transaction.support.TransactionTemplate。 TransactionTemplate封装了事务管理的功能,包括异常时的事务回滚,以及操作成功后的事务提交。和JdbcTemplate一样,它使 得我们无需在琐碎的try/catch/finally代码中徘徊。
在doInTransaction中进行的操作,如果抛出未捕获异常将被自动回滚,如果成功执行,则将被自动提交。
这里我们故意制造了一些异常来观察数据库操作是否回滚(通过在第二条语句中更新自增ID字段故意触发一个异常):
编写一个简单的TestCase来观察实际效果:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO");
userDAO.insertUser();
相信大家多少觉得上面的代码有点凌乱,Callback类的编写似乎也有悖于日常的编程习惯(虽然笔者觉得这一方法比较有趣,因为它巧妙的解决了笔者在早期自行开发数据访问模板中曾经遇到的问题)。
如何进一步避免上面这些问题?Spring 的容器事务管理机制在这里即体现出其强大的能量。
u 参数化配置的事务管理
在上面的Application-Context.xml增加一个事务代理(UserDAOProxy)配置,同时,由于事务由容器管理,UserDAO不再需要TransactionManager设定,将其移除:
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
上面的配置中,UserDAOProxy节点配置了一个针对userDAO bean的事务代理(由target属性指定)。
通 过transactionAttributes属性,我们指定了事务的管理策略,即对所有以insert开头的方法进行事务管理,如果被管理方法抛出异 常,则自动回滚方法中的事务,如果成功执行,则在方法完成之后进行事务提交。另一方面,对于其他方法(通过通配符*表示),则进行只读事务管理,以获得更 好的性能。
与之对应,UserDAO.insertUser的代码修改如下:
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');");
jt.update("insert into users (id,username) values (2,'erica');");
}
测试代码修改如下:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意这里须通过代理Bean"userDAOProxy"获得引用,而不是直接getBean(“userDAO”)
//此外这里还存在一个有关强制转型的潜在问题,请参见Hibernate in Spring一节后
//关于强制转型的补充描述。
UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy");
userDAO.insertUser();
可以看到,insertUser变得非常简洁。数据逻辑清晰可见,对比前面代码控制的事务管理,以及传统的JDBC操作,相信大家会有一些霍然开朗的感觉。
细 心的读者会说,这只不过将代码转移到了配置文件,并没有减少太多的工作量。这点区别也许并不重要,从应用维护的角度而言,配置化的事务管理显然更具优势。 何况,实际开发中,如果前期设计细致,方法的事务特性确定之后一般不会发生大的变动,之后频繁的维护过程中,我们只需面对代码中的数据逻辑即可。
上 面我们结合JdbcTemplate介绍了Spring中的模板操作以及事务管理机制。Spring作为一个开放式的应用开发平台。同时也针对其他组件提 供了良好的支持。在持久层,Spring提供面向了Hibernate、ibatis和JDO的模板实现,同样,这些实现也为我们的开发提供了强有力的支 持
上例中的JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还无法保证数据操作的原子性(要么全部生效,要么全部无效),如:
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'");
由 于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库中”erica”对应的记录已经被更新,如果第二个操作失败,我们 无法使得整个事务回滚到最初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致致命错误。
为了实现数据操作的原子性,我们需要在程序中引入事务逻辑,在JdbcTemplate中引入事务机制,在Spring中有两种方式:
1. 代码控制的事务管理
2. 参数化配置的事务管理
下面就这两种方式进行介绍。
代码控制的事务管理
首先,进行以下配置,假设配置文件为(Application-Context.xml):
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>
配置中包含了三个节点:
Ø dataSource
这里我们采用了apache dhcp组件提供的DataSource实现,并为其配置了
JDBC驱动、数据库URL、用户名和密码等参数。
Ø transactionManager
针对JDBC DataSource类型的数据源,我们选用了
DataSourceTransactionManager
作为事务管理组件。
如果需要使用基于容器的数据源(JNDI),我们可以采用如下配置:
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTrans
actionManager"
/>
Ø userDAO
申明了一个UserDAO Bean,并为其指定了dataSource和
transactionManger资源。
UserDAO对应的代码如下:
public class UserDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');");
jt.update(
"insert into users (id,username) values(2,
'erica');");
return null;
}
});
}
}
可 以看到,在insertUser方法中,我们引入了一个新的模板 类:org.springframework.transaction.support.TransactionTemplate。 TransactionTemplate封装了事务管理的功能,包括异常时的事务回滚,以及操作成功后的事务提交。和JdbcTemplate一样,它使 得我们无需在琐碎的try/catch/finally代码中徘徊。
在doInTransaction中进行的操作,如果抛出未捕获异常将被自动回滚,如果成功执行,则将被自动提交。
这里我们故意制造了一些异常来观察数据库操作是否回滚(通过在第二条语句中更新自增ID字段故意触发一个异常):
编写一个简单的TestCase来观察实际效果:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO");
userDAO.insertUser();
相信大家多少觉得上面的代码有点凌乱,Callback类的编写似乎也有悖于日常的编程习惯(虽然笔者觉得这一方法比较有趣,因为它巧妙的解决了笔者在早期自行开发数据访问模板中曾经遇到的问题)。
如何进一步避免上面这些问题?Spring 的容器事务管理机制在这里即体现出其强大的能量。
u 参数化配置的事务管理
在上面的Application-Context.xml增加一个事务代理(UserDAOProxy)配置,同时,由于事务由容器管理,UserDAO不再需要TransactionManager设定,将其移除:
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
上面的配置中,UserDAOProxy节点配置了一个针对userDAO bean的事务代理(由target属性指定)。
通 过transactionAttributes属性,我们指定了事务的管理策略,即对所有以insert开头的方法进行事务管理,如果被管理方法抛出异 常,则自动回滚方法中的事务,如果成功执行,则在方法完成之后进行事务提交。另一方面,对于其他方法(通过通配符*表示),则进行只读事务管理,以获得更 好的性能。
与之对应,UserDAO.insertUser的代码修改如下:
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');");
jt.update("insert into users (id,username) values (2,'erica');");
}
测试代码修改如下:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意这里须通过代理Bean"userDAOProxy"获得引用,而不是直接getBean(“userDAO”)
//此外这里还存在一个有关强制转型的潜在问题,请参见Hibernate in Spring一节后
//关于强制转型的补充描述。
UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy");
userDAO.insertUser();
可以看到,insertUser变得非常简洁。数据逻辑清晰可见,对比前面代码控制的事务管理,以及传统的JDBC操作,相信大家会有一些霍然开朗的感觉。
细 心的读者会说,这只不过将代码转移到了配置文件,并没有减少太多的工作量。这点区别也许并不重要,从应用维护的角度而言,配置化的事务管理显然更具优势。 何况,实际开发中,如果前期设计细致,方法的事务特性确定之后一般不会发生大的变动,之后频繁的维护过程中,我们只需面对代码中的数据逻辑即可。
上 面我们结合JdbcTemplate介绍了Spring中的模板操作以及事务管理机制。Spring作为一个开放式的应用开发平台。同时也针对其他组件提 供了良好的支持。在持久层,Spring提供面向了Hibernate、ibatis和JDO的模板实现,同样,这些实现也为我们的开发提供了强有力的支 持
发表评论
-
java实现Tree
2012-07-10 09:59 839/****************************** ... -
Java正则表达式应用总结
2012-05-25 12:23 1044一、概述 正则表达式是Java处理字符串、文本的重要工具。 ... -
Java编程中“为了性能”尽量要做到的一些地方
2012-05-09 17:59 889最近的机器内存又爆满 ... -
jconsole远程监控Java进程
2012-05-07 11:44 1052JDK中的工具jconsole可以很好地监控Java进程及其运 ... -
spring集成quartz
2012-04-16 15:56 2190首先,让spring框架运转起来,可以参看一下:ht ... -
JMX RMI 访问
2011-09-02 10:46 4429RMI(Remote Method Invocation) R ... -
采用开发框架quartz调度管理Job
2011-07-11 10:03 19211.所需要的第三方包:quartz-1.5.2.jarcom ... -
java类型转换
2011-05-20 17:13 882string和int之间的转换? 字符串转换成数据 ... -
java整型数与网络字节序的 byte[] 数组转换关系
2011-05-05 10:47 3747因工作需要在java和c/c++之间进行socket通信,而 ... -
线程安全总结(二)
2010-11-12 10:34 829站内很多人都问我,所谓线程的“工作内存”到底是个什么东西? ... -
java线程安全总结
2010-11-12 10:33 802java线程安全总结(二 ... -
ora-02289问题解决
2010-10-19 12:35 1600<id name="id" type ... -
JDBC的批处理操作三种方式 pstmt.addBatch();
2010-09-25 15:58 8645SQL批处理是JDBC性能优化的重要武器,经本人研究总结,批处 ... -
log4j输出多个自定义日志文件
2010-05-12 10:28 1486<转>http://hi.baidu.com/ ... -
spring任务调度
2010-04-28 09:48 1381概述 在JDK 1.3以后的版本中,Java通过java.ut ... -
JDK线程池的使用
2010-04-07 16:35 1416一、简介 线程池类为 j ... -
Java文件操作
2010-02-06 15:29 849本文汇集常用文件操作方法,包括文件的建立/检查与删除,目录的建 ... -
[JMX一步步来] 6、Model Bean
2009-12-21 11:46 1174在上一节是用apache的commons-modeler来 ... -
[JMX一步步来] 5、用Apache的commons-modeler来辅助开发JMX
2009-12-21 11:45 1055一、前言 每一个MBean都要有一个接口,比如前面的Hello ... -
[JMX一步步来] 4、动态MBean:DynamicMBean
2009-12-21 11:37 1502一、前言 动态MBean是在运行期才定义它的属性和方法 ...
相关推荐
JdbcTemplate是spring-jdbc提供的数据库核心操作类,那对JdbcTemplate进行事务控制呢?
2、配置数据源,注入JdbcTemplate,启用事务管理,注入DataSourceTransactionManager 3、传播机制 @see Propagation#REQUIRED 支持当前事务,如果没有则新建一个事务, 例:a方法调用b方法,如果a方法有事务,则b加入...
配制Spring事务和JdbcTemplate使用 配制Spring事务和JdbcTemplate使用
Spring中的JdbcTemplate,Spring中的的事务.。。。。。。。
Spring4--3.jdbcTemplate事务
主要介绍了spring实现jdbctemplate添加事务支持示例,重写JdbcTemplate增加beginTranstaion,commit,rollback方法,需要的朋友可以参考下
本资源包含了两个子项目,分别进行了springboot+jpa+jdbcTemplate的多数据源独立事务配置和jta分布式事务配置,并针对不同的情况编写了事务配置测试接口,还演示了JPA的domain一对多自动生成数据库表且不生成数据库...
Spring JdbcTemplate&声明式事务.md
https://blog.csdn.net/u012081441/article/details/80746538
day4-Spring JdbcTemplate & 声明式事务.md
①导入spring-jdbc和spring-tx坐标 ②创建数据库表和实体 ③创建JdbcTemplate对象 ④执行数据库操作
注意:只是jdbc自带的jdbctample,不能 用于整合mybatis框架的事务,我整合了,事务不起作用!!!! 按老师的说法是基于xml方式,但不准确,因为也用到了注解 <aop:aspectj-autoproxy proxy-target-class="true">...
NULL 博文链接:https://jiaozhiguang-126-com.iteye.com/blog/1673077
//jdbcTemplate.queryForObject(sql, Double.class, isbn);rowMapper public double findBookPriceByIsbn(String isbn); //更新书的库存,使书号对应的库存减num,若库存不足,则给出提示,并且不更新 public ...
SpringBoot+Atomikos分布式事务及多数据源动态切换,两种demo,两条数据源,是满足事务唯一性的,看清楚是demo
myeclipse开发,导入即可用,可以参阅http://www.cnblogs.com/shamo89/p/7326718.html
spring配置事务五种方式 代初学都参考使用
使用maven构建项目,spring mvc,spring,分别与jdbctemplate,hibernate,mybatis全注解整合,其中包括包含有spring动态代理,数据库的事务处理。以及动态数据源的切换! 最新新增了ehcache缓存的应用
涉及IoC、DI、AOP、JdbcTemplate和事务管理等核心概念。同时讲解了xml和注解两种方式使用Spring的示例。通过Spring的入门程序介绍了Spring的 IoC 和 DI 的概念,介绍了Spring的基本模块。详细介绍了对象创建的细节和...
BaseDao,jdbcTemplate,Spring AOP 事务 MVC分层 BaseDao,jdbcTemplate,Spring AOP,SpringMVC,JSP 事务