13

Transaction-事务隔离级别&传播行为

 2 years ago
source link: https://blog.51cto.com/u_15993308/6167569
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

数据库事务并发问题

假设现有两个事务:Transaction01和Transaction02并发执行。

  • 脏读
    [1]Transaction01将某条记录的AGE值从20修改为30。
    [2]Transaction02读取了Transaction01更新后的值:30。
    [3]Transaction01回滚,AGE值恢复到了20。
    [4]Transaction02读取到的30就是一个无效的值。
  • 不可重复读
    [1]Transaction01读取了AGE值为20。
    [2]Transaction02将AGE值修改为30。
    [3]Transaction01再次读取AGE值为30,和第一次读取不一致。
  • 幻读
    [1]Transaction01读取了STUDENT表中的一部分数据。
    [2]Transaction02向STUDENT表中插入了新的行。
    [3]Transaction01读取了STUDENT表时,多出了一些行。

隔离级别——数据库系统须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

  • 读未提交——READ UNCOMMITTED
    允许Transaction01读取Transaction02未提交的修改。
    读已提交——READ COMMITTED
    要求Transaction01只能读取Transaction02已提交的修改。
  • 可重复读——REPEATABLE READ (快照读)
    确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。(mysql下可避免所有问题)
  • 串行化——SERIALIZABLE
    确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。
    Transaction-事务隔离级别&传播行为_隔离级别
    Transaction-事务隔离级别&传播行为_MySQL_02
修改MySQL隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

如:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

查询MySQL的隔离级别
SELECT @@global.tx_isolation; //查询全局隔离级别
SELECT @@session.tx_isolation;//查询当前会话隔离级别 
SELECT @@tx_isolation;//同上


事务操作
开启事务  start transaction;
提交事务  commit;
回滚事务  rollback;

Transaction-事务隔离级别&传播行为_隔离级别_03
Transaction-事务隔离级别&传播行为_MySQL_04
Transaction-事务隔离级别&传播行为_MySQL_05
Transaction-事务隔离级别&传播行为_隔离级别_06

事务的传播行为

  • propagation-Propagation——事务的传播行为;当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
    Transaction-事务隔离级别&传播行为_隔离级别_07
@Service
public class MulService {
	@Autowired
	BookService bookService;

	@Transactional
	public void mulTx() {
		//传播行为来设置这个事务方法是不是和之前的大事务共享一个事务(使用同一条连接);
		//REQUIRED  三个共用一个事务 失败一起失败
		bookService.checkOut("Tom", "ISBN-001");
		bookService.updatePrice("ISBN-002", 998);
		//int i=10/0;
	}
}

@Transactional(propagation=Propagation.REQUIRED)
public void checkOut(String username,String isbn)

@Transactional(propagation=Propagation.REQUIRED)
public void updatePrice(String isbn,int price)
@Transactional
public void mulTx() {
	//REQUIRED  
	bookService.checkOut("Tom", "ISBN-001");
	System.out.println("checkOut完成");
	// REQUIRES_NEW 这种情况 updatePrice出现异常会往上抛出导致checkOut也回滚
	bookService.updatePrice("ISBN-002", 998);
}

@Transactional
public void mulTx() {
	// REQUIRES_NEW 
	bookService.checkOut("Tom", "ISBN-001");
	System.out.println("checkOut完成");
	// REQUIRED 这种情况 updatePrice出现异常 checkOut是新开的事务 不受影响
	bookService.updatePrice("ISBN-002", 998);
}

Transaction-事务隔离级别&传播行为_隔离级别_08
multx(){
     //REQUIRED
     A(){
        //REQUIRES_NEW
        B(){}
        //REQUIRED
        c(){}
     }
     
     //REQUIRES_NEW
     D(){
        //REQUIRED
        E(){
           //REQUIRES_NEW
           F(){
           }
        }
        //REQUIRES_NEW
        G(){}
     }
     10/0 成功的(B 以及D分支下所有)     
}   

multx(){
     //REQUIRED
     A(){
        //REQUIRES_NEW
        B(){}
        //REQUIRED
        c(){}
     }
     
     //REQUIRES_NEW
     D(){
        DDDD()//  REQUIRES_NEW不崩,REQUIRED崩
        //REQUIRED
        E(){
           //REQUIRES_NEW
           F(){
              10/0(E,G,D,A,C崩了)
           }
        }
        //REQUIRES_NEW
        G(){}
     }
 }
任何处崩,已执行的REQUIRES_NEW都会成功;

如果是REQUIRED;事务的属性都是继承于大事务的;
本类方法的嵌套调用就只是一个事务
在子事务中 设置timeout 无效的
REQUIRES_NEW:这个方法直接使用新的connection;

问题 把调用写在本类Service中

bookService.checkOut(“Tom”, “ISBN-001”);
bookService.updatePrice(“ISBN-002”, 998);

Transaction-事务隔离级别&传播行为_MySQL_09

基于XML配置的事务


<!-- 基于xml配置的事务;依赖tx名称空间和aop名称空间-->
	 <aop:config>
	 	<aop:pointcut expression="execution(* com.atguigu.ser*.*.*(..))" id="txPoint"/>
	 	<!-- 
	 	事务建议/事务增强
	 	advice-ref:指向事务管理器的配置 
	 	-->
	 	<aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"/>
	 </aop:config>
	 
	 <!--  配置事务管理器
	 transaction-manager="transactionManager":指定是配置哪个事务管理器;
	 -->
	 <tx:advice id="myAdvice" transaction-manager="transactionManager">
	 		<!--事务属性  -->
	 		<tx:attributes>
	 			<!-- 指明哪些方法是事务方法;
	 			切入点表达式只是说,事务管理器要切入这些方法,
	 			哪些方法加事务——使用tx:method指定 -->
	 			<tx:method name="*"/>
	 			<tx:method name="checkout" propagation="REQUIRED" timeout="-1"/>
	 			<tx:method name="get*" read-only="true"/>
	 		</tx:attributes>
	 </tx:advice>
	 
	 <!-- 基于注解的和配置方法的都使用:重要的用配置,不重要的用注解 -->


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK