mybatis和spring jdbc持久层框架事务支持分析

​ 持久层框架中的事务支持指的是持久层框架如何支持数据库事务,我们先梳理出原生数据库事务操作的主线脉络,它是通过java.sql 包下的Connection接口中定义的几个关键方法来实现的,包括setAutoCommit、commit、rollback几个核心的方法;先通过设置setAutoCommit false来关闭自动提交,然后通过显式的调用commit方法来提交事务;同样Connection接口中也定义了设置事务隔离级别的方法。

​ 底层实现事务方式的接口方法我们梳理清楚之后,我们要去探究持久层框架究竟是如何实现数据库事务的,就很清晰了,我们只要找到持久层框架在哪里调用了connection 接口的setAutoCommit、commit、rollback 方法就知道了,然后我们沿着这个思路去分析下mybatis是怎么实现事务的,spring jdbc是怎么实现事务的,这就是我们分析的一个方法论。

一、mybatis 事务支持源码剖析

1、实例

我们先写个实例看下,mybatis事务怎么去操作

private static void simpleExecutorTest() {long start = System.currentTimeMillis();// 然后根据 sqlSessionFactory 得到 session,关闭自动提交SqlSession session = sqlSessionFactory.openSession(ExecutorType.SIMPLE,false);// 获取学生Student student3 = session.selectOne("getStudent", 3);System.out.println(student3);// 获取学生Student student4 = session.selectOne("getStudent", 4);System.out.println(student4);// 获取学生Student student5 = session.selectOne("getStudent", 5);System.out.println(student5);// 修改学生student3.setName("修改的学生3");session.update("updateStudent", student3);// 修改学生student4.setName("修改的学生4");session.update("updateStudent", student4);// 修改学生student5.setName("修改的学生5");session.update("updateStudent", student5);// 手动提交session.commit();long end = System.currentTimeMillis();System.out.println("SimpleExecutor 更新的执行时间为:" + (end - start));}

首先通过sqlSessionFactory 来开启会话openSession的时候我们需要将自动提交设置为false,然后最后通过session.commit()方法来提交事务,不执行commit的话实际数据库更新操作是没有提交的。

2、源码剖析

openSession这个方法怎么关闭自动提交的,我们一层一层点进去看下,看下false这个参数传给了谁,最终我们会发现它传给了JdbcTransaction,JdbcTransaction是用来获取连接的,我们接着看下它获取连接的方法

protected void openConnection() throws SQLException {if (log.isDebugEnabled()) {log.debug("Opening JDBC Connection");}connection = dataSource.getConnection();if (level != null) {connection.setTransactionIsolation(level.getLevel());}// 设置自动提交setDesiredAutoCommit(autoCommmit);}protected void setDesiredAutoCommit(boolean desiredAutoCommit) {try {if (connection.getAutoCommit() != desiredAutoCommit) {if (log.isDebugEnabled()) {log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");}// 设置自动提交connection.setAutoCommit(desiredAutoCommit);}} catch (SQLException e) {// Only a very poorly implemented driver would fail here,// and there's not much we can do about that.throw new TransactionException("Error configuring AutoCommit.  "+ "Your driver may not support getAutoCommit() or setAutoCommit(). "+ "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);}}

最终我们发现就是这个地方调用了connection的setAutoCommit方法;同样commit方法也可以通过这种方式去分析。

二、spring jdbc 事务支持源码剖析

1、实例

同样先来看一个使用示例,

配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!--直接配置数据库连接--><bean id="testDbDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="root"/></bean><!-- DAL客户端接口实现 --><bean id="sqlSession"class="com.handserome.daat.session.DefaultSqlSession"><property name="sqlMapConfigLocation" value="classpath*:conf/sqlMap/sqlMap_*.xml"/><property name="dataSource" ref="testDbDs"/></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"><constructor-arg type="javax.sql.DataSource" ref="testDbDs"/></bean><bean id="studentDao" class="com.handserome.test.dao.StudentDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate"/></bean><context:annotation-config /><context:component-scan base-package="com.handserome.test.dao" /><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="testDbDs"/></bean><tx:annotation-driven transaction-manager="transactionManager"/></beans>

dao层实现类

public class StudentDaoImpl implements StudentDao {private NamedParameterJdbcTemplate jdbcTemplate;@Transactional@Overridepublic void insertTransactionTest() {insert();insert1();}public void insert() {String sql = "insert into student(student_id, name, create_time) values (:studentId, :name, :createTime)";Map<String, Object> paramMap = new HashMap<String, Object>();paramMap.put("studentId", "454");paramMap.put("name", "bbbb");paramMap.put("createTime", new Timestamp(System.currentTimeMillis()));// 返回的是更新的行数int count = jdbcTemplate.update(sql, paramMap);System.out.println(count);}public void insert1() {String sql = "insert into student(student_id, name, create_time) values (:studentId, :name, :createTime)";Map<String, Object> paramMap = new HashMap<String, Object>();paramMap.put("studentId", "454");paramMap.put("name", "bbbb");paramMap.put("createTime", new Timestamp(System.currentTimeMillis()));// 返回的是更新的行数int count = jdbcTemplate.update(sql, paramMap);System.out.println(count);}public NamedParameterJdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(NamedParameterJdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}
}

在spring事务使用的时候,只要加个@Transactional注解就实现了事务的处理,跟mybatis不一样我们没有看到它在哪设置了自动提交false,在哪调用了commit方法,应此我们只需要找到在哪调用的这两个方法就能梳理清楚它的脉络。

2、源码剖析

首先在配置文件中,可以看到配了几个东西,1、是配置了事务管理器DataSourceTransactionManager 2、是开启了包路径扫描 3、是开启了注解使用;

配的事务管理器DataSourceTransactionManager 肯定是用来管理事务的,那么稍微思考下就知道它肯定包含一些事务的操作方法,像开启事务,提交事务,回滚事务,具体我们分析一个就可以了。

protected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {if (txObject.getConnectionHolder() == null ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {Connection newCon = this.dataSource.getConnection();if (logger.isDebugEnabled()) {logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");}txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}txObject.getConnectionHolder().setSynchronizedWithTransaction(true);con = txObject.getConnectionHolder().getConnection();Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,// so we don't want to do it unnecessarily (for example if we've explicitly// configured the connection pool to set it already).if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug("Switching JDBC Connection [" + con + "] to manual commit");}// 关闭自动提交con.setAutoCommit(false);}txObject.getConnectionHolder().setTransactionActive(true);int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// Bind the session holder to the thread.if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());}}catch (Exception ex) {DataSourceUtils.releaseConnection(con, this.dataSource);throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}

​ 我们可以看到,它从transaction对象里面先拿到了connectionHolder, 然后通过connectionHolder拿到connection,然后再调用的connection的setAutoCommit方法;看到这是不是感觉和mybatis很像了,都是从transaction中获取到连接,然后调用connection的setAutoCommit 方法。

​ 分析到这还不够,我们要进一步思考,什么时候会调用DataSourceTransactionManager 的doBegin方法呢,实例里面调用insertTransactionTest方法和它又存在什么关联呢?我们只需要在doBegin方法里打个断点,看下调用链栈,方法反向追踪下就清楚了。

​ 从线程栈里我们可以看到上层是JdkDynamicAopProxy inoke 方法调用的,是jdk动态代理实现的,StudentDaoImpl这个对象被包装了,它的insertTransactionTest方法实际是通过JdkDynamicAopProxy 动态代理去完成了,动态代理增强了insertTransactionTest方法,在它执行前最终调用了DataSourceTransactionManager 的doBegin方法。关于动态代理对象又是如何构建的可以去看spring 容器的创建和初始化加载过程,这里就不讲了,这和配置里面开启包路径扫描和注解使用时相关的。

mybatis和spring jdbc持久层框架事务支持分析相关推荐

  1. 【java学习】MyBatis使用——Java 数据持久层框架

    1,概念 MyBatis是一个数据持久层(ORM)框架,封装了jdbc.把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现.MyBATIS需要开发人员自己来写sql语句,这可以增加了程 ...

  2. 肝!Spring JDBC持久化层框架“全家桶”教程!

    目录 写在前面 一.什么是JdbcTemplate? 二.JdbcTemplate框架搭建 1.导入所需jar包 2.配置JDBC数据源 (1).直接在中配置数据源 (2).引入外部配置文件 3.配置 ...

  3. Spring 从入门到精通 (二十) 持久层框架 MyBatis

    关键词:Spring | 整合 | 持久层 | MyBatis 本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨ 目录 一.MyBat ...

  4. SSM持久层框架MyBatis,看这一篇就够了

    前言: 此篇仅为个人初期学习笔记,如有错误,请xd们指正 你这么好看,还.... MyBatis 前言 一.MyBatis简介 二.搭建MyBatis项目 1. 开发环境 2. 创建maven工程 3 ...

  5. Java软件开发:自定义MyBatis持久层框架

    自定义MyBatis持久层框架 1 框架概述 1.1 什么是框架 1.2 框架要解决的问题 1.3 软件开发的分层的重要性 2 MyBatis框架 3 JDBC编程 3.1 JDBC程序的回顾 3.2 ...

  6. 优秀的持久层框架-Mybatis(上)

    文章目录 前言 一.MyBatis概述 1.1传统JDBC编程 1.2 mybatis的历史 1.3 mybatis是什么? 1.4如何使用? 1.5Mybatis架构 二. MyBatis环境搭建 ...

  7. Java数据库持久层框架基础:jdbc原理和使用综述

    Java数据库持久层框架基础:jdbc原理和使用综述 前言 jdbc基础架构 jbdc的使用 jdbc的主要接口 驱动 连接 连接池 会话Statement 结果集ResultSet 前言 目前jav ...

  8. 【狂神说:秦疆】Mybatis持久层框架笔记

    目录 Mybatis 1.简介 1.1.什么是Mybatis 1.2.如何获取Mybatis 1.3.持久化 1.4.持久层 1.5.为什么使用Mybatis 2.第一个Mybatis程序 2.1.搭 ...

  9. Mybatis持久层框架MBGExample类详解

    Mybatis 1. 概念 1.1 什么是Mybatis 是一个持久层框架: 所谓持久层,也就是数据访问层.又称为DAL层,有时候也称为是持久层,其功能主要是负责数据库的访问. 我的理解就是Mybai ...

最新文章

  1. 【数据结构】队列-顺序队列、循环队列、链队、双端队列
  2. docker之docker-machine用法
  3. git远程仓库的使用
  4. 获取当前时间的天、周、月、季度、半年度、年度开始和结束时间
  5. 【毕业答辩】毕业论文答辩温馨提示
  6. python 除法 保留2位小数
  7. linux后台运行程序(secureCRT断掉或关闭后继续运行程序)
  8. 如何查询OS、CPU、内存、硬盘信息
  9. php tcpdf image,php采用tcpdf生成pdf支持中文,图片
  10. 2020 iOS拼多多(多多进宝)APP端接入,打开拼多多商品详情与授权
  11. 51单片机c语言的延时程序,51单片机延时程序
  12. 开源首发!Android入门“神器“——《Android编程入门教程》,理论与实战齐飞!
  13. 免费赠品发布:Wintry Blue Wallpaper
  14. OpenCV-python 自制图片画框脚本
  15. 倪光南院士:网络安全和信息化要同步推进
  16. canvas教程18-刮刮乐
  17. 手把手QQ机器人制作教程,根据官方接口进行开发,基于Python语言制作的详细教程(更新中)
  18. Android新浪微博实训报告,新浪微博产品简析
  19. html如何提取图片颜色代码,PS怎么提取颜色做色卡?
  20. 设计模式 外观模式 一键电影模式

热门文章

  1. 【Spark Summit EU 2016】使用参数服务器在Spark上扩展因式分解机
  2. XRDP与VNC的关系
  3. 在Paint事件中绘制控件(边框)
  4. 各种厂商打开bios按键总汇
  5. Flume+Kafka+Spark Streaming+MySQL实时日志分析
  6. 大数据分析的价值体现
  7. 如何商业智能平台BI的成本
  8. 物联网卡对企业设备的重要性
  9. java重新连接tcp,如何处理TCP客户端丢弃和重新连接
  10. python百度贴吧怎么爬取最早的帖子_Python爬虫爬取百度贴吧的帖子