Spring事务处理

1、位置

        事务的处理一定是在service层


2、应用

        事务主要应用在DML(增、删、改)操作上


3、事务的五个维度(产生事务:出现问题会回滚)

 

(1)事务的传播行为

        当拥有事务的一个方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:(前两种是我们常用的)

传播行为含义

PROPAGATION_REQUIRED

(必须传播)

表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务(例如:有两个方法,a方法和b方法。b方法调用了a方法,若设置a方法传播机制是必须,a方法会检测b方法有不有事务,如果b方法有事务,则把a方法的事务加入进去,如果b方法没有事务,则创建一个事务。也就是required必须运行在事务当中,产生事务会回滚。)

PROPAGATION_SUPPORTS

(支持传播)

表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行(例如:有两个方法,a方法和b方法。a方法不存在事务,b方法存在事务,b方法调用了a方法,那么b方法会支持a方法加入到这个事务里面来。)

PROPAGATION_MANDATORY

表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常

PROPAGATION_REQUIRED_NEW

表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

PROPAGATION_NOT_SUPPORTED

表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

PROPAGATION_NEVER

表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常

PROPAGATION_NESTED

表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

(2)事务的隔离级别

        事务的第二个维度就是隔离级别(isolation level)。隔离级别定义了一个事务可能受其他并发事务影响的程度。 

        ①并发事务引起的问题 

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致一下的问题。

 

l  脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。

         解决办法:把数据库的事务隔离级别调整到READ_COMMITTED

l  不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。

         解决 办法:把数据库的事务隔离级别调整到REPEATABLE_READ

l  幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。

解决办法:把数据库的事务隔离级别调整到SERIALIZABLE_READ

不可重复读与幻读的区别

不可重复读的重点是修改: 

在同一事务当中, 你读取过的数据, 再次读取出来发现值不一样了 

例如:在事务1中,Mary 读取了自己的工资为1000,操作并没有完成

    con1 = getConnection();       select salary from employee empId ="Mary"; 

在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.

    con2 = getConnection();       update employee set salary = 2000;       con2.commit(); 

在事务1中,Mary 再次读取自己的工资时,工资变为了2000

    //con1       select salary from employee empId ="Mary";

在一个事务中前后两次读取的结果并不一致,导致了不可重复读。

幻读的重点在于新增或者删除: 

在同一事务当中, 第1次和第2次读出来的记录数不一样 

例如:目前工资为1000的员工有10人。事务1,读取所有工资为1000的员工。

    con1 = getConnection();       Select * from employee where salary =1000;

共读取10条记录

这时另一个事务向employee表插入了一条员工记录,工资也为1000

    con2 = getConnection();       Insert into employee(empId,salary) values("Lili",1000);       con2.commit(); 

事务1再次读取所有工资为1000的员工

    //con1       select * from employee where salary =1000; 

共读取到了11条记录,这就产生了幻像读。

从总的结果来看, 似乎不可重复读和幻读都表现为两次读取的结果不一致。但如果你从控制的角度来看, 两者的区别就比较大。 

对于前者, 只需要锁住满足条件的记录。 

对于后者, 要锁住满足条件及其相近的记录。

        ②隔离级别

隔离级别

含义

ISOLATION_DEFAULT

使用后端数据库默认的隔离级别

ISOLATION_READ_UNCOMMITTED

最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

ISOLATION_READ_COMMITTED

允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

ISOLATION_REPEATABLE_READ

对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

ISOLATION_SERIALIZABLE

最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

 

(3)只读

        事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。

(4)事务超时

        为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。        

(5)回滚规则

        事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的) 

但是你可以声明事务在遇到特定的检查型异常(编译时异常)时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值