mybatis事务和MySQL事务_Spring 与 Mybatis 的事务管理

问题:Spring 与 Myabatis 整合后,为什么 DAO 不提交事务,但是数据能够插入数据库中?

Mybatis 提供的连接池对象 —> 创建 Connection

Connection.setAutoCommit(false) 手工的控制了事务,操作完成后,需要手工提交。

Druid(C3P0、DBCP)作为连接池 —> 创建 Connection

Connection.setAutoCommit(true) 默认值为 true,保持自动控制事务,一条 sql 自动提交。

答案:因为 Spring 与 Mybatis 整合时,引入了外部连接池对象,保持自动的事务提交这个机制Connection.setAutoCommit(true),不需要手工进行事务的操作,也能进行事务的提交。

注意:实战中,还是会手工控制事务(多条SQL一起成功,一起失败),后续 Spring 通过 事务控制 解决这个问题

1. 事务回顾

事务的 4 大特点: A、C、I、D

Atomicity 原子性

Consistency 一致性

Isolation 隔离性

Durability 持久性

如何控制事务?(JDBC、Mybatis)

JDBC

Connection.setAutoCommit(false);

Connection.commit();

Connection.rollback();

Mybatis

Mybatis 自动开启事务

sqlSession.commit();,底层还是调用的 Connection

sqlSession.rollback();,底层还是调用的 Connection

2. Spring 中控制事务的开发

3. Spring 中的事务属性(Transaction Attribute)

什么是事务属性?

描述物体特征的一系列值(性别、身高、体重)

事务属性:描述事务特征的一系列值

如何添加事务属性?

@Transactional(isolation=, propagation=, readOnly=,timeout=,rollbackFor,noRollbackFor=,)

隔离属性(ISOLATION)

描述了事务解决并发问题的特征。

什么是并发?

多个事务(用户)在同一时间,访问操作了相同的数据。

同一时间:0.000 几秒左右

并发会产生那些问题?

脏读

不可重复读

幻影读

并发问题如何解决?

通过隔离属性解决,隔离属性中设置不同过的值,解决并发处理的过程中的问题。

事务并发产生的问题:

脏读

一个事务,读取了另一个事务中没有提交的数据,会在本事务中产生数据不一样的现象

解决方案:@Transaction(isolation = Isolation.READ_COMMITTED)

不可重复读

一个事务中,多次读取相同的数据,但是读取结果不一样,会在本事务中产生数据不一样的现象

注意:1.不是脏读 2.在一个事务中

解决方案:@Transaction(isolation = Isolation.REPEATABLE_READ)

本质:一把行锁(对数据库表的某一行加锁)

幻影读

一个事务中,多次对整表进行查询统计,但是结果不一样,会在本事务中产生数据不一致的问题

解决方案:@Transaction(isolation = Isolation.SERIALIZABLE)

本质:表锁(对数据库某个表加锁)

安全与效率对比:

并发安全:SERIALIZABLE > READ_ONLY > READ_COMMITTED

运行效率:READ_COMMITTED > READ_ONLY > SERIALIZABLE

默认的隔离属性:

Spring 默认会指定为 ISOLATION_DEFAULT,调用不同数据库所设置的默认隔离属性

MySQL:REPEATABLE_READ

Oracle:READ_COMMITTED

查看数据库的默认隔离属性:

MySQL:SELECT @@tx_isolation;

Oracle:较麻烦,建议百度。

隔离属性在实验中的建议:

推荐使用 Spring 默认指定的 ISOLATION_DEFAULT

未来的实战中,遇到并发访问的情况,很少见

如果真的遇到并发问题,解决方案:乐观锁

Hibernate(JPA):version

MyBatis:通过拦截器自定义开发

传播属性(PROPAGATION)

概念:描述了事务解决 嵌套问题 的特征。

事务的嵌套

指的是一个大的事务中,包含了若干个小的事务。

事务嵌套产生的问题

大事务中融入了很多小的事务,他们彼此影响,最终就导致外部大的事务丧失了事务的原子性。

传播属性的值及其用法:

传播属性的值

外部不存在事务

外部存在事务

用法

备注

REQUIRED(默认)

开启新的事务

融合到外部事务中

@Transactional(propagation = Propagation.REQUIRED)

增、删、改方法

SUPPORTS

不开启事务

融合到外部事务中

@Transactional(propagation = Propagation.SUPPORTS)

查询方法

REQUIRES_NEW

开启新的事务

挂起外部事务,创建新的事务

@Transactional(propagation = Propagation.REQUIRES_NEW)

日志记录方法中

NOT_SUPPORTED

不开启事务

挂起外部事务

@Transactional(propagation = Propagation.NOT_SUPPORTED)

极其不常用

NEVER

不开启事务

抛出异常

@Transactional(propagation = Propagation.NEVER)

极其不常用

MANDATORY

抛出异常

融合到外部事物中

@Transactional(propagation = Propagation.MANDATORY)

极其不常用

Spring 中传播属性的默认值是:REQUIRED

推荐传播属性的使用方式:

增删改 方法:使用默认值 REQUIRED

查询 方法:显示指定传播属性的值为 SUPPORTS

只读属性(readOnly)

针对于 只进行查询操作的业务方法,可以加入只读属性,提高运行效率。

默认值:false

@Transactional(readOnly = true)

超时属性(timeout)

指定了事务等待的最长时间。

为什么事务会进行等待?

当前事务访问数据时,有可能访问的数据被别的事务进行加锁的处理,那么此时本事务就必须进行等待。

等待时间:单位是 秒

如何使用:@Transactional(timeout = 2)

超时属性的默认值:-1

-1 表示超时属性由对应的数据库来指定(一般不会主动指定,-1 即可)

异常属性

Spring 事务处理过程中:

默认对于 RuntimeException 及其子类,采用 回滚 的策略。

默认对于 Exception 及其子类,采用 提交 的策略。

使用方法:

@Transactional(rollbackFor = java.lang.Exception.class, xxx, xxx)

@Transactional(noRollbackFor = java.lang.RuntimeException, xxx, xxx)

事务属性常见配置总结

隔离属性:默认值

传播属性:Required(默认值)增删改、Supports 查询操作

只读属性:readOnly=false 增删改,true 查询操作

超时属性:默认值 -1

异常属性:默认值

开发建议

增删改操作:@Transactional

查询操作:@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值