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 的容器事务管理机制在这里即体现出其强大的能量。

二、声明式事务

声明式事务又有三种实现方法:

(第一种) 最早的方法,用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>

(第二种) 使用<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上

(第三种) 这个方法方便,使用注解来实现声明式事务, 下面详细说说这个方法:

第一步:引入<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与事务的更多相关文章

  1. Spring JdbcTemplate 与 事务管理 学习

    Spring的JDBC框架能够承担资源管理和异常处理的工作,从而简化我们的JDBC代码, 让我们只需编写从数据库读写数据所必需的代码.Spring把数据访问的样板代码隐藏到模板类之下, 结合Sprin ...

  2. Spring jdbctemplate和事务管理器 全注解配置 不使用xml

    /** * spring的配置类,相当于bean.xml */@Configuration//@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans ...

  3. Spring jdbctemplate和事务管理器

    内部bean 对象结构: @Autowiredprivate IAccountService accountService; @Service("accountService")@ ...

  4. Spring的JdbcTemplate与其事务

    JdbcTemplate:http://lehsyh.iteye.com/blog/1579737 JdbcTemplate with TransactionTemplate:http://www.c ...

  5. Spring的 JDBCTemplate和声明式事务控制

    Spring 中的 JdbcTemplate[会用] JdbcTemplate 概述 它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装.spring 框架为我们提供 ...

  6. Spring之事务管理的好处

    在以往的JDBCTemplate中事务提交成功,异常处理都是通过Try/Catch 来完成,而在Spring中.Spring容器集成了TransactionTemplate,封装了所有对事务处理的功能 ...

  7. Spring注解驱动开发之声明式事务

    前言:现今SpringBoot.SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解.原理,比如@Conditional.@Import.@Ena ...

  8. Spring:(三) --常见数据源及声明式事务配置

    Spring自带了一组数据访问框架,集成了多种数据访问技术.无论我们是直接通过 JDBC 还是像Hibernate或Mybatis那样的框架实现数据持久化,Spring都可以为我们消除持久化代码中那些 ...

  9. 重新学习Spring注解——声明式事务

    36.声明式事务-环境搭建 37.声明式事务-测试成功 38.[源码]-声明式事务-源码分析 /** * 声明式事务: * * 环境搭建: * 1.导入相关依赖 * 数据源.数据库驱动.Spring- ...

随机推荐

  1. 谈谈三层架构中Model的作用

    Model又叫实体类,这个东西,大家可能觉得不好分层.包括我以前在内,是这样理解的:UI<-->Model<-->BLL<-->Model<-->DAL ...

  2. Android AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

    AlarmManager的使用机制有的称呼为全局定时器,有的称呼为闹钟.通过对它的使用,个人觉得叫全局定时器比较合适,其实它的作用和Timer有点相似.都有两种相似的用法:(1)在指定时长后执行某项操 ...

  3. Union的妙用和注意

    对于Union我用的比较少,最近一段时间大多使用Lua,所以复习一下Union Union是共用体,顾名思义,公用一块内存 一块内存不同的访问方式 // 1.数组的便捷访问 // 一块内存两种等价的访 ...

  4. 最短路径BellmanFord , Dijsktra

    最短路径算法也是常用的图算法,在网上看到了一份c的代码,写的很清楚,今天有空给写成java的了,就当练手了.另,算法导论362页详细介绍了Bellman-Ford算法,本来打算再写个Dijsktra算 ...

  5. Session与Cookie

    Session与Cookie的比较 Cookie与Session都可以进行会话跟踪,但是实现的原理不太一样.一般情况下二者均可以满足需求,但有时候不可以使用Cookie,有时候不可以使用Session ...

  6. 《Linux内核设计与实现》读书笔记(七)- 中断处理【转】

    转自:http://www.cnblogs.com/wang_yb/archive/2013/04/19/3030345.html 中断处理一般不是纯软件来实现的,需要硬件的支持.通过对中断的学习有助 ...

  7. AE 栅格数据使用总结

    RasterBand)的数据组成,一个波段就是一个数据矩阵.对于格网数据(DEM数据)和单波段的影像数据,表现为仅仅只有一个波段数据的栅格数据集,而对于多光谱影像数据则表现为具有多个波段的栅格数据集. ...

  8. MXF素材文件交换格式深入研究

    MXF素材文件交换格式深入研究   2012-09-03 | 访问次数:262 | 新闻来源:电科网               [摘要]DCI规定数字电影需采用MXF封装音视频等节目素材内容.为了深 ...

  9. Oracle Order Management DropShip Flow for R12

    Oracle Order Management DropShip Flow for R12 Email ThisBlogThis!Share to TwitterShare to FacebookSh ...

  10. POJ 3107 Godfather (树形dp)

    题目链接 虽然题目不难,但是1A还是很爽, 只是刚开始理解错题意了,想了好久. 还有据说这个题用vector会超时,看了以后还是用邻接吧. 题意: 给一颗树,保证是一颗树,求去掉一个点以后的联通块里节 ...