详解 MyBatis 事务管理,彻底颠覆你对事务的理解!

article/2025/9/16 5:01:18

来源:https://my.oschina.net/zudajun/blog/666764

前言

说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性、四大隔离级别、七大传播特性。四大还好说,问题是七大传播特性是哪儿来的?是 Spring 在当前线程内,处理多个数据库操作方法事务时所做的一种事务应用策略。事务本身并不存在什么传播特性,不要混淆事务本身和 Spring 的事务应用策略。(当然,找工作面试时,还是可以巧妙的描述传播特性的)

一说到事务,人们可能又会想起 create、begin、commit、rollback、close、suspend。可实际上,只有 commit、rollback 是实际存在的,剩下的 create、begin、close、suspend 都是虚幻的,是业务层或数据库底层应用语意,而非 JDBC 事务的真实命令。

create(事务创建):不存在。

begin(事务开始):姑且认为存在于 DB 的命令行中,比如 Mysql 的 start transaction 命令,以及其他数据库中的 begin transaction 命令。JDBC 中不存在。

close(事务关闭):不存在。应用程序接口中的 close () 方法,是为了把 connection 放回数据库连接池中,供下一次使用,与事务毫无关系。

suspend(事务挂起):不存在。Spring 中事务挂起的含义是,需要新事务时,将现有的 connection1 保存起来(它还有尚未提交的事务),然后创建 connection2,connection2 提交、回滚、关闭完毕后,再把 connection1 取出来,完成提交、回滚、关闭等动作,保存 connection1 的动作称之为事务挂起。在 JDBC 中,是根本不存在事务挂起的说法的,也不存在这样的接口方法。

因此,记住事务的三个真实存在的方法,不要被各种事务状态名词所迷惑,它们分别是:conn.setAutoCommit()、conn.commit()、conn.rollback()

conn.close () 含义为关闭一个数据库连接,这已经不再是事务方法了。


推荐一个开源免费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

1. Mybaits 中的事务接口 Transaction

public interface Transaction {Connection getConnection() throws SQLException;void commit() throws SQLException;void rollback() throws SQLException;void close() throws SQLException;
}

有了文章开头的分析,当你再次看到 close () 方法时,千万别再认为是关闭一个事务了,而是关闭一个 conn 连接,或者是把 conn 连接放回连接池内。

事务类层次结构图:

JdbcTransaction:单独使用 Mybatis 时,默认的事务管理实现类,就和它的名字一样,它就是我们常说的 JDBC 事务的极简封装,和编程使用 mysql-connector-java-5.1.38-bin.jar 事务驱动没啥差别。其极简封装,仅是让 connection 支持连接池而已。

ManagedTransaction:含义为托管事务,空壳事务管理器,皮包公司。仅是提醒用户,在其它环境中应用时,把事务托管给其它框架,比如托管给 Spring,让 Spring 去管理事务。

org.apache.ibatis.transaction.jdbc.JdbcTransaction.java 部分源码。

@Overridepublic void close() throws SQLException {if (connection != null) {resetAutoCommit();if (log.isDebugEnabled()) {log.debug("Closing JDBC Connection [" + connection + "]");}connection.close();}}

面对上面这段代码,我们不禁好奇,connection.close () 之前,居然调用了一个 resetAutoCommit (),含义为重置 autoCommit 属性值。connection.close () 含义为销毁 conn,既然要销毁 conn,为何还多此一举的调用一个 resetAutoCommit () 呢?消失之前多喝口水,真的没有必要。

其实,原因是这样的,connection.close () 不意味着真的要销毁 conn,而是要把 conn 放回连接池,供下一次使用,既然还要使用,自然就需要重置 AutoCommit 属性了。通过生成 connection 代理类,来实现重回连接池的功能。如果 connection 是普通的 Connection 实例,那么代码也是没有问题的,双重支持。

2. 事务工厂 TransactionFactory

顾名思义,一个生产 JdbcTransaction 实例,一个生产 ManagedTransaction 实例。两个毫无实际意义的工厂类,除了 new 之外,没有其他代码。

<transactionManager type="JDBC" />

mybatis-config.xml 配置文件内,可配置事务管理类型。

3. Transaction 的用法

无论是 SqlSession,还是 Executor,它们的事务方法,最终都指向了 Transaction 的事务方法,即都是由 Transaction 来完成事务提交、回滚的。

配一个简单的时序图。

代码样例:

public static void main(String[] args) {SqlSession sqlSession = MybatisSqlSessionFactory.openSession();try {StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);Student student = new Student();student.setName("yy");student.setEmail("email@email.com");student.setDob(new Date());student.setPhone(new PhoneNumber("123-2568-8947"));studentMapper.insertStudent(student);sqlSession.commit();} catch (Exception e) {sqlSession.rollback();} finally {sqlSession.close();}
}

注:Executor 在执行 insertStudent (student) 方法时,与事务的提交、回滚、关闭毫无瓜葛(方法内部不会提交、回滚事务),需要像上面的代码一样,手动显示调用 commit ()、rollback ()、close () 等方法。

因此,后续在分析到类似 insert ()、update () 等方法内部时,需要忘记事务的存在,不要试图在 insert () 等方法内部寻找有关事务的任何方法。

4. 你可能关心的有关事务的几种特殊场景表现(重要)

1. 一个 conn 生命周期内,可以存在无数多个事务。

// 执行了connection.setAutoCommit(false),并返回
SqlSession sqlSession = MybatisSqlSessionFactory.openSession();
try {StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);Student student = new Student();student.setName("yy");student.setEmail("email@email.com");student.setDob(new Date());student.setPhone(new PhoneNumber("123-2568-8947"));studentMapper.insertStudent(student);// 提交sqlSession.commit();studentMapper.insertStudent(student);// 多次提交sqlSession.commit();
} catch (Exception e) {// 回滚,只能回滚当前未提交的事务sqlSession.rollback();
} finally {sqlSession.close();
}

对于 JDBC 来说,autoCommit=false 时,是自动开启事务的,执行 commit () 后,该事务结束。以上代码正常情况下,开启了 2 个事务,向数据库插入了 2 条数据。JDBC 中不存在 Hibernate 中的 session 的概念,在 JDBC 中,insert 了几次,数据库就会有几条记录,切勿混淆。而 rollback (),只能回滚当前未提交的事务。

2. autoCommit=false,没有执行 commit (),仅执行 close (),会发生什么?

try {studentMapper.insertStudent(student);
} finally {sqlSession.close();
}

就像上面这样的代码,没有 commit (),固执的程序员总是好奇这样的特例。

insert 后,close 之前,如果数据库的事务隔离级别是 read uncommitted,那么,我们可以在数据库中查询到该条记录。

接着执行 sqlSession.close () 时,经过 SqlSession 的判断,决定执行 rollback () 操作,于是,事务回滚,数据库记录消失。

下面,我们看看 org.apache.ibatis.session.defaults.DefaultSqlSession.java 中的 close () 方法源码。

  @Overridepublic void close() {try {executor.close(isCommitOrRollbackRequired(false));dirty = false;} finally {ErrorContext.instance().reset();}}

事务是否回滚,依靠 isCommitOrRollbackRequired (false) 方法来判断。

  private boolean isCommitOrRollbackRequired(boolean force) {return (!autoCommit && dirty) || force;}

在上面的条件判断中,!autoCommit=true(取反当然是 true 了),force=false,最终是否回滚事务,只有 dirty 参数了,dirty 含义为是否是脏数据。

  @Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);}@Overridepublic int update(String statement, Object parameter) {try {dirty = true;MappedStatement ms = configuration.getMappedStatement(statement);return executor.update(ms, wrapCollection(parameter));} catch (Exception e) {throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

源码很明确,只要执行 update 操作,就设置 dirty=true。insert、delete 最终也是执行 update 操作。

只有在执行完 commit ()、rollback ()、close () 等方法后,才会再次设置 dirty=false。

  @Overridepublic void commit(boolean force) {try {executor.commit(isCommitOrRollbackRequired(force));dirty = false;} catch (Exception e) {throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

因此,得出结论:autoCommit=false,但是没有手动 commit,在 sqlSession.close () 时,Mybatis 会将事务进行 rollback () 操作,然后才执行 conn.close () 关闭连接,当然数据最终也就没能持久化到数据库中了。

3. autoCommit=false,没有 commit,也没有 close,会发生什么?

studentMapper.insertStudent(student);

干脆,就这一句话,即不 commit,也不 close。

结论:insert 后,jvm 结束前,如果事务隔离级别是 read uncommitted,我们可以查到该条记录。jvm 结束后,事务被 rollback (),记录消失。通过断点 debug 方式,你可以看到效果。

这说明 JDBC 驱动实现,已经 Kao 虑到这样的特例情况,底层已经有相应的处理机制了。这也超出了我们的探究范围。

但是,一万个屌丝程序员会对你说:Don't do it like this. Go right way。

警告:请按正确的 try-catch-finally 编程方式处理事务,若不从,本人概不负责后果。

注:无参的 openSession () 方法,会自动设置 autoCommit=false。

总结:Mybatis 的 JdbcTransaction,和纯粹的 Jdbc 事务,几乎没有差别,它仅是扩展支持了连接池的 connection。另外,需要明确,无论你是否手动处理了事务,只要是对数据库进行任何 update 操作(update、delete、insert),都一定是在事务中进行的,这是数据库的设计规范之一。读完本篇文章,是否颠覆了你心中目前对事务的理解呢?欢迎点评。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!


http://chatgpt.dhexx.cn/article/tBFCQTvT.shtml

相关文章

MyBatis的事务

Mybatis管理事务是分为两种方式: (1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交 (2)使用MANAGED的事务管理机制&#xff0c;这种机制mybatis自身不会去实现事务管理&#xff0c;而是让程序的容器&#xff08;JBOSS,WebLogic&#xff09;来实现对…

MyBatis--事务

事务是基于关系型数据库的企业应用的重要组成部分&#xff0c;用来确保应用程序数据的完整性和一致性。 事务就是一个系列(一组、几个)操作的集合单元&#xff0c;这些操作要么全部完成&#xff0c;要么全部失败&#xff0c;如果某一个操作失败&#xff0c;就算是已经成功执行…

ResNet网络结构解析

ResNet是识别、检测中常用的backbone&#xff0c;看检测相关论文的时候重点都在方法创新上&#xff0c;并没有特别在意网络结构&#xff0c;但是到自己跑实验改网络的时候就涉及到结构细节问题&#xff0c;于是详细的看了下ResNet网络结构。下图是ResNet的网络结构简图&#xf…

resnet网络结构图

很重要&#xff0c;单独放

ResNet网络结构,BN以及迁移学习详解

网络中的亮点&#xff1a; 1.超深的网络结构&#xff08;超过1000层&#xff09; 2.提出residual(残差)模块 3.使用Batch Normalization加速训练&#xff08;丢弃dropout&#xff09; 左边是将卷积层和池化层进行一个简单的堆叠所搭建的网络结构 20层的训练错误率大概在1%…

ResNet网络结构详解(Tensorflow2.6.0实现网络结构)

文章目录 1.ResNetX网络结构表&#xff08;1&#xff09;论文地址&#xff1a;&#xff08;2&#xff09;ResNet18网络结构&#xff1a;&#xff08;3&#xff09;ResNet34网络结构&#xff1a; 2.卷积神经网络的发展(1).卷积神经网络的发展&#xff1a;&#xff08;2&#xff…

ResNet网络结构详解,网络搭建,迁移学习

前言&#xff1a; 参考内容来自up&#xff1a;6.1 ResNet网络结构&#xff0c;BN以及迁移学习详解_哔哩哔哩_bilibili up的代码和ppt&#xff1a;https://github.com/WZMIAOMIAO/deep-learning-for-image-processing 一、简介 ResNet 网络是在 2015年 由微软实验室提出&#xf…

ResNet网络结构详解与模型的搭建

ResNET(Deep Residual Learning for Image Recognition ) ResNet网络是在2015年由微软实验室提出&#xff0c;斩获当年ImageNet竞赛中分类任务第一名&#xff0c;目标检测第一名。获得COCO数据集中目标检测第一名&#xff0c;图像分割第一名。下图是ResNet34层模型的结构简图。…

Resnet网络结构图和对应参数表的简单理解

Resnet Resnet即就是残差网络&#xff0c;本文主要是对于resnet给出的网络结构图进行简单解释。 网络结构图 以上就是34层网络的网络结构图。 以上是18层、34层、50层、101层以及152层网络所对应的残差块。 我刚开始在网上看到这两张图片的时候&#xff0c;感觉一点都不懂&a…

pytorch Resnet 网络结构

最近在学习廖老师的pytorch教程&#xff0c;学到Resnet 这部分着实的烧脑&#xff0c;这个模型都捣鼓了好长时间才弄懂&#xff0c;附上我学习过程中最为不解的网络的具体结构连接&#xff08;网上一直没有找到对应网络结构&#xff0c;对与一个自学的学渣般的我&#xff0c;很…

ResNet网络结构解析--Pytorch

ResNet101–DSSD/SSD &#xff08;1&#xff09;ResNet在Pytorch官方代码中有5种不同深度的结构&#xff0c;分别为18、34、50、101、152&#xff08;各网络深度指的是“需要通过训练更新参数“的层数&#xff0c;如卷积层&#xff0c;全连接层等&#xff09;&#xff0c;和论…

ResNet网络结构详解及代码复现

1. ResNet论文详解 1.1. Introduction 一般网络越深&#xff0c;特征就越丰富&#xff0c;模型效果也就越好。在深度重要的驱动下&#xff0c;出现了2个问题&#xff1a; 梯度消失和梯度爆炸&#xff1a; 梯度消失&#xff1a;误差梯度<1&#xff0c;当网络层数增多时&…

resnet50网络结构_pytorch实践(改造属于自己的resnet网络结构并训练二分类网络)

我的CSDN博客:https://blog.csdn.net/litt1e 我的公众号:工科宅生活 在学习pytorch过程中,突然想拥有属于自己的网络结构,于是便自己选择了一个比较简单的resnet18进行改造,并用其对蚂蚁和蜜蜂进行分类,比较一下没有经过预训练的resnet18好还是自己改造的resnet_diy好。 …

【DL系列】ResNet网络结构详解、完整代码实现

Name&#xff1a; Deep Residual Learning for Image Recognition Author&#xff1a; 何恺明团队 Publiced&#xff1a; 2015.12_CVPR 文章目录 前言1. 残差网络待解决的问题2. ResNet模型亮点 ResNet模型结构1. 残差学习2. Residual模块3. ResNet模型 ResNet-layers模型完整代…

pytorch实现resnet网络结构

ResNet结构和pytorch实现 resnet的网络结构都是经过5个不同数量的残差块最后一个全连接分类完成的。 在resnet50以后&#xff0c;由于层数的增加残差块发生了变化&#xff0c;从原来3x3卷积变为三层卷积&#xff0c;卷积核分别为1x1、3x3、1x1&#xff0c;减少了网络参数。主…

ResNet网络结构搭建

ResNet 下图为包含有18层(17个卷积层和1个全连接层)、34层(33个卷积层和1个全连接层)、50层(49个卷积层和1个全连接层)、101层(100个卷积层和1个全连接层)、152层(151个卷积层和1个全连接层)的resnet结构 下图是论文中给出的两种残差结构。左边的残差结构是针对层数较少网络&a…

ResNet网络结构

注&#xff1a;深度好像就是channel w*h*c 根据b站up霹雳吧啦的讲解做的笔记 视频地址6.1 ResNet网络结构&#xff0c;BN以及迁移学习详解_哔哩哔哩_bilibiliR 6.2 使用pytorch搭建ResNet并基于迁移学习训练_哔哩哔哩_bilibili ResNet网络解决梯度消失、爆炸&#xff0c;以及…

经典网络ResNet介绍

经典网络ResNet(Residual Networks)由Kaiming He等人于2015年提出&#xff0c;论文名为《Deep Residual Learning for Image Recognition》&#xff0c;论文见&#xff1a;https://arxiv.org/pdf/1512.03385.pdf ResNet要解决的是深度神经网络的”退化(degradation)”问题&…

六、ResNet网络详细解析(超详细哦)

1、 RestNet网络 1.1、 RestNet网络结构 ResNet在2015年被提出&#xff0c;在ImageNet比赛classification任务上获得第一名&#xff0c;因为它“简单与实用”并存&#xff0c;之后很多方法都建立在ResNet50或者ResNet101的基础上完成的&#xff0c;检测&#xff0c;分割&…

ResNet结构

文章目录 系列文章目录一、Residual net(残差网络)二、BatchNormalization(BN)三、ResNet结构 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开…