DB

数据库事务

Posted by Clear Blog on April 10, 2017

事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。 数据库默认事务是自动提交的,也就是发一条sql它就执行一条,如果想多条sql放在一个事务中执行,则需要显示的声明事务开始结束: start transaction … … commit

事务的四大特性:ACID

A:atom

原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚, 因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

C:consistency

一致性,即数据处于一种有意义的状态,a+b=100.a改变了,b也得改变,否则就处于不一致状态。

I:isolution

隔离性,多个进程之间对数据的操作相互隔离,通过不同级别的锁来控制。这也就引出了事务的隔离级别这一问题

D:Durability

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

隔离级别(isolation)

由事务的隔离性引出的隔离级别,分为四种:Read Uncommitted,Read Committed,Repeatable Read,Serializable

隔离级别 脏读 重复读 幻读
Read Uncommitted true true true
Read Committed false true true
Repeatable Read false false true
Serializable false false false

@Transactional(isolation = Isolation.READ_UNCOMMITTED)

脏读

脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

不可重复读

不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

幻读

从结果上来看,幻读与不可重复读相似,多次读取的结果不一致。 导致幻读的原因是其他线程插入或者删除了数据,如果要防止幻读,需要锁表。 所以从控制的角度上来区分,不可重复读是行级锁,而幻读需要锁表,锁表也就意味着只能单线程来操作了,那就是串行访问。

串行

不允许事务并发,完全避免了脏读幻读以及不可重复读,但是影响性能。

传播属性(propagation)

@Transactional(propagation=Propagation.REQUIRED)

传播属性大致可以分为两大类,支持已有事务和不支持已有事务的。

  1. REQUIRED ,这个是默认的属性 Support a current transaction, create a new one if none exists. 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。 如图所示:

  2. MANDATORY Support a current transaction, throw an exception if none exists.支持当前事务,如果当前没有事务,就抛出异常。

  3. SUPPORTS Support a current transaction, execute non-transactionally if none exists. 支持当前事务,如果当前没有事务,就以非事务方式执行。

以上三种是支持当前事务的隔离级别。

  1. NEVER Execute non-transactionally, throw an exception if a transaction exists. 以非事务方式执行,如果当前存在事务,则抛出异常。

  2. NOT_SUPPORTED Execute non-transactionally, suspend the current transaction if one exists. 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  3. REQUIRES_NEW Create a new transaction, suspend the current transaction if one exists. 新建事务,如果当前存在事务,把当前事务挂起。 如图所示:

  4. NESTED Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else. 支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

特别说明下PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别

它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。 使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。 两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务管理器的支持。 使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。

事务超时

@Transactional(timeout=30) //默认是30秒

readonly

readonly的事务能够提高性能

rollbackFor和noRollbackFor

可以指定异常名称进行回滚, 默认情况下,spring只会针对运行期异常进行回滚,如果发生检查型异常则不会触发事务回滚。