一、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. 《mysql必知必会》学习_第22章_20180809_欢

    第22章:使用视图,视图是虚拟的表,以表形式呈现的是你查询的结果.并不是说在数据库里面真的存在这个表,但是是真的存在这些数据. select cust_name,cust_contact from c ...

  2. android启动画面隐藏状态栏全屏显示

    1.在根部局给一个id,然后直接设置就行了layout.setSystemUiVisibility(View.INVISIBLE); 状态栏就没有了. 2.如果你只是想改变状态栏颜色的也可以 //5. ...

  3. Unix时间戳转日期时间格式,C#、Java、Python各语言实现!

    之前有个Q上好友没事问我,怎么自己写Unix时间戳转日期时间?于是我就顺手写了个C#版本给他!最近想起来,就萌发多写几个语言的版本分享,权当练习思路外加熟悉另外两种语言. 先说转换步骤 先处理年份,从 ...

  4. 背水一战 Windows 10 (81) - 全球化

    [源码下载] 背水一战 Windows 10 (81) - 全球化 作者:webabcd 介绍背水一战 Windows 10 之 全球化 Demo 格式化数字 示例1.演示全球化的基本应用Locali ...

  5. POJ 1177Picture 扫描线(若干矩形叠加后周长)

    Picture   Description A number of rectangular posters, photographs and other pictures of the same sh ...

  6. Android 和 iOS 实现录屏推流的方案整理

    一.录屏推流实现的步骤 1. 采集数据 主要是采集屏幕获得视频数据,采集麦克风获得音频数据,如果可以实现的话,我们还可以采集一些应用内置的音频数据. 2. 数据格式转换 主要是将获取到的视频和音频转换 ...

  7. dubbo rpc调用,接收到的bean为null原因?

    前几天对接公司内部其他部门的系统,用dubbo调用,dubbo看起来很简单,但是却让我们调试了好久啊! 下面是调试纪录: 1. 调用该服务时,直接调不通,查看错误为 no provider ? 然后就 ...

  8. kill 结束进程

    kill 支持的信号 kill -1 重启进程 kill -9 终止进程 pkill 和 killall 的区别在于pkill 可以踢终端用户 pkill  -9  -t tty1

  9. Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin

    Zipkin 是一个开放源代码分布式的跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集.存储.查找和展现.它的理论模型来自于Google ...

  10. Android中内容提供者ContentProvider的详解

    1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不 ...