JdbcTemplate与事务
Spring2.0框架的事务处理有两大类:
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 声明式事务
Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。
事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。
Spring提供了如下所示的事务管理器。
这些事务的父接口都是PlatformTransactionManager。
Spring的事务管理机制是一种典型的策略模式,PlatformTransactionManager代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必须提供getTransaction()方法(开启事务)、commit()方法(提交事务)、rollback()方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时,需要底层应用服务器支持,而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类,如:WebLogicJtaTransactionManager(Oracle的WebLogic服务器提供)、UowJtaTransactionManager(IBM的WebSphere服务器提供)等。
一、编码式事务
首先,进行以下配置,假设配置文件为(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 dbcp组件提供的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 申明了一个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 的容器事务管理机制在这里即体现出其强大的能量。
二、声明式事务
声明式事务又有三种实现方法:
1 (第一种) 最早的方法,用TransactionProxyFactoryBean,他是一个有AOP代理功能的FactoryBean.他返回的对象有事务.
还要在spring的配置文件XML中配置,比较麻烦,不详细说.
<!-- 事务测试DAO -->
<bean id="go_TestPOAO" class="pic.dao.transaction_test.TestPOAOImpl" parent="go_POAOBase"></bean> <!-- 事务测试DAO 声明式事务管理 -->
<bean id="go_TestPOAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>pic.dao.transaction_test.TestPOAO</value>
</list>
</property>
<property name="target" ref="go_TestPOAO"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
2 (第二种) 使用<tx:>来实现声明式事务 ,也要在spring的配置文件XML中配置,比较麻烦,不详细说.
<tx:advice id="">
.....
</tx:advice> <aop:config>
.....
</aop:config>
采用声明式事务
1、声明式事务配置
* 配置SessionFactory
* 配置事务管理器
* 事务的传播特性
* 那些类那些方法使用事务
2、编写业务逻辑方法
* 继承HibernateDaoSupport类,使用HibernateTemplate来持久化,HibernateTemplate是Hibernate session的封装 * 默认的回滚是RuntimeException(包括继承RuntimeException的子类),普通异常不回滚
* 在编写业务逻辑方法时,最好将异常一直往上抛出,在呈现层处理(struts)
* spring的事务需要设置到业务方法上(事务边界定义到Facade类上),不要添加到Dao上
3 (第三种) 这个方法方便,使用注解来实现声明式事务, 下面详细说说这个方法:
第一步:引入<tx:>命名空间 ,在spring的配置文件中修改, beans根元素里多了三行,如下
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
第二步:在spring的配置文件中修改,将所有具有@Transactional 注解的bean自动配置为声明式事务支持
<!--JDBC事务管理器,根据你的情况使用不同的事务管理器,如果工程中有Hibernate,就用Hibernate的事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref local="dataSource"/>
</property>
</bean> <!-- 用注解来实现事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
第三步: 在接口或类的声明处 ,写一个@Transactional. 要是只的接口上写, 接口的实现类就会继承下来.
接口的实现类的具体方法,还可以覆盖类声明处的设置.
@Transactional
public class TestPOAOImpl extends POAOBase implements TestPOAO
{
@Transactional(isolation = Isolation.READ_COMMITTED)
public void test1()
{
String sql = "INSERT INTO sy_test (NAME,AGE) VALUES('注解赵云',30)";
execute(sql); sql = "INSERT INTO sy_test (NAME,AGE) VALUES('注解张飞',26)";
execute(sql); int a = 9 / 0; //异常 sql = "INSERT INTO sy_test (NAME,AGE) VALUES('注解关羽',33)";
execute(sql);
System.out.println("走完了");
}
//execute() 方法略...
}
注意的几点:
1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
2 默认情况下,一个有事务方法, 遇到RuntiomeException 时会回滚 . 遇到 受检查的异常 是不会回滚 的. 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .
@Transactional 的所有可选属性如下:
属性 | 类型 | 默认值 | 说明 |
propagation | Propagation枚举 | REQUIRED | 事务传播属性 (下有说明) |
isolation | isolation枚举 | DEFAULT | 事务隔离级别 (另有说明) |
readOnly | boolean | false | 是否只读 |
timeout | int | -1 | 超时(秒) |
rollbackFor | Class[] | {} | 需要回滚的异常类 |
rollbackForClassName | String[] | {} | 需要回滚的异常类名 |
noRollbackFor | Class[] | {} | 不需要回滚的异常类 |
noRollbackForClassName | String[] | {} | 不需要回滚的异常类名 |
JdbcTemplate与事务的更多相关文章
- Spring JdbcTemplate 与 事务管理 学习
Spring的JDBC框架能够承担资源管理和异常处理的工作,从而简化我们的JDBC代码, 让我们只需编写从数据库读写数据所必需的代码.Spring把数据访问的样板代码隐藏到模板类之下, 结合Sprin ...
- Spring jdbctemplate和事务管理器 全注解配置 不使用xml
/** * spring的配置类,相当于bean.xml */@Configuration//@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans ...
- Spring jdbctemplate和事务管理器
内部bean 对象结构: @Autowiredprivate IAccountService accountService; @Service("accountService")@ ...
- Spring的JdbcTemplate与其事务
JdbcTemplate:http://lehsyh.iteye.com/blog/1579737 JdbcTemplate with TransactionTemplate:http://www.c ...
- Spring的 JDBCTemplate和声明式事务控制
Spring 中的 JdbcTemplate[会用] JdbcTemplate 概述 它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装.spring 框架为我们提供 ...
- Spring之事务管理的好处
在以往的JDBCTemplate中事务提交成功,异常处理都是通过Try/Catch 来完成,而在Spring中.Spring容器集成了TransactionTemplate,封装了所有对事务处理的功能 ...
- Spring注解驱动开发之声明式事务
前言:现今SpringBoot.SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解.原理,比如@Conditional.@Import.@Ena ...
- Spring:(三) --常见数据源及声明式事务配置
Spring自带了一组数据访问框架,集成了多种数据访问技术.无论我们是直接通过 JDBC 还是像Hibernate或Mybatis那样的框架实现数据持久化,Spring都可以为我们消除持久化代码中那些 ...
- 重新学习Spring注解——声明式事务
36.声明式事务-环境搭建 37.声明式事务-测试成功 38.[源码]-声明式事务-源码分析 /** * 声明式事务: * * 环境搭建: * 1.导入相关依赖 * 数据源.数据库驱动.Spring- ...
随机推荐
- html 页面表单如果是disabled,则不能提交到服务器端,request.getParameter得到的将为null
html 页面表单如果是disabled,则不能提交到服务器端,request.getParameter得到的将为null 解决方法:使用hidden 利用javascript赋值,传递到后台
- 关于请求添加HttpRequestHeader
WebClient w = new WebClient(); w.Headers.Add(HttpRequestHeader.Accept, "application/json") ...
- node io.sockt 聊天应用
index.html <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset=& ...
- AE 将地图导出为图片的两种方法
在ArcGIS的开发中,我们经常需要将当前地图打印(或是转出)到图片文件中.将Map或Layout中的图象转出有两种方法,一种为通过IActiveView的OutPut函数,另外一种是通过IExpor ...
- [原]poj-2680-Choose the best route-dijkstra(基础最短路)
题目大意: 已知n 个点,m条路线,s为终点:给出m条路线及其权值:给出w个起点,求最短路! 思路:基础的dijkstra,有向无环正权最短路,只要把终点和起点 reverse考虑便可. AC代码如下 ...
- PowerDesigner15.1创建模型及生成带注释sql操作手册
转自:http://blog.csdn.net/huiwenjie168/article/details/7824029 一.创建模型 操作:file-->new Model… 快捷键:ctrl ...
- OpenJDK和OracleJDK的JVM性能有多大差距
首先要先明确OpenJDK和Sun/OracleJDK之间,以及OpenJDK 6.OpenJDK 7.OpenJDK 7u和OpenJDK 8等项目之间是什么关系,这有助于确定接下来编译要使用的JD ...
- Longest Valid Parentheses(最长有效括号)
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- jquery来跨域提交表单
说说用jquery来实现跨域提交表单 在jQuery中,我们使用json数据类型,通过getJSON方法来实现从服务端获取或发送数据,而当要向不同远程服务器端提交或者获取数据时,要采用jsonp数据类 ...
- blade全集
http://daylerees.com/codebright/blade