Mybatis深入:事务隔离级别和管理
Mybatis事务管理
我们前面已经讲解了如何让Mybatis与Spring更好地融合在一起,通过将对应的Bean类型注册到容器中,就能更加方便的去使用Mapper,那么现在,我们接着来看Spring的事务控制。
在开始之前,我们还是回顾一下事务机制。首先事务遵循一个ACID原则:
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
简单来说,事务就是要么完成,要么就啥都别做!并且不同的事务直接相互隔离,互不干扰。
那么我们接着来深入了解一下事务的隔离机制(在之前数据库入门阶段并没有提到)我们说了,事务之间是相互隔离互不干扰的,那么如果出现了下面的情况,会怎么样呢:
当两个事务同时在执行,并且同时在操作同一个数据,这样很容易出现并发相关的问题,比如一个事务先读取了某条数据,而另一个事务此时修改了此数据,当前一个事务紧接着再次读取时,会导致和前一次读取的数据不一致,这就是一种典型的数据虚读现象。
因此,为了解决这些问题,事务之间实际上是存在一些隔离级别的:
- ISOLATION_READ_UNCOMMITTED(读未提交):其他事务会读取当前事务尚未更改的提交(相当于读取的是这个事务暂时缓存的内容,并不是数据库中的内容)
- ISOLATION_READ_COMMITTED(读已提交):其他事务会读取当前事务已经提交的数据(也就是直接读取数据库中已经发生更改的内容)
- ISOLATION_REPEATABLE_READ(可重复读):其他事务会读取当前事务已经提交的数据并且其他事务执行过程中不允许再进行数据修改(注意这里仅仅是不允许修改数据)
- ISOLATION_SERIALIZABLE(串行化):它完全服从ACID原则,一个事务必须等待其他事务结束之后才能开始执行,相当于挨个执行,效率很低
我们依次来看看,不同的隔离级别会导致什么问题。首先是读未提交
级别,此级别属于最低级别,相当于各个事务共享一个缓存区域,任何事务的操作都在这里进行。那么它会导致以下问题:
也就是说,事务A最后得到的实际上是一个毫无意义的数据(事务B已经回滚了)我们称此数据为"脏数据",这种现象称为脏读
我们接着来看读已提交
级别,事务只能读取其他事务已经提交的内容,相当于直接从数据中读取数据,这样就可以避免脏读问题了,但是它还是存在以下问题:
这正是我们前面例子中提到的问题,虽然它避免了脏读问题,但是如果事件B修改并提交了数据,那么实际上事务A之前读取到的数据依然不是最新的数据,直接导致两次读取的数据不一致,这种现象称为虚读也可以称为不可重复读
因此,下一个隔离级别可重复读
就能够解决这样的问题(MySQL的默认隔离级别),它规定在其他事务执行时,不允许修改数据,这样,就可以有效地避免不可重复读的问题,但是这样就一定安全了吗?这里仅仅是禁止了事务执行过程中的UPDATE操作,但是它并没有禁止INSERT这类操作,因此,如果事务A执行过程中事务B插入了新的数据,那么A这时是毫不知情的,比如:
两个人同时报名一个活动,两个报名的事务同时在进行,但是他们一开始读取到的人数都是5,而这时,它们都会认为报名成功后人数应该变成6,而正常情况下应该是7,因此这个时候就发生了数据的幻读现象。
因此,要解决这种问题,只能使用最后一种隔离级别串行化
来实现了,每个事务不能同时进行,直接避免所有并发问题,简单粗暴,但是效率爆减,并不推荐。
最后总结三种情况:
- 脏读:读取到了被回滚的数据,它毫无意义。
- 虚读(不可重复读):由于其他事务更新数据,两次读取的数据不一致。
- 幻读:由于其他事务执行插入删除操作,而又无法感知到表中记录条数发生变化,当下次再读取时会莫名其妙多出或缺失数据,就像产生幻觉一样。
(对于虚读和幻读的区分:虚读是某个数据前后读取不一致,幻读是整个表的记录数量前后读取不一致)
最后这张图,请务必记在你的脑海,记在你的心中,记在你的全世界:
Mybatis对于数据库的事务管理,也有着相应的封装。一个事务无非就是创建、提交、回滚、关闭,因此这些操作被Mybatis抽象为一个接口:
public interface Transaction {Connection getConnection() throws SQLException;void commit() throws SQLException;void rollback() throws SQLException;void close() throws SQLException;Integer getTimeout() throws SQLException;
}
对于此接口的实现,MyBatis的事务管理分为两种形式:
- 使用JDBC的事务管理机制:即利用对应数据库的驱动生成的
Connection
对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等,对应的实现类为JdbcTransaction
- 使用MANAGED的事务管理机制:这种机制MyBatis自身不会去实现事务管理,而是让程序的容器(比如Spring)来实现对事务的管理,对应的实现类为
ManagedTransaction
而我们之前一直使用的其实就是JDBC的事务,相当于直接使用Connection
对象(之前JavaWeb阶段已经讲解过了)在进行事务操作,并没有额外的管理机制,对应的配置为:
<transactionManager type="JDBC"/>
那么我们来看看JdbcTransaction
是不是像我们上面所说的那样管理事务的,直接上源码:
public class JdbcTransaction implements Transaction {private static final Log log = LogFactory.getLog(JdbcTransaction.class);protected Connection connection;protected DataSource dataSource;protected TransactionIsolationLevel level;protected boolean autoCommit;public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {//数据源this.dataSource = ds;//事务隔离级别,上面已经提到过了this.level = desiredLevel;//是否自动提交this.autoCommit = desiredAutoCommit;}//也可以直接给个Connection对象public JdbcTransaction(Connection connection) {this.connection = connection;}public Connection getConnection() throws SQLException {//没有就通过数据源新开一个Connectionif (this.connection == null) {this.openConnection();}return this.connection;}public void commit() throws SQLException {//连接已经创建并且没开启自动提交才可以使用if (this.connection != null && !this.connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Committing JDBC Connection [" + this.connection + "]");}//实际上使用的是数据库驱动提供的Connection对象进行事务操作this.connection.commit();}}
相当于JdbcTransaction
只是为数据库驱动提供的Connection
对象套了层壳,所有的事务操作实际上是直接调用Connection
对象。
那么我们接着来看ManagedTransaction
的源码:
public class ManagedTransaction implements Transaction {...public void commit() throws SQLException {}public void rollback() throws SQLException {}...
}
我们发现,大体内容和JdbcTransaction
差不多,但是它并没有实现任何的事务操作。也就是说,它希望将实现交给其他的管理框架来完成,而Spring就为Mybatis提供了一个非常好的事务管理实现。
Mybatis深入:事务隔离级别和管理相关推荐
- spring事务隔离级别、传播行为以及spring+mybatis+atomikos实现分布式事务管理
1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...
- Spring事务管理--(一)数据库事务隔离级别与mysql引擎基础讲解
一.前言 本篇文章来自网络整理,很简单,但是很实用对于初级和中级工程师. 原创地址1:http://www.cnblogs.com/hollen/archive/2012/05/13/2498309. ...
- mybatis 源码系列(七) Java基础之数据库事务隔离级别
更多mybatis 源码系列文章可关注我的博客,点击前往 正确设置数据库的事务访问级别,有助于我们的应用程序达到预期的效果 在mybatis中,提供了事务隔离级别的枚举类:org.apache.iba ...
- spring事务隔离级别与数据库事务隔离级别的关系
一直没搞清楚spring事务与数据库事务与锁之间的关系. spring事务: spring事务本质上使用数据库事务,而数据库事务本质上使用数据库锁,所以spring事务本质上使用数据库锁,开启spri ...
- 什么是事务和事务隔离级别
目录 1. 什么是事务 2. 事务的作用 3. 事务隔离所导致的一些问题 4. 事务隔离级别 Isolation 5. 事务传播行为 Propagation 6. 事物隔离级别查看及修改 1. 什么是 ...
- 脏读、幻读和不可重复读 + 事务隔离级别
丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的: 1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进 ...
- Spring五个事务隔离级别和七个事务传播行为
Spring五个事务隔离级别和七个事务传播行为 1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数 ...
- 服务器无法执行该事务_分布式事务、MVCC、事务隔离级别
我们都知道,OceanBase 是一个分布式数据库,数据是打散到多台服务器上的,当一个分布式事务要执行的时候,可能需要跨越多台 OB Server,如果在执行过程中遇到各种各样的异常情况,OceanB ...
- spring 事务-使用@Transactional 注解(事务隔离级别)
先看下@Transactional可以配制那些参数及以其所代表的意义. isolation 枚举org.springframework.transaction.annotation.Isolation ...
最新文章
- iOS 9应用开发教程之使用代码添加按钮美化按钮
- 用了10年的微信表情,它居然偷偷把烟给戒了...
- AppCompat 22.1,Google暴走,MD全面兼容低版本
- Make Them Equal
- 在Windows下如何创建虚拟环境(默认情况下)
- java类验证和装载顺序_Java类的加载机制和双亲委派模型
- MYSQL统计行数时到底应该怎么COUNT
- 青、取之于蓝,而青于蓝。
- 基于C语言EOF与getchar()的使用详解
- 淘宝天猫店铺,竞争对手卖同款产品,价格比我低,标题一模一样,如何应对?
- 使用Filter,Listener 时无法注入Bean的解决方法
- Android_View,ViewGroup,Window之间的关系
- 自动化运维工具 ansible的安装 及远程操作命令
- 南京大学软件测试复习
- 如何破解WP7并安装xap文件
- linux典型压缩包操作 tar打包、压缩与解压
- 深度学习(一)优化算法之随机梯度下降法(SGD)详解
- 惠普打印机双击之后没有扫描_惠普打印机为什么扫描不了,显示这个,什么意思,怎么处理?急...
- 酒店订房系统 java_javaweb酒店客房预订系统
- 科技界、IT届的外号