Spring 中的事务(Transaction)处理

1.事务定义?
  事务(transaction)是一个不可分割逻辑工作单元.例如
  转账,存钱,下订单等都可以看成一个事务.
2.事务的四大特性:
  1)原子性(事务逻辑中的操作要么都执行要么不执行.)
  2)一致性(事务前后数据状态应该是一致的);
  3)隔离性(多个事务并发执行时应是相互隔离的)
  4)持久性(事务一旦提交或回滚事务状态将会持久性发生变化)


 FAQ?
 1)如何保证一个业务中多个操作要么都执行,要么都不执行?
 2)多个事务并发执行时可能导致什么问题?
 2.1)脏读(读取了别人未提交数据)
       
       A: start transaction 
       insert into book values(1,......)
       ....
       B: start transaction
       select * from book; 显示有1


       A: rollback;//此时B看到的1这条数据就称之为脏数据.


       出现此问题的原因:事务的隔离级别可能是
       read uncommited
       解决方案:将事务隔离级别设置为read commited;


 2.2)不可重复读(一个事务内部多次读取的数据结果不一致.)
       A: start transaction 
       select count from book where id=1001; 100
       B: start transaction 
       update book set count-1 where id=1001;
       .....
       A:select count from book where id=1001; 99
       
       假如事务的隔离级别为read commited 可能还会导致
       一个事务内部多次读取出现不一致的现象.此时可以将
       事务的隔离级别设置为Repeatable Read(这是mysql
       中默认的隔离级别.)
       
 2.3)幻影读(修改了本事务看不到的数据)
       首先事务的隔离级别为repeatable read
       B:事务开启(手动提交)
       select * from book;
       1  java 10
       2  android 20
       A:事务开启(手动提交)
       insert into book (3,......);
       insert into book (5,......);
       commit; ok
       B:事务查询
       select * from book;
       1  java 10
       2  android 20


       B:事务执行
       delete from book where id=3;//删除OK
       update book set count=21 where id=5; //ok
       
       出现的这种现象通常称之为幻读.解决幻读问题
       需要将事务的隔离级别设置为Serializable
       
2.4) 丢失更新
       现有一个购书案例:A&B同时购书
       A  事务:
       step01:查询 book(100)
       step02:购买 update book set count=100-1 where id=1001
       B  事务: book(100)
       step01:查询 book(100)
       step02:购买 update book set count=100-1 where id=1001


       这个现象可以理解为丢失更新,那如何解决这个问题?
       可以通过加锁的机制解决这个问题,那如何加锁?(排他锁,乐观锁)


      典型的排他锁(悲观):
      select * from book where id=1001 for update;
      典型的乐观锁:一般是在表中添加version字段(版本):


3. 数据库事务的隔离级别


   多个事务并发执行时通常会借助设置事务的隔离级别来避免
   脏读,不可重复读,幻影读等现象.mysql中支持的事务隔离级别
   有如下四中:
   1)Read Uncommitted
   2)Read Committed
   3)Repeatable Read
   4)Serializable


   mysql中如何查看和设置事务的隔离级别.


  1).查看当前会话隔离级别
  select @@tx_isolation;
  2).查看系统当前隔离级别
  select @@global.tx_isolation;
  3).设置当前会话隔离级别,例如
  set session transaction isolation level repeatable read;
  4.设置系统当前隔离级别,例如
  set global transaction isolation level repeatable read;
  5.命令行,开始事务时(设置事务手动提交方式)
  set autocommit=off 或者 start transaction




4.Spring 中事务控制?


Spirng中的事务控制有两种实现:
1)编程式事务(基本不用)
   Connection conn
   try{
   conn=DbUitl.getConnection();
   conn.setAutoCommit(false);
   dao.updateObject(...)
   dao.saveObject(...)
   conn.commit();
   }catch(Exception e){
    conn.rollback();
  }finally{
    conn.close();
  }
2)声明式事务(重点使用):
   将编程事务的那部分代码交给spring底层实现,然后通过
   AOP机制将事务控制代码植入到业务层.
   spring 中的声明式事务处理方式:两种方式
   a)基于xml
   b)基于注解(重点掌握):通过@Transactional


   实现步骤:
   1)配置文件中启用事务配置
   <!-- 配置spring的生命式事务管理 -->
   <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--设置注解驱动的事务管理  -->
    <tx:annotation-driven 
    transaction-manager="txManager"/>
   2)业务类中通过@Transactional注解定义事务


5.Spring 中事务的传播特性


何为传播特性?
当一个事务业务方法调用另外一个事务业务方法时
事务的执行方式,称之为传播特性.


常用传播特性:


@Transactional(propagation=Propagation.REQUIRED) 如果没有事务创建新事务, 如果当前有事务参与当前事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
必须是新事务, 如果有当前事务, 挂起当前事务并且开启新事务.

猜你喜欢

转载自blog.csdn.net/qq_41264674/article/details/80674762