先看一部分代码 这里面有一些值得注意的地方 public void insertUser(User user) { try { //加载主配置文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //创建sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //创建sqlSession sqlSession = sqlSessionFactory.openSession(); //默认提交 在创建中使用的是false; //插入 默认没有提交 //疑问? 为什么需要提交 没有显示开启事务 得到sessions时从environment中获取事务管理,开启事务 //io流为什么不需要关 在SqlSessionFactoryBuilder().build(inputStream)中会调用io流的关闭函数 sqlSession.insert("insertUser", user); //增insert,删delete, 底层都是调用的update函数 //没有这一句为什么数据库中表没有 sqlSession.commit(); //提交以后事务不会回滚, 提交后会回滚,通过ditry 提交后为false //未提交为true; } catch (IOException e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
首先进入new SqlSessionFactoryBuilder().build(inputStream);看看究竟是怎样调用的
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { SqlSessionFactory var5; try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); var5 = this.build(parser.parse()); } catch (Exception var14) { throw ExceptionFactory.wrapException("Error building SqlSession.", var14); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException var13) { ; } } return var5; }
首先建立了一个XMLConfigBuilder 型的xml解析器,在通过this.build(parser.parse())得到 SqlSessionFactory(默认是
返回DefaultSqlSessionFactory),并注意在使用完后该方法中已近帮我们关闭了inputStream,因此我们在使用过程中不需要关闭inputStream
接着看我们的openSession函数
public SqlSession openSession() { return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false); }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; DefaultSqlSession var8; try { Environment environment = this.configuration.getEnvironment(); TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); Executor executor = this.configuration.newExecutor(tx, execType); var8 = new DefaultSqlSession(this.configuration, executor, autoCommit); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; }
到这里我们明白了
configuration存放着我们所有的mybatis.xml 中的配置是对配置文件的一个封装,这里 通过配置文件取得环境 也就是
事务工厂,并得到一个事务, 然后获取一个执行器,最后最终初始化了sqlSession并返回在这里 通过上面两个方法我们知道这里的autoCommit(从名字中我们也可以猜出)是false
接着我们继续往下看DefaultSqlSession的insert方法
public int insert(String statement, Object parameter) { return this.update(statement, parameter); }
//这里可以看出是调用了update方法
public int update(String statement, Object parameter) { int var4; try { this.dirty = true; MappedStatement ms = this.configuration.getMappedStatement(statement); var4 = this.executor.update(ms, this.wrapCollection(parameter)); } catch (Exception var8) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + var8, var8); } finally { ErrorContext.instance().reset(); } return var4; }
//这里通过配置类获取我们所写的sql语句也就是 id为"insertUser" 对应得语句 ,然后通过我们的执行器就行执行,但这里需要注意 this.dirty = true; 这个是用于标志内存中数据是否跟数据库中是否一致,设为true表示不一致因为即将要修改。
接着我们看一下sqlSession.commit()函数
public void commit() { this.commit(false); }
继续
public void commit(boolean force) { try { this.executor.commit(this.isCommitOrRollbackRequired(force)); this.dirty = false; } catch (Exception var6) { throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + var6, var6); } finally { ErrorContext.instance().reset(); } }
this.executor.commit(this.isCommitOrRollbackRequired(force)); 注意这一步 我们看实现 并且在这里注意一下,执行完提交后
会执行这句 this.dirty = false; 意思是提交完成,数据库状态中的记录与内存中数据一致
private boolean isCommitOrRollbackRequired(boolean force) { return !this.autoCommit && this.dirty || force; }
这里我们注意 force闯入的是false,而 this.dirty在上面我们知道被设置为了true,所以最终由this.autoCommit决定,当我们
直接使用不带参数的openSession默认.autoCommit是为false故这里为返回的为真
继续看commit函数 public void commit(boolean required) throws SQLException { if (this.closed) { throw new ExecutorException("Cannot commit, transaction is already closed"); } else { this.clearLocalCache(); this.flushStatements(); if (required) { this.transaction.commit(); } } }
这里的required是为真,故事务提交即sqlSession.commit()提交或导致事务的提交
在这里我们知道了sqlSession.commit()提交会进行事务的提交
接下来我们关注一下sqSession.close() 来明白为什么我们不需要担心失败会滚的问题了
public void close() { try { this.executor.close(this.isCommitOrRollbackRequired(false)); this.closeCursors(); this.dirty = false; } finally { ErrorContext.instance().reset(); } }
看一下这个方法
private boolean isCommitOrRollbackRequired(boolean force) { return !this.autoCommit && this.dirty || force; }
这里 !this.autoCommit是true, force为false,所以值由dirty决定,在前面commit中,若提交成功,dirty或被重新设置为false
则返回的是false, 若提交不成功,则返回的是true,则返回的是true
我们看executor的close方法 public void close(boolean forceRollback) { try { try { this.rollback(forceRollback); } finally { if (this.transaction != null) { this.transaction.close(); } } } catch (SQLException var11) { log.warn("Unexpected exception on closing transaction. Cause: " + var11); } finally { this.transaction = null; this.deferredLoads = null; this.localCache = null; this.localOutputParameterCache = null; this.closed = true; } }
再看rollbanck方法 我们知道 public void rollback(boolean required) throws SQLException { if (!this.closed) { try { this.clearLocalCache(); this.flushStatements(true); } finally { if (required) { this.transaction.rollback(); } } } }
在这里我们终于知道了 若是 提交成功 required就是false 就不会回滚, 若提交失败。required就是true就会回滚事务。 同时也应当注意 当我们使用sqlSessionFactory.openSession() 在 做一些跟新操作的时候别忘了使用sqlsession.commit()哦! 不然所有的都会回滚 。