当前位置:   article > 正文

MyBatis事务-----JdbcTransaction_mybatis jdbctransaction

mybatis jdbctransaction

Mybatis管理事务是分为两种方式:

  1. (1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
  2. (2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理

JdbcTransaction

本文主要是学习第一种方式:

先来复习一下JDBC的事务: 
获取数据库连接:conncetion对象 
开始事务:conncetion.setAutoCommit(false),false表示不自动提交事务; 
事务提交:conncetion.commit(); 
事务回滚:conncetion.rollback();

例如下面的代码执行删除操作:

  1. //加载核心配置文件
  2. String resource = "sqlMapConfig.xml";
  3. InputStream in = Resources.getResourceAsStream(resource);
  4. //创建SqlSessionFactory
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
  6. //创建SqlSession
  7. SqlSession sqlSession = sqlSessionFactory.openSession();
  8. //获得Mapper
  9. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  10. userMapper.deleteUserById(31);
  11. //如果不提交,事务会自动回滚,无法插入数据到数据库
  12. sqlSession.commit();
  13. //释放资源
  14. sqlSession.close();

mybatis自动为我们开始了事务,而且设置为不自动提交事务。

但是事务是什么时候开启的呢,于是就去扒了一下源码。因为事务是包含在一次SqlSession会话中的,所以从创建会话开始分析,即SqlSessionFactory的openSession方法开始分析:

SqlSessionFactory是一个接口,它有两个实现类,DefaultSqlSessionFactory和SqlSessionManager,默认情况下使用的是DefaultSqlSessionFactory。 

DefaultSqlSessionFactory的openSession()方法:

  1. public SqlSession openSession() {
  2. return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
  3. }

调用了:openSessionFromDataSource方法:

  1. private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  2. Transaction tx = null;
  3. DefaultSqlSession var8;
  4. try {
  5. //加载配置文件中的数据库信息
  6. Environment environment = this.configuration.getEnvironment();
  7. //创建事务工厂
  8. TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
  9. //实例化事务对象,传入数据源,事务等级,以及是否自动提交事务,但是通过查看源码发现,事务并没有在这里提交
  10. tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
  11. //这是一个执行的对象,是正操作数据库的对象。
  12. Executor executor = this.configuration.newExecutor(tx, execType);
  13. //实例化一个会话对象,并传入executor,当我们通过SqlSession向数据库发送指令时,最终都是调用的executor方法。
  14. var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
  15. } catch (Exception var12) {
  16. this.closeTransaction(tx);
  17. throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
  18. } finally {
  19. ErrorContext.instance().reset();
  20. }
  21. return var8;
  22. }

这里面有一个实例化了一个事务工厂TransactionFactory,TransactionFactory是一个接口:

它也有两个实现类:JdbcTransactionFactory和ManagedTransactionFactory,我们使用的是JDBC事务,所以使用JdbcTransactionFactory的newTransaction方法,创建JdbcTransaction。

查看JdbcTransaction源码:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.apache.ibatis.transaction.jdbc;
  6. import java.sql.Connection;
  7. import java.sql.SQLException;
  8. import javax.sql.DataSource;
  9. import org.apache.ibatis.logging.Log;
  10. import org.apache.ibatis.logging.LogFactory;
  11. import org.apache.ibatis.session.TransactionIsolationLevel;
  12. import org.apache.ibatis.transaction.Transaction;
  13. import org.apache.ibatis.transaction.TransactionException;
  14. public class JdbcTransaction implements Transaction {
  15. private static final Log log = LogFactory.getLog(JdbcTransaction.class);
  16. protected Connection connection;
  17. protected DataSource dataSource;
  18. protected TransactionIsolationLevel level;
  19. protected boolean autoCommmit;
  20. public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
  21. this.dataSource = ds;
  22. this.level = desiredLevel;
  23. this.autoCommmit = desiredAutoCommit;
  24. }
  25. public JdbcTransaction(Connection connection) {
  26. this.connection = connection;
  27. }
  28. //获取数据库连接
  29. public Connection getConnection() throws SQLException {
  30. if (this.connection == null) {
  31. this.openConnection();
  32. }
  33. return this.connection;
  34. }
  35. //事务提交
  36. public void commit() throws SQLException {
  37. if (this.connection != null && !this.connection.getAutoCommit()) {
  38. if (log.isDebugEnabled()) {
  39. log.debug("Committing JDBC Connection [" + this.connection + "]");
  40. }
  41. this.connection.commit();
  42. }
  43. }
  44. //事务回滚
  45. public void rollback() throws SQLException {
  46. if (this.connection != null && !this.connection.getAutoCommit()) {
  47. if (log.isDebugEnabled()) {
  48. log.debug("Rolling back JDBC Connection [" + this.connection + "]");
  49. }
  50. this.connection.rollback();
  51. }
  52. }
  53. //关闭资源
  54. public void close() throws SQLException {
  55. if (this.connection != null) {
  56. this.resetAutoCommit();
  57. if (log.isDebugEnabled()) {
  58. log.debug("Closing JDBC Connection [" + this.connection + "]");
  59. }
  60. this.connection.close();
  61. }
  62. }
  63. //设置事务是否自动提交
  64. protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
  65. try {
  66. if (this.connection.getAutoCommit() != desiredAutoCommit) {
  67. if (log.isDebugEnabled()) {
  68. log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + this.connection + "]");
  69. }
  70. this.connection.setAutoCommit(desiredAutoCommit);
  71. }
  72. } catch (SQLException var3) {
  73. throw new TransactionException("Error configuring AutoCommit. Your driver may not support getAutoCommit() or setAutoCommit(). Requested setting: " + desiredAutoCommit + ". Cause: " + var3, var3);
  74. }
  75. }
  76. //重置事务提交方式
  77. protected void resetAutoCommit() {
  78. try {
  79. if (!this.connection.getAutoCommit()) {
  80. if (log.isDebugEnabled()) {
  81. log.debug("Resetting autocommit to true on JDBC Connection [" + this.connection + "]");
  82. }
  83. this.connection.setAutoCommit(true);
  84. }
  85. } catch (SQLException var2) {
  86. log.debug("Error resetting autocommit to true before closing the connection. Cause: " + var2);
  87. }
  88. }
  89. protected void openConnection() throws SQLException {
  90. if (log.isDebugEnabled()) {
  91. log.debug("Opening JDBC Connection");
  92. }
  93. this.connection = this.dataSource.getConnection();
  94. if (this.level != null) {
  95. this.connection.setTransactionIsolation(this.level.getLevel());
  96. }
  97. this.setDesiredAutoCommit(this.autoCommmit);
  98. }
  99. }

在getConnection()方法中调用了openConnection()方法,获取数据库连接,设置了等级,开启了事务。

回到上面的openSessionFromDataSource方法,创建好事务对象后,紧接着又实例化了两个对象:一个是Executor对象,一个的DefaultSqlSession对象,并将这个对象返回,并没有调用getConnection()方法,所以事务的开始并不在OpenSession方法中,那么我猜测,事务的开始,是在准备执行向数据库发送Sql语句的时候,于是回到最上面执行删除的代码中:
 

  1. //加载核心配置文件
  2. String resource = "sqlMapConfig.xml";
  3. InputStream in = Resources.getResourceAsStream(resource);
  4. //创建SqlSessionFactory
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
  6. //创建SqlSession
  7. SqlSession sqlSession = sqlSessionFactory.openSession();
  8. //获得Mapper
  9. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  10. userMapper.deleteUserById(31);
  11. //如果不提交,事务会自动回滚,无法插入数据到数据库
  12. sqlSession.commit();
  13. //释放资源
  14. sqlSession.close();

在userMapper.deleteUserById(31)这里打了一下断点,然后一路追踪到了SimpleExecutor发doUpdate方法中,SimpleExecutor是Executor的实现类:

  1. public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
  2. Statement stmt = null;
  3. int var6;
  4. try {
  5. Configuration configuration = ms.getConfiguration();
  6. StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
  7. stmt = this.prepareStatement(handler, ms.getStatementLog());
  8. var6 = handler.update(stmt);
  9. } finally {
  10. this.closeStatement(stmt);
  11. }
  12. return var6;
  13. }

然后查看:prepareStatement()方法:

  1. private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  2. Connection connection = this.getConnection(statementLog);
  3. Statement stmt = handler.prepare(connection);
  4. handler.parameterize(stmt);
  5. return stmt;
  6. }

看到了getConnection,继续追进去:

进入BaseExecutor的getConnection方法:

  1. protected Connection getConnection(Log statementLog) throws SQLException {
  2. Connection connection = this.transaction.getConnection();
  3. return statementLog.isDebugEnabled() ? ConnectionLogger.newInstance(connection, statementLog, this.queryStack) : connection;
  4. }

Connection connection = this.transaction.getConnection();这一句调用了传入的transaction的getConnection方法, 
这里的transaction使我们在opensession方法中,实例化,并传入的。至此终于找到事务在哪开启的了。

分析了一大堆:其实只要记住,MyBatis使用JDBC进行事务管理的时候,会默认开始事务,并设置不自动提交事务
 

  1. package com.xf.app1;
  2. import com.xf.app1.mapper.UserMapper;
  3. import com.xf.app1.pojo.User;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. public class Xml_SqlSessionFactory {
  11. public static void main(String[] args) {
  12. SqlSessionFactory sqlSessionFactory;
  13. SqlSession sqlSession = null;
  14. //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件)
  15. try {
  16. //mybatis配置文件
  17. String resource = "com/xf/app1/mybatis-config.xml";
  18. InputStream inputStream = Resources.getResourceAsStream(resource);
  19. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  20. //创建能执行映射文件中sql的sqlSession
  21. sqlSession = sqlSessionFactory.openSession();
  22. //获取mapper方式
  23. UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
  24. User user1 =userMapper.selectUser(1L) ;
  25. System.out.println(user1);
  26. userMapper.deleteUserById(1L);//这里删除是不会提交到数据库的
  27. //通过具体路径
  28. User user = sqlSession.selectOne("com.xf.app1.mapper.UserMapper.selectUser", 1);
  29. System.out.println(user);
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }finally {
  33. if (sqlSession != null) {
  34. sqlSession.close();
  35. }
  36. }
  37. }
  38. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/748952
推荐阅读
相关标签
  

闽ICP备14008679号