返回顶部
首页 > 资讯 > 数据库 >Mybatis:颠覆你心中对事务的理解
  • 652
分享到

Mybatis:颠覆你心中对事务的理解

Mybatis:颠覆你心中对事务的理解 2015-06-07 09:06:18 652人浏览 才女
摘要

【推荐】2020年最新Java电子书集合.pdf(吐血整理) >>> 1、说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性、四大隔离级别、七大传播特性。四大还好说,问题是七大传播特性是哪儿来的?是spring在当前线程

Mybatis:颠覆你心中对事务的理解

【推荐】2020年最新Java电子书集合.pdf(吐血整理) >>>

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

2、一说到事务,人们可能又会想起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()含义为关闭一个数据库连接,这已经不再是事务方法了。

Mybaits中的事务接口Transaction

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

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

事务类层次结构图:

Mybatis:颠覆你心中对事务的理解

 

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

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

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

@Override
  public 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实例,那么代码也是没有问题的,双重支持。

事务工厂TransactionFactory

Mybatis:颠覆你心中对事务的理解

 

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

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

Transaction的用法

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

配一个简单的时序图。

Mybatis:颠覆你心中对事务的理解

 

代码样例:

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()等方法内部寻找有关事务的任何方法。

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

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()方法源码。

 @Override
  public 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含义为是否是脏数据。

 @Override
  public int insert(String statement, Object parameter) {
    return update(statement, parameter);
  }

  @Override
  public 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。

  @Override
  public 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。

 
您可能感兴趣的文档:

--结束END--

本文标题: Mybatis:颠覆你心中对事务的理解

本文链接: https://lsjlt.com/news/5068.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Mybatis:颠覆你心中对事务的理解
    【推荐】2020年最新Java电子书集合.pdf(吐血整理) >>> 1、说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性、四大隔离级别、七大传播特性。四大还好说,问题是七大传播特性是哪儿来的?是Spring在当前线程...
    99+
    2015-06-07
    Mybatis:颠覆你心中对事务的理解
  • 你理解MySQL中的事务吗
    本文主要给大家介绍MySQL中的事务,文章内容都是笔者用心摘选和编辑的,具有一定的针对性,对大家的参考意义还是比较大的,下面跟笔者一起了解下MySQL中的事务吧。一个示例:银行引用是事务的一个经典例子:假如...
    99+
    2024-04-02
  • Spring的事务管理你了解吗
    目录1、事务介绍2、事务的四个特性(ACID)3、Spring 事务管理的核心接口4、PlatformTransactionManager 事务管理器5、TransactionSta...
    99+
    2024-04-02
  • MyBatis中处理事务的方法是什么
    MyBatis中处理事务的方法有两种: 使用程序控制事务:通过获取MyBatis的SqlSession对象,调用其beginTra...
    99+
    2024-03-07
    MyBatis
  • 一文带你了解MySQL中的事务
    目录一.什么是事务二.事务操作演示小结三.事务的特性四.事务的隔离级别概述四种隔离级别脏读、不可重复读、幻读操作一.什么是事务 在mysql中的事务(Transaction)是由存储引擎实现的,在MySQL中,只有Inn...
    99+
    2023-02-17
    MySQL事务使用 MySQL事务
  • 怎么理解PostgreSQL事务管理中的子事务
    本篇内容主要讲解“怎么理解PostgreSQL事务管理中的子事务”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解PostgreSQL事务管理中的子事务”吧...
    99+
    2024-04-02
  • 一文带你读懂SpringBoot中的事务管理
    一文带你读懂SpringBoot中的事务管理?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Springboot内部提供的事务管理器是根据autoconfigur...
    99+
    2023-05-31
    springboot bo 事务管理
  • 带你彻底理解JavaScript中的原型对象
    目录一、什么是原型1.1 函数的原型对象1.2 使用构造函数创建对象二、与原型有关的几个属性和方法2.1 prototype属性2.2 constructor属性2.3 __prot...
    99+
    2024-04-02
  • PHP 异常处理常见问题解答:解决你心中的疑惑!
    问:什么是 PHP 异常? 答:PHP 异常是发生错误时抛出的对象。它提供有关错误的详细信息,例如错误类型、错误消息和错误发生的位置。 问:如何抛出 PHP 异常? 答:可以使用 throw 语句抛出 PHP 异常。例如: ...
    99+
    2024-02-24
    PHP 异常处理 错误处理 try...catch throw
  • 怎么理解oracle中的事务
    本篇内容主要讲解“怎么理解oracle中的事务”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解oracle中的事务”吧! 一组...
    99+
    2024-04-02
  • 如何理解MySQL中的事务
    今天就跟大家聊聊有关如何理解MySQL中的事务,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。事务又叫做TCL,全称是transaction cont...
    99+
    2024-04-02
  • 阿里架构师:带你快速理解微服务架构,理解微服务架构的核心
    什么是微服务首先微服务并没有一个官方的定义,想要直接描述微服务比较困难,我们可以通过对比传统WEB应用,来理解什么是微服务。传统的WEB应用核心分为业务逻辑、适配器以及API或通过UI访问的WEB界面。业务逻辑定义业务流程、业务规则以及领域...
    99+
    2023-06-04
  • 一文带你深入了解Go语言中的事务
    目录背景事务实践事务说明优化方案总结背景 近期看到一篇文章,真的感叹作者的洞察力,在开发时有可能就会犯这样的错误,所以一定要多学习,多实践。其问题就是你在提交事务时,如果中间有其他业...
    99+
    2023-05-16
    Go语言事务终止 Go语言事务 Go 事务
  • Redis缓存中的事务处理讲解
    这篇文章主要介绍“Redis缓存中的事务处理讲解”,在日常操作中,相信很多人在Redis缓存中的事务处理讲解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Redis缓存中的事...
    99+
    2024-04-02
  • 如何在面试中展示你对Go和Linux的理解?
    在当前的技术行业中,越来越多的公司开始使用Go语言和Linux系统进行开发和部署。因此,如果你想在这个领域找到一份工作,对于这两个技术的深入理解是非常重要的。在面试过程中,你需要展示你对Go和Linux的理解,让面试官相信你是一位合适的候选...
    99+
    2023-08-22
    linux 响应 面试
  • 你是否准备好在ASP面试中展现你对函数的深入理解?
    在ASP面试中,对函数的深入理解是非常重要的。在这篇文章中,我们将讨论一些关于ASP函数的基础知识,并提供一些示例代码来帮助你更好地理解。 一、什么是ASP函数? 在ASP中,函数是一段可重复使用的代码,它接收输入参数并返回值。它们通常用于...
    99+
    2023-07-29
    面试 函数 spring
  • 阿里云服务器控制中心如何管理和监控你的云服务器
    阿里云服务器控制中心是一款强大而便捷的云服务器管理工具,它可以帮助你轻松地管理和监控你的云服务器。本文将详细讲解如何使用阿里云服务器控制中心。 阿里云服务器控制中心是阿里云推出的一款云服务器管理工具,它可以帮助你轻松地管理和监控你的云服务器...
    99+
    2023-12-16
    服务器 阿里 控制中心
  • 面试中如何展现你对Go接口和函数的理解?
    在Go语言中,接口(interface)是一种类型,它定义了一组方法的签名。接口类型可以定义为一个变量的类型,因此它可以被用来声明变量、作为函数参数或返回值。在Go语言中,接口是非常重要的,因为它允许我们编写可复用的代码,同时还可以减少代...
    99+
    2023-06-16
    接口 函数 面试
  • Java大数据处理中的对象加载问题你了解吗?
    随着大数据时代的到来,数据处理变得越来越复杂,而Java作为一种广泛应用于企业级应用程序的语言,也必须应对大数据处理方面的挑战。在处理大数据时,Java程序需要加载大量的对象,因此对象加载的效率成为了一个关键问题。本文将介绍Java大数据...
    99+
    2023-08-16
    大数据 对象 load
  • 如何理解MySQL中的事务隔离级别
    这篇文章给大家介绍如何理解MySQL中的事务隔离级别,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。很多小伙伴对 MySQL 的隔离级别一直心存疑惑,其实这个问题一点都不难,关键看怎么讲...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作