事务 Transactional注解

前言

事务:4种事务特性,5种隔离级别,7种传播行为

一、什么是事务?

事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。

二、事务的特性(4种)

原子性 (atomicity):强调事务的不可分割;要成功都成功,要失败都失败。
一致性 (consistency):事务的执行的前后数据的完整性保持一致。
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰。
持久性(durability) :事务一旦结束,数据就持久到数据库。

三、事务的隔离级别(5种)

不考虑隔离性引发的安全性问题:
脏读:一个事务读到了另一个事务未提交的数据
不可重复读:一个事务读到另一个事务已经提交的update的数据导致多次查询结果不一致。(针对某条记录,两次查询不一致)
虚幻读:一个事务读到了另一个事务已经提交的insert的数据导致多次查询结果不一致。(针对某张表,两次查询到条数不一致,查到了多的数据)

事务隔离级别
DEFAULT这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别;
未提交读(read uncommited):脏读,不可重复读,幻读都有可能发生
已提交读(read commited):避免脏读。但是不可重复读和幻读都有可能发生;
可重复读(repeatable read):避免脏读和不可重复读,但是幻读有可能发生;
串行化的(serializable):避免以上所有读问题。
在这里插入图片描述
未提交读(read uncommited):是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。
已提交读(read commited):保证一个事物提交后才能被另外一个事务读取,另外一个事务不能读取该事物未提交的数据。
可重复读(repeatable read):这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。
串行化的(serializable):这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻读(避免三种)。

MySQL默认:可重复读
Oracle默认:已提交读

1、脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
2、不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
3、幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改或者查询,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行或者没有读到的行,就好象发生了幻觉一样。

四、事务的传播行为(7种)

保证同一个事务中
PROPAGATION_REQUIRED(required)支持当前事务,如果不存在,就新建一个(默认)
PROPAGATION_SUPPORTS(supports)支持当前事务,如果不存在,就以非事务形式处理
PROPAGATION_MANDATORY(mandatory) 支持当前事务,如果不存在,抛出异常
保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行,如果没有事务则创建新事务

即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。

在Spring种定义有7种传播行为:
1、PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
    // do something
}

单独调用methodB方法时,因为当前上下文不存在事务,所以会开启一个新的事务。 调用methodA方法时,因为当前上下文不存在事务,所以会开启一个新的事务。当执行到methodB时,methodB发现当前上下文有事务,因此就加入到当前事务中来。

2、PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

// 事务属性为SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
    // do something
}

单纯的调用methodB时,methodB方法是非事务的执行的。当调用methdA时,methodB则加入了methodA的事务中,事务地执行。

3、PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常(mandatory:强制的)

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

// 事务属性为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
    // do something
}

当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);当调用methodA时,methodB则加入到methodA的事务中,事务地执行。

4、PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
doSomeThingA();
methodB();
doSomeThingB();
// do something else
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
    // do something
}

当执行methodA()时,相当于执行了

TransactionManager tm = null;
try{
    //获得一个JTA事务管理器
    tm = getTransactionManager();
    tm.begin();//开启一个新的事务
    Transaction ts1 = tm.getTransaction();
    doSomeThing();
    tm.suspend();//挂起当前事务
    try{
        tm.begin();//重新开启第二个事务
        Transaction ts2 = tm.getTransaction();
        methodB();
        ts2.commit();//提交第二个事务
    } Catch(RunTimeException ex) {
        ts2.rollback();//回滚第二个事务
    } finally {
        //释放资源
    }
    //methodB执行完后,恢复第一个事务
    tm.resume(ts1);
    doSomeThingB();
    ts1.commit();//提交第一个事务
} catch(RunTimeException ex) {
    ts1.rollback();//回滚第一个事务
} finally {
    //释放资源
}

在这里,我把ts1称为外层事务,ts2称为内层事务。从上面的代码可以看出,ts2与ts1是两个独立的事务,互不相干。Ts2是否成功并不依赖于 ts1。如果methodA方法在调用methodB方法后的doSomeThingB方法失败了,而methodB方法所做的结果依然被提交。而除了 methodB之外的其它代码导致的结果却被回滚了

5、PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
 methodC();
}

// 事务属性为NOT_SUPPORTED
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() {
    // do something
}

// 事务属性为NOT_SUPPORTED
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodC() {
    // do something
}

methodB和methodC 的注解为 NOT_SUPPORTED,即这两个方法是不需要加入事务中的,所以methodB和methodC是没有加入 A 的事务中去的,所以哪怕methodB或methodC抛出异常,由于不参会事务,所以 B 和 C 的数据都是不会回滚的。

6、PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB();
// do something else
}

@Transactional(propagation = Propagation.PROPAGATION_NEVER)
public void methodB() {
    // do something
}

当调用methodA时,会报错 org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’。因为methodB是以非事务的方式去运行,如果有事务,则抛出异常。

7、PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行

@Transactional(propagation = Propagation.REQUIRED)
methodA(){
  doSomeThingA();
  methodB();
  doSomeThingB();
}

@Transactional(propagation = Propagation.NESTED)
methodB(){
  ……
}

如果单独调用methodB方法,则按REQUIRED属性执行。如果调用methodA方法,相当于下面的效果

Connection con = null;
Savepoint savepoint = null;
try{
    con = getConnection();
    con.setAutoCommit(false);
    doSomeThingA();
    savepoint = con2.setSavepoint();
    try{
        methodB();
    } catch(RuntimeException ex) {
        con.rollback(savepoint);
    } finally {
        //释放资源
    }
    doSomeThingB();
    con.commit();
} catch(RuntimeException ex) {
    con.rollback();
} finally {
    //释放资源
}

当methodB方法调用之前,调用setSavepoint方法,保存当前的状态到savepoint。如果methodB方法调用失败,则恢复到之前保存的状态。但是需要注意的是,这时的事务并没有进行提交,如果后续的代码(doSomeThingB()方法)调用失败,则回滚包括methodB方法的所有操作。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

参考别人,记录一下,好好学习,天天向上…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值