MyBatis事务
数据很重要
在介绍MyBatis事务之前,先普及下数据库事务相关知识
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。一个事务可以是一条SQL语句,一组SQL语句或整个程序。
它有四大特性:原子性、一致性、隔离性、持续性,简称ACID
1.原子性:事务是应用中最小的执行单位,就如原子是自然界最小颗粒,具有不可再分的特征一样。事务是应用中不可再分的最小逻辑执行体,一组事务,要么成功;要么撤回。
2.一致性:事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库中只包含事务成功提交的结果时,数据库处于一致性状态。一致性是通过原子性来保证的。有非法数据(外键约束之类),事务撤回。
3.隔离性:各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。也就是说:并发执行的事务之间不能看到对方的中间状态,并发执行的事务之间不能相互影响。事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
4.持续性:持续性也称为持久性,指事务一旦提交,对数据所做的任何改变,都要记录到永久存储器中,通常是保存进物理数据库。软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 选项 决定什么时候吧事务保存到日志里。
读取数据的三个概念:
1.脏读(Dirty Reads):所谓脏读就是对脏数据的读取,而脏数据所指的就是未提交的数据。一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的(可能提交也可能回滚),这时,第二个事务来读取这条没有提交的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被称为脏读。
2.不可重复读(Non-Repeatable Reads):一个事务先后读取同一条记录,但两次读取的数据不同,我们称之为不可重复读。也就是说,这个事务在两次读取之间该数据被其它事务所修改。
3.幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻读。
事务的隔离级别:
1、Read Uncommitted(未授权读取、读未提交):这是最低的隔离等级,允许其他事务看到没有提交的数据。这种等级会导致脏读。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。避免了更新丢失,却可能出现脏读。也就是说事务B读取到了事务A未提交的数据。SELECT语句以非锁定方式被执行,所以有可能读到脏数据,隔离级别最低。
2.Read Committed(授权读取、读提交):读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。该隔离级别避免了脏读,但是却可能出现不可重复读。事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
3.repeatable read(可重复读取):就是在开始读取数据(事务开启)时,不再允许修改操作,事务开启,不允许其他事务的UPDATE修改操作,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。避免了不可重复读取和脏读,但是有时可能出现幻读。这可以通过“共享读锁”和“排他写锁”实现。
4.串行化、序列化:提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。
原生JDBC给了事务定义的级别,在java.sql.Connection.java文件中:
具体实现:
普及了数据库和jdbc的事务级别后,然后再说MyBatis事务
MyBatis作为Java语言的数据库框架,对数据库的事务管理是其非常重要的一个方面。本文将从事务的分类、配置和实现分析MyBatis的事务管理的实现机制。部分组件图
MyBatis事务分类
事务接口定义在org.apache.ibatis.transaction.Transaction。核心方法:
它有两种实现方式:
1、使用JDBC的事务管理机制:利用java.sql.Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等
2、使用MANAGED的事务管理机制:这种机制MyBatis自身不会去实现事务管理,而是让程序的容器如(tomcat,JBOSS,Weblogic,spring)来实现对事务的管理,此文暂不考虑
可在mybatis配置文件中配置其中一种事务处理方式:
Mybatis事务创建
MyBatis事务的创建是交给TransactionFactory 事务工厂来创建的,如果我们将<transactionManager>的type 配置为"JDBC",那么,在MyBatis初始化解析<environment>节点时,会根据type="JDBC"创建一个JdbcTransactionFactory工厂,核心代码:
dom树解析就不说了,以前开发不经常来回解析xml吗,xml文档与java类之间的互转,数据交换的一种,可以把xml当成一种组装数据的方式,可以多层嵌套,现在流行后台java注解解析和前台json了。
如果type = "JDBC",则MyBatis会创建一个JdbcTransactionFactory.class 实例;如果type="MANAGED",则MyBatis会创建一个MangedTransactionFactory.class实例。
MyBatis对<transactionManager>节点的解析会生成 TransactionFactory实例;而对<dataSource>解析会生成datasouce实例。作为<environment>节点,会根据TransactionFactory和DataSource实例创建一个Environment对象,代码如下所示:
Environment表示着一个数据库的连接,生成后的Environment对象会被设置到Configuration实例中。
通过事务工厂TransactionFactory很容易获取到Transaction对象实例。我们以JdbcTransaction为例,看一下JdbcTransactionFactory是怎样生成JdbcTransaction的,代码如下:
JdbcTransactionFactory会创建JDBC类型的Transaction,即JdbcTransaction,ManagedTransactionFactory也会创建ManagedTransaction。下面分别深入JdbcTranaction 和ManagedTransaction,看它们到底是怎样实现事务管理的。
JdbcTransaction事务
JdbcTransaction使用JDBC的提交和回滚事务管理机制 ,它依赖与从dataSource中取得的连接connection 来管理transaction 的作用域,connection对象的获取被延迟到调用getConnection()方法。如果autocommit设置为on,开启状态的话,它会忽略commit和rollback。
直观地讲,就是JdbcTransaction是使用的java.sql.Connection 上的commit和rollback功能,JdbcTransaction只是相当于对java.sql.Connection事务处理进行了一次包装(wrapper),Transaction的事务管理都是通过java.sql.Connection实现的。JdbcTransaction的代码实现如下:
事务隔离级别(TransactionIsolationLevel )
mybatis定义了五种事务级别,在包org.apache.ibatis.session下,源代码如下:
和上面介绍的隔离级别对应
测试核心代码:
总结:事务,先搞懂数据库事务,然后看原生JDBC的事务表现,最后才是框架包装的事务。
参考网址:
0 . 这一次,带你搞清楚MySQL的事务隔离级别!http://blog.itpub.net/31559358/viewspace-2221931/
1. 十分钟搞懂MySQL四种事务隔离级别 https://juejin.im/post/5c9756296fb9a070ad504a05
2. JDBC 4.2 Specification规范 https://download.oracle.com/otn-pub/jcp/jdbc-4_2-mrel2-eval-spec/jdbc4.2-fr-spec.pdf?AuthParam=1588653978_d9c7458a368a7a1630e262c8325ca34b
也可在我的github上获取:https://github.com/dongguangming/java/blob/master/jdbc4.2-fr-spec.pdf
3. 事务基础和分布式事务
https://www.ibm.com/developerworks/cn/cloud/library/cl-manage-cloud-transactions_1/index.html
4. mybatis jdbc transaction.java https://mybatis.org/mybatis-3/zh/jacoco/org.apache.ibatis.transaction.jdbc/JdbcTransaction.java.html
5. The ABCs of JDBC, Part 5 - Transactions
https://dzone.com/articles/jdbc-faq-transactions
6. Java JDBC Transaction Management and Savepoint
https://www.journaldev.com/2483/java-jdbc-transaction-management-savepoint
7. JDBC transaction performance tips
https://www.javaperformancetuning.com/tips/jdbctransaction.shtml
参考书籍:
MyBatis技术内幕