什么是事务?

访问并可能更新数据库中各种数据项的一个程序执行单元

        事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。

     三种错误现象

脏读:读了别人修改但未提交的数据;

 

不可重复读:读数据期间别人修改了数据,导致前后读到数据不同(行);

 

幻读:读数据期间别人增删了数据,导致读到的数据行不同(表)。

 

mysql的底层支持(IndoDB事务模型)

开启事务:start transaction / begin / autocommit=0

锁释放:事务commit

  

快照读:不需要等待X锁释放,直接读快照(历史数据) 

当前读:加排他锁(X锁),其他事务只能等待,

 加共享锁(S锁),其他事务可以加S,但X锁只能等待;

 

查操作需要显示使用,增删改自动添加X锁。

 

四大隔离级别(分级处理策略)

隔离:事务解决并发问题的特征;

并发:多个事务(用户)同一时间,访问操作同一数据。

 

isolation_default(默认值)mysql:可重复读,oracle:读已提交;

Oracle没有 repeatable_read 这个值,但采用多版本比对(快照)方法实现可重复读。

 

高并发场景使用Read Committed,低并发场景使用Repeatable Read。

并发问题实战:乐观锁是应用锁,隔离属性是物理锁。

 

接口TransactionDefinition,定义了7种事务传播机制

传播:事务解决嵌套问题的特征;

存在问题:大事务嵌套很多小事务,导致大事务缺失原子性;

融合:取消小事务,以大事务为准。

 

1、propagation_required
默认设置,支持当前事务;如果不存在,创建一个新的。(增删改)

2、_supports
支持当前事务;如果不存在事务,则以非事务方式执行。(查,显示声明)

3、_requires_new
创建一个新事务,如果存在当前事务,则挂起(暂停)当前事务。(日志记录)

4、_mandatory
支持当前事务;如果当前事务不存在,抛出异常。

5、_not_supported
不支持当前事务,存在事务挂起当前事务,始终以非事务方式执行。

6、_never
不支持当前事务;如果当前事务存在,抛出异常。

7、_nested
当前事务存在,则在嵌套事务中执行,不存在,创建一个新的。

 

实战:

@Transactional //增删改(用默认值)
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true) //查操作需要指定只读

 

应用

编程式事务管理:使用底层源码可实现更细粒度的事务控制。

transactionTemplate.execute

 

声明式事务管理:基于Spring AOP实现,本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

业务方法上添加@Transactional注释,定义事务的传播机制为required(默认)

<bean id="userService" class="com.yusael.service.UserServiceImpl">
    <property name="userDAO" ref="userDAO"/>
</bean>

<!--DataSourceTransactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

@Transactional
public class UserServiceImpl implements UserService {
    private UserDAO userDAO;

<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

 

标签事务配置:如果开发中要为每一个方法都显示添加@Transactional会比较麻烦,所以用标签配置替代注释可以一劳永逸。

<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes>
      <tx:method name="modify*"/> //增删改用默认属性
      <tx:method name="get*" propagation="SUPPORTS" read-only="true"/> 
                                  //读操作不开启新事务,指定只读。
    </tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="pc" expression="execution(* com.mj.service.*.*(..))"/>
<aop:advisor pointcut-ref="pc" advice-ref="advice" /> //组装切面
</aop:config>

 

源码解析文章飞机票

原文地址:https://www.cnblogs.com/mo-jian-ming/p/13300872.html