Spring 3 - 事务管理

先参考这篇文章

数据库事务隔离级别

http://blog.csdn.net/willfcareer/article/details/5820821


在这篇文章中,我将向你展示如何使用Spring处理事务管理。

Spring事务管理的优势
  • 非常容易使用,不需要一点底层事务API的知识
  • 你的事务管理代码将与具体的事务实现分离
  • 提供了注解和XML的配置方式
  • 并不需要运行在服务器上

非常好!让我们开始一些基础信息,如果你狠了解事务的话,你可以忽略它。

概览

事务 保证你应用中(数据源)的数据保持一致。同样,你也需要熟悉ACID概念。

现在,在Java中,你可以使用纯SQL来处理事务、使用纯JDBC、Hibernate或更高层面的EJB或者Spring。

EJB要求一个应用服务器,但是我们的应用不需要。

编程式 vs. 声明式

Spring提供了两种处理事务的方式:编程式和声明式。如果你熟悉EJB的事务处理,这两种对应的方式应该是bean管理和容器管理的事务管理。

编程式 意味着你需要在业务代码中加入事务管理代码。这样非常灵活,但是维护起来比较麻烦。

声明式 意味着你将事务管理代码从业务代码中分离,只需要使用基于注解或XML的配置即可。

我们说:

  • 编程式管理在开发阶段更加灵活但是在应用生命周期中则不是很灵活
  • 声明式管理在开发阶段不是很灵活但是在应用生命周期中则更加灵活
在本文中…

我们将关注声明式事务管理.

好吧,关于我们将希望实现的和如何来实现做一个简短的讨论。

目标:

  • 一个桌面应用(也就是说,不需要服务器)
  • 使用最少的XML进行声明式事务管理

这意味着:

  • 使用Eclipse和SpringIDE创建的Maven项目
  • Spring事务管理
  • 带有启用注解的Java(我将使用Java6)
  • JPA 2.0
事务管理

首先,我们必须确定我们希望使用基于注解的事务管理。

 

当然,事务管理器本身:

     

我们使用的事务管理器是JpaTransactionManager。当然也有其他的管理器:

DataSourceTransactionManager – 用于单独的数据源和JDBC

它引用了一个名为entityManagerFactory的bean。如下:

      

基于注解的事务管理

@Transactional是你可以在任何bean的任何方法或bean本身上使用的注解。

import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional
public void doSomething(...
// ...

如果你将该注解用于bean上(也就是类级别),其中的每个公共的方法都将是受事务控制的。

注意:该注解仅仅对受Spring管理的数据源有效。如果你从其他的数据源获取数据,@Transactional将没有任何作用。

在哪里放@Transactional?

你需要将该注解放到你的业务逻辑方法(服务方法)上,而不是DAO方法中,这是一个规则。通常一个业务方法将调用很多DAO方法,并且这些方法只有在组合在一起时才有意义。

事务范围

每当一个事务方法被调用时,都要做一个决定,如何处理该事务。创建一个新事务?如果已存在,使用已有的,或者是创建新事务?使用已存在的事务,如果存在,否则失败?

为了使你可以规定它,事务范围(propagation)行为被添加了。

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional(propagation = Propagation.REQUIRED)
public void doSomething(...
// ...

如下的行为:

  • REQUIRED – 使用已存在的事务。如果不存在,创建一个新事务
  • REQUIRES_NEW – 必须启用新事务。如果已存在,那么已存在的需要被挂起
  • SUPPORTS – 如果已存在事务,在它里面运行代码。如果不存在,那么就不使用事务
  • NOT_SUPPORTED – 必须不能在事务中运行。如果已存在事务,那么需要被挂起
  • MANDATORY – 必须运行于事务中。如果没有已存在事务,它将抛出异常
  • NEVER – 一定不能运行于事务中。如果已存在事务,它将抛出异常
  • NESTED – 如果已存在事务,它将在嵌套事务中运行。否则,它运行于自己的事务中

对每个方法采用何种事务范围就取决于你了。REQUIRED是默认的。

注意:如果你使用XML来设置事务,你可以使用XML来配置这些行为。

事务隔离

并发事务引发的问题可能很难审查。

  • 丢失更新 – 两个事务都修改一行数据,如果第二个事务失败,那么所有的更新都将丢失
  • 脏读 – 读取了未提交的改变
  • 非重复读 – 一个事务对同一行数据读了两次,每次获取了不同的数据
  • 幻读(Phantom read) – 与前一个类似,只是行号不同

现在,该问题最好的解决方案是最大化事务隔离,但是在现实中,这将导致太多的资源消耗并可能导致死锁。因此,你需要如下五个隔离等级(第五个实际是最大化的事务隔离等级)。

  • DEFAULT – 使用默认的数据库隔离等级
  • READ_UNCOMMITTED – 脏读、非重复读、幻读等问题可能会出现,但是不会出现更新丢失
  • READ_COMMITTED – 非重复读、幻读可能出现
  • REPEATABLE_READ – 幻读可能出现
  • SERIALIZABLE – 所有的问题都可以避免!但是性能最差

默认的选择是DEFAULT.

HSQLDB 2.0支持READ_COMMITTED和SERIALIZABLE levels (HSQLDB FAQ).

… 那么回滚!事务回滚

使用Spring事务管理,自动回滚默认的行为是:只有非受检异常引起回滚。非受检异常是 RuntimeExceptions 和 Errors。

 import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional
public void doSomething(...
// ...

思考几秒钟!你确信你理解了吗?

  • 如果doSomething方法正常执行完毕,没有抛出任何异常,那么事务就会提交
  • 如果doSomething或它调用的任何方法抛出任何类型的异常被doSomething捕获并没有重新抛出,那么事务被提交
  • 如果doSomething或它调用的任何方法抛出了任何的受检异常并且没有被捕获或者是被重新抛出,那么事务被提交。(因此到到异常代码处之前的所有都会被提交)
  • 如果doSomething或它调用的任何方法抛出了任何的非受检异常并且没有被捕获或者是被重新抛出,那么事务将被回滚(在该事务中没有任何东西会被提交到数据库)

这是默认的行为。然而,你可能希望能为特定的情况改变它:

 @Transactional(rollbackFor = IOException.class, noRollbackFor = RuntimeException.class)
public void doSomething(...

这里,我要求事务管理器为IOException回滚异常,而对RuntimeException异常不回滚。

注意:如果你使用XML来设置事务,你可以配置这些规则。


写的不错

http://blog.csdn.net/lxzo123/article/details/5942187

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值