编程式事务与声明式事务的区别

通俗点讲就是:

编程式事务就是自己写Try catch语句调用commit\rollback等函数来实现那段业务数据改变的事务性。 声明式事务:是通过框架和事务定义配置给自己的业务代码添加事务性,比如Spring里面的AOP。 前者需要自己写大量重复的事务控制代码,后者通过设置可以一次性给所有的业务方法添加上事务特性,@Transaction注解的方式。

使用方法(声明式)

 1.添加tx名字空间

xmlns:tx="http://www.springframework.org/schema/tx"

 2.配置xml开启事务控制

<!-- 开启事务控制的注解支持 -->  
<tx:annotation-driven transaction-manager="transactionManager"/>

3.MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可。

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource" />  
    <property name="configLocation">  
        <value>classpath:mybatis-config.xml</value>  
    </property>  
</bean> 
​
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource" ref="dataSource" />  
</bean> 

使用@Transactional注解

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该注解来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

事物的特性(ACID)

1、原子性:一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做,,不可能只执行其中的一部分操作。

2、一致性:事务必须是使数据库从一个一致性状态变到另一个一致性状态。

3、隔离性:一个事务的执行不能被其他事务干扰。

4、持久性:指一个事务一旦提交,它对数据库中数据进行持久化处理。

事物的隔离级别

img

Read uncommitted(读未提交) 如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务B读取到了事务A未提交的数据,解决了更新丢失,但还是可能会出现脏读

Read committed(读提交) 如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。解决了更新丢失和脏读问题

Repeatable read(可重复读取) 可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。(读取数据的事务)可以通过“共享读镜”和“排他写锁”实现。解决了更新丢失、脏读、不可重复读、但是还会出现幻读

Serializable(可序化) 提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读.解决了更新丢失、脏读、不可重复读、幻读(虚读)

事物的并发问题

脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么 A读取到的数据是脏数据

不可重复读:一个事务中两次(不同时间点)读取同一行数据,但是这两次读取到的数据不一致

幻读:事务A读取数据时,未把事务B新增的数据读取到,像产生了幻觉一样

丢失更新:事务A覆盖了事务B已提交更新的数据,导致事务B的更新数据好像丢失了一样

事务的传播特性

REQUIRED(required):默认的传播特性,业务方法需要在一个事务中运行,如果一个方法已经处在一个事务中那么就加入到这个事务中,否则就会创建一个事务。

NEVER(never): 指定的业务方法绝对不能在事务范围内运行,如果业务方法在某个事务中执行,就会抛异常,只有业务方法没有任何事务才正常执行

MANDATORY(mandatory):该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能自己发起自己的事务,如果业务方法不存在事务,容器就抛异常。

SUPPORTS(supports):如果业务方法中已经在某个事务中被调用,则方法就称为事务的一部分,如果外部业务方法没有开启事务,supports该方法也会在没有事务的环境中执行。

NOT_SUPPORTED(not_supported):如果该业务方法在一个事务中被调用,那么当前的事务会被挂起,执行该业务方法,方法执行完毕唤醒被挂起的事务,如果业务方法不在一个事务中执行,该方法也不会开事务。不管是否在有无事务的环境中执行都不开启事务。

REQUIRES_NEW(requires_new):不管是否存在事务,业务方法总会自己开启一个事务,如果在已有事务的环境中调用,已有事务会被挂起,新的事务会被创建,直到业务方法调用结束,已有事务才被唤醒

NESTED(nested):如果业务方法在一个事务中执行,就在这个事务中嵌套,如果没有事务按着required执行,开启单独的事务,这种事务有多个事务的保存点,内部事务的回滚对外部事务没有影响

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值