Spring中的事务问题

1.声明式事务@Transactional

如果需要添加事务在类上或者public方法上添加@Transactional注解即可,如果某些方法不需要事务可以添加 @Transactional(propagation =Propagation.NOT_SUPPORTED),例如:

@Transactional //开启事务
 public class TestServiceBean implements TestService { 
    private TestDao dao; 
   public void setDao(TestDao dao) { 
       this.dao = dao; 
 } 
    @Transactional(propagation =Propagation.NOT_SUPPORTED)//不要需要事务
    public List getAll() { 
        return null; 
    } 
}

一般情况下我们都会在Service实现类上添加@Transactional 注解开启事务。

2. 事务的传播行为

我们可以根据自己的业务需要添加不同的事务传播行为:

@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(最常用的传播行为)

@Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务

@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务

@Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常

@Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)

@Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务

3. 事务超时设置

我们还可以设置事务超时的时间,默认超时时间是30秒,可以根据业务情况适当修改时间

@Transactional(timeout=30) //事务超时时间默认是30秒,也可以自定义

4.事务的隔离级别

说到事务的隔离级别就要介绍几个名词:

脏读一个事务读取到另一个事务未提交的数据
不可重复读在同一事务中,多次读取发现同一数据返回的结果不同
幻读一个事务读取到另一个事务已提交的数据

事务的基本要素(ACID):

  1. 原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间     环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
  2. 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转    账,不可能A扣了钱,B却没收到。
  3.  隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  4. 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

@Transactional中设置事务隔离级别:

@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用

@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)

@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)

@Transactional(isolation = Isolation.SERIALIZABLE):串行化

我们MySQL数据库的默认为REPEATABLE_READ级别,可以根据需要自行调整隔离级别,隔离级别越高,越能保证数据的完整性和统一性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读,而且具有较好的并发性能

5.@Transactional注解使用注意要点

1.@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记@Transactional也不会报错,但方法没有事务功能

2.用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("运行时异常");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)

@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName() {
   throw new Exception("全部异常");
}

@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
public ItimDaoImpl getItemDaoImpl() {
   throw new RuntimeException("运行时异常");
}

3.一般地我们在业务类上方添加@Transactional注解,这样更加清晰方便事务管理

6.Controller层调用多Service层方法并使用try catch捕获异常不能回滚问题

1.如果将业务逻辑放到service层面来处理,则能够保证事务安全,即便使用了AOP来切入service方法也能保证事务安全;

2.如果多个service在controller层做业务逻辑(本身就是错误的),则不能保证事务安全。如果出现上述情况,则可以使用编程式事务管理(也就是手动控制事务)在Controller逻辑开始之前手动开启/获取事务,然后在controller逻辑结束后再根据需要提交或者回滚事务;

这里要清楚3个关于编程式事务的概念:

  • PlatformTransactionManager 平台事务管理器,spring要管理事务,必须使用事务管理器

进行事务配置时,必须配置事务管理器。

  • TransactionDefinition:事务详情(事务定义、事务属性),spring用于确定事务具体详情,

例如:隔离级别、是否只读、超时时间 等进行事务配置时,必须配置详情。spring将配置项封装到该对象实例。

  • TransactionStatus:事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。

代码案例:

//注入编程式事务管理器
@Autowired
private PlatformTransactionManager platformTransactionManager;
//注入事务详情
@Autowired
private TransactionDefinition transactionDefinition;

@Transactional(rollbackFor = Exception.class)
@RequestMapping(value = "/query", method = RequestMethod.POST)
public String getUser(String userId){
    //开启事务状态
    TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition); 
    try{
        ...各种业务逻辑
        //业务代码结束后提交事务
        platformTransactionManager.commit(transactionStatus);
    }catch(Exception e){
       e.printStackTrace();
       //出现异常事务回滚
       platformTransactionManager.rollback(transactionStatus);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值