一、Mybatis事务

1、事务管理方式

Mybatis中的事务管理方式有两种:

1、JDBC的事务管理机制,即使用JDBC事务管理机制进行事务管理

2、MANAGED的事务管理机制,Mybatis没有实现对事务的管理,而是通过容器来实现对事务的管理

其中,Mybatis提供了事务的接口:Transaction,其代码如下:

public interface Transaction {

  /**
* Retrieve inner database connection
* @return DataBase connection
* @throws SQLException
*/
//获得数据库连接
Connection getConnection() throws SQLException; /**
* Commit inner database connection.
* @throws SQLException
*/
//提交
void commit() throws SQLException; /**
* Rollback inner database connection.
* @throws SQLException
*/
//回滚
void rollback() throws SQLException; /**
* Close inner database connection.
* @throws SQLException
*/
//连接关闭
void close() throws SQLException; /**
* Get transaction timeout if set
* @throws SQLException
*/
//获取事务timeout
Integer getTimeout() throws SQLException; }

Transaction有两个实现类:JdbcTransaction和ManagedTransaction,分别对应两种事务管理方式。

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 autoCommmit; public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
} public JdbcTransaction(Connection connection) {
this.connection = connection;
} @Override
public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
return connection;
} @Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
} @Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
} @Override
public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
} 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);
}
} protected void resetAutoCommit() {
try {
if (!connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
}
connection.setAutoCommit(true);
}
} catch (SQLException e) {
if (log.isDebugEnabled()) {
log.debug("Error resetting autocommit to true "
+ "before closing the connection. Cause: " + e);
}
}
} 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);
} @Override
public Integer getTimeout() throws SQLException {
return null;
}
}

JdbcTransaction通过使用jdbc提供的方式来管理事务,通过Connection提供的事务管理方法来进行事务管理,只是将JDBC的事务管理进行了封装。

ManagedTransaction实现类是通过容器来进行事务管理,所有它对事务提交和回滚并不会做任何操作。其代码如下:

public class ManagedTransaction implements Transaction {

  private static final Log log = LogFactory.getLog(ManagedTransaction.class);

  private DataSource dataSource;
private TransactionIsolationLevel level;
private Connection connection;
private final boolean closeConnection; public ManagedTransaction(Connection connection, boolean closeConnection) {
this.connection = connection;
this.closeConnection = closeConnection;
} public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {
this.dataSource = ds;
this.level = level;
this.closeConnection = closeConnection;
} @Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
} @Override
public void commit() throws SQLException {
// Does nothing
} @Override
public void rollback() throws SQLException {
// Does nothing
} @Override
public void close() throws SQLException {
if (this.closeConnection && this.connection != null) {
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + this.connection + "]");
}
this.connection.close();
}
} protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
} @Override
public Integer getTimeout() throws SQLException {
return null;
} }

此外,当Mybatis与Spring一起使用时,Spring会提供一个Transaction的实现类SpringManagedTransaction进行事务管理,这会在后面的Spring源码中说到。

可参考:https://blog.csdn.net/qq924862077/article/details/525997851.2

2、事务配置方式

Mybatis的事务管理方式的配置是在核心配置文件中进行的,它是在configuration标签下的environments中与数据源一起配置的,可以配置多个,如下所示:

 <environments default="development">
<environment id="development">
//配置事务管理方式
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>

二、事务隔离级别

在上面的源码中,我们看到TransactionIsolationLevel—事务隔离级别,Mybaais中定义了五种隔离级别,代码如下所示:

public enum TransactionIsolationLevel {
NONE(Connection.TRANSACTION_NONE),
READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE); private final int level; private TransactionIsolationLevel(int level) {
this.level = level;
} public int getLevel() {
return level;
}
}

其中四种是一般数据库的事务隔离级别,从高到底以此为:Read uncommitted(读未提交)、Read committed(读已提交)、Repeatable read(可重复读)、Serializable(可串行化),这几个级别主要用于解决脏读、不可重复读、幻读等问题,其总结如下表:

级别 脏读 不可重复读 幻读 说明
读未提交 Y Y Y 一个更新语句没有提交,但是别的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。
读已提交 X Y Y 语句提交以后即执行了COMMIT以后别的事务就能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别,可防止脏读。
可重复读 X X Y 同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。
可串行化 X X X 事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

注:Y表示出现,X表示不出现

参考自:https://blog.csdn.net/qq924862077/article/details/52599961

Mybatis添加的隔离级别NONE,可在DefaultSqlSessionFactory中创建SqlSession时,设置数据库的事务隔离级别,以及通过设置autoCommit来设置事务的提交方式。代码参见DefaultSqlSessionFactory,示例代码如下:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)

三、事务工厂

此外,在Mybatis中还提供了事务工厂:TransactionFactory,代码如下所示:

public interface TransactionFactory {

  //配置工厂属性
void setProperties(Properties props); //通过Connection获取事务
Transaction newTransaction(Connection conn); //通过数据库,事务等级,是否自动提交创建事务
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }

类似的,TransactionFactory也有两个实现类:JdbcTransactionFactory和ManagedTransactionFactory

JdbcTransactionFactory代码如下:

public class JdbcTransactionFactory implements TransactionFactory {

  @Override
public void setProperties(Properties props) {
} @Override
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
} @Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
}

ManagedTransactionFactory代码如下:

public class ManagedTransactionFactory implements TransactionFactory {

  private boolean closeConnection = true;

  @Override
public void setProperties(Properties props) {
if (props != null) {
String closeConnectionProperty = props.getProperty("closeConnection");
if (closeConnectionProperty != null) {
closeConnection = Boolean.valueOf(closeConnectionProperty);
}
}
} @Override
public Transaction newTransaction(Connection conn) {
return new ManagedTransaction(conn, closeConnection);
} @Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new ManagedTransaction(ds, level, closeConnection);
}
}

Mybatis事务管理的更多相关文章

  1. spring+mybatis事务管理

    spring+mybatis事务管理 最近在和朋友做一个项目,考虑用springmvc+mybatis来做,之前在公司工作吧,对于数据库这块的配置也有人再弄,最近因为这个项目,我就上网学习了一些关于数 ...

  2. spring,mybatis事务管理配置与@Transactional注解使用[转]

    spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...

  3. 《深入理解mybatis原理》 MyBatis事务管理机制

    MyBatis作为Java语言的数据库框架,对数据库的事务管理是其很重要的一个方面.本文将讲述MyBatis的事务管理的实现机制. 首先介绍MyBatis的事务Transaction的接口设计以及其不 ...

  4. springMVC+mybatis事务管理总结

    1.spring,mybatis事务管理配置与@Transactional注解使用: 概述事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framewo ...

  5. spring,mybatis事务管理配置与@Transactional注解使用

    spring,mybatis事务管理配置与@Transactional注解使用[转]   spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是 ...

  6. SpringMVC+MyBatis 事务管理二

    前言 上篇主要从编程式事务和声明式事务注解的形式来了解了事务,而这篇我们针对AOP的方式来实现事务.先回顾下事务的基础知识事务的隔离级别和事务的传播行为.使用aop 配置事务时注意引用aspectjw ...

  7. springboot mybatis 事务管理

    本文主要讲述springboot提供的声明式的事务管理机制. 一.一些概念 声明式的事务管理是基于AOP的,在springboot中可以通过@Transactional注解的方式获得支持,这种方式的优 ...

  8. Mybatis 事务管理

    mybatis的事务和数据源有着非常密切的联系.上文讲述了mybatis的数据源,本文要讲述的便是mybatis的事物 1.事务的分类 我们还是已一段xml配置文件为例 <environment ...

  9. mybatis事务管理机制详解

    1.mybatis事务的配置和使用 mybatis事务有两种使用方式: (a):使用JDBC的事务管理机制:即使用java.Sql.Connection对象完成对事务的提交,回滚和关闭操作. (b): ...

随机推荐

  1. 从MATLAB到FPGA 视频和图像处理——讲座学习小结(视频地址https://ww2.mathworks.cn/videos/from-matlab-to-fpga-video-and-image-processing-102492.html)

    1.HDLcoder产品介绍 图像处理分为两个部分: 这里主要讨论第一部分图像处理部分. 一般产品设计流程如下: 适用人群有以下两类: 这里先用一张slider来进行整体概括: 基于模型的设计的好处— ...

  2. Spring 使用javaconfig配置aop

    1.在xml中需要配置自动代理 /** * */ package com.junge.demo.spring.dao; import org.springframework.context.annot ...

  3. Js之设置日期时间 判断日期是否在范围内

    var now = new Date(); var startDate = new Date(); startDate.setFullYear(2018, 08, 07); startDate.set ...

  4. Tools - Atom编辑器

    Atom官网 Atom编辑器的常用插件 预览 document-outline:Show a heirarchical outline of a text document minimap:A pre ...

  5. HoloLens开发手记-凝视 Gaze

    在全息应用中,凝视是第一种输入形式,被用于定位物体(功能和PC的光标指针类似).凝视告诉你用户正在看向世界中的位置,让你能够确定他们的意图.在现实世界中,你通常会盯着你打算与之交互的物体.这种方式与凝 ...

  6. OC学习1——基本数据类型

    1.OC是在C语言的基础上进行扩展的一种面向对象的编程语言.很多基础知识都和C语言中的非常类似.首先介绍一下OC中的基本数据类型,整体框架如下图: 2.自动数据类型转换顺序:short --> ...

  7. RawConfigParser 与 ConfigParser ——Python的配件文件读取模块

    一般情况都是使用ConfigParser这个方法,但是当我们配置中有%(filename)s这种格式的配置的时候,可能会出现以下问题: configparser.InterpolationMissin ...

  8. 《深入分析Linux内核源代码》读书、私藏笔记大放送

    秉承着"不懂操作系统原理的程序员不是合格的程序员"的至理名言,鄙人又是买陈莉君老师的“Linux教学视频”,又是研读其力作<深入分析Linux内核源代码>,先将总结笔记 ...

  9. JVM笔记11-类加载器和OSGI

    一.JVM 类加载器: 一个类在使用前,如何通过类调用静态字段,静态方法,或者new一个实例对象,第一步就是需要类加载,然后是连接和初始化,最后才能使用. 类从被加载到虚拟机内存中开始,到卸载出内存为 ...

  10. win32编程简介

    win32编程简介 复习Win32整理下知识. 为什么学习win32? 我们要编写windos程序.都离不开API. 也就是我们所说的win32程序. 所以学好win32是你能不能再windows下编 ...