在Ibatis中我们要执行一个事务,代码是这样的:
sqlMapClient.startTransaction ();
sqlMapClient.add (xxxxx);
sqlMapClient.update (xxxxx);
sqlMapClient.commitTransaction ();
看到这段代码你会不会有一个问题,sqlMapClient里面到底是怎么做的?
我能猜到有两种做法:
1. 调用sqlMapClient.startTransaction时会通知数据库事务开始了,然后依次执行add和update,最后告诉数据库提交事务。
2.调用sqlMapClient.startTransaction时并没有通知数据库,只不过在sqlMapClient这个对象中记录了一个标志,然后下面的add操作与update操作也没有实际上执行语句,只是产生了sql语句并存储在sqlMapClient中。最终调用sqlMapClient.commitTransaction时,会把产生的这些sql语句作为一个事务一次提交执行。
google了一下,没发现有人提出这样的问题。只好自己看源码。下面是源码的调用关系。
SqlMapClientImpl.startTransaction() --->
public void startTransaction(int transactionIsolation) throws SQLException {
getLocalSqlMapSession().startTransaction(transactionIsolation);
}
这里的 getLocalSqlMapSession()返回了一个SqlMapSession对象,这个对象非常重要,它管理了一次事务的状态,为什么重要后面会讲到。
继续跟踪调用
------>SqlMapSessionImpl.startTransaction(transactionIsolation)
------>SqlMapExecutorDelegate.startTransaction(session, transactionIsolation)
------>TransactionManager.begin(session, transactionIsolation)这个方法是重点,看代码:
public void begin(SessionScope session, int transactionIsolation) throws SQLException, TransactionException {
Transaction trans = session.getTransaction();
TransactionState state = session.getTransactionState();
if (state == TransactionState.STATE_STARTED) {
throw new TransactionException("TransactionManager could not start a new transaction. " +
"A transaction is already started.");
} else if (state == TransactionState.STATE_USER_PROVIDED) {
throw new TransactionException("TransactionManager could not start a new transaction. " +
"A user provided connection is currently being used by this session. " +
"The calling .setUserConnection (null) will clear the user provided transaction.");
}
txThrottle.increment();
try {
trans = transactionConfig.newTransaction(transactionIsolation);
-------------------------------------------------------------------
session.setCommitRequired(false);
} catch (SQLException e) {
txThrottle.decrement();
throw e;
} catch (TransactionException e) {
txThrottle.decrement();
throw e;
}
session.setTransaction(trans);
----------------------------------------------
session.setTransactionState(TransactionState.STATE_STARTED);
}
注意用横线标出的那两句,首先创建了一个Transcaction,然后把它放入了session,为什么放入session,很重要,继续往下看。
transactionConfig.newTransaction(transactionIsolation);中创建了一个JdbcTransaction
看看JdbcTransaction的代码:
public class JdbcTransaction implements Transaction {
private static final Log connectionLog = LogFactory.getLog(Connection.class);
private DataSource dataSource;
private Connection connection;
private IsolationLevel isolationLevel = new IsolationLevel();
public JdbcTransaction(DataSource ds, int isolationLevel) throws TransactionException {
// Check Parameters
dataSource = ds;
if (dataSource == null) {
throw new TransactionException("JdbcTransaction initialization failed. DataSource was null.");
}
this.isolationLevel.setIsolationLevel(isolationLevel);
}
private void init() throws SQLException, TransactionException {
// Open JDBC Transaction
connection = dataSource.getConnection();
if (connection == null) {
throw new TransactionException("JdbcTransaction could not start transaction. Cause: The DataSource returned a null connection.");
}
// Isolation Level
isolationLevel.applyIsolationLevel(connection);
// AutoCommit
if (connection.getAutoCommit()) {
connection.setAutoCommit(false);
}
// Debug
if (connectionLog.isDebugEnabled()) {
connection = ConnectionLogProxy.newInstance(connection);
}
}
public void commit() throws SQLException, TransactionException {
if (connection != null) {
connection.commit();
}
}
public void rollback() throws SQLException, TransactionException {
if (connection != null) {
connection.rollback();
}
}
public void close() throws SQLException, TransactionException {
if (connection != null) {
try {
isolationLevel.restoreIsolationLevel(connection);
} finally {
connection.close();
connection = null;
}
}
}
public Connection getConnection() throws SQLException, TransactionException {
if (connection == null) {
init();
}
return connection;
}
}
它在Init方法中调用了
connection.setAutoCommit(false);来开始一个事务。
但是Init方法并没有在构造方法中调用啊。那它是什么时候被调用的呢?
仔细看一下,是在getConnection()方法中调用。那getConnection()又是什么时候被调用呢。回头想一下,前面我们把这个创建出来的transcation对象放入了session,在事务中第一次操作数据库的时候,比如说add操作时,就会从session中把这个transcation对象拿出来,然后调用getConnection()方法。这时就会通知数据库开始一个事务。
到现在为止,我们的问题应该清楚了。我刚开始提出来的两个猜想都不完全正确。不过第一个猜想更接近一点。
正确的答案是:
调用sqlMapClient.startTransaction时并没有通知数据库开始事务。但也不是最后commit时一次提交。
而是在调用sqlMapClient.startTransaction后,第一次执行数据库操作时通知数据库开始事务,在我们的例子中,就是sqlMapClient.add (xxxxx)的这个时机。
分享到:
相关推荐
描述与iBatis相关技术与数据库进行增删改查操作
很好的spring+ibatis事务的配置文档.
SPRING与IBATIS整合采用保留IBATIS事务,可自己控制回滚!
在用iBatis.net与数据库打交道的过程中,发现iBatis.net拼接字符串不能直接拷贝然后在dbms里执行
spring+ibatis声明式事务Demo
操作数据库 iBATIS查询,java 和spring的配置方法
一个关于ibatis事务控制的案例实现,java+ibaitis+sql实现。
spring+ibatis声明式事务Demo源码
iBATIS_DAO事务管理实现
它将内省一个数据库表(或多个表),并将生成可用于访问表的工件。这减轻了设置对象和配置文件以与数据库表进行交互的麻烦。MBG试图对简单CRUD(创建,检索,更新,删除)的大部分数据库操作产生重大影响。您仍将...
本工程以“银行账号转账”为例子演示了 如何处理Ibatis结合MySQL数据库使用时的事务操作 本工程编码方式:UTF-8 须执行的SQL语句: CREATE DATABASE `test`; USE `test`; CREATE TABLE `lm_bank_card` ( `id` ...
ibatis+spring事务控制 压缩文件中有很多例子,如果控制事务,事务不回滚的解决方法等等。另外附上python学习文档。
运用IBATIS在三层架构的基础上建立的数据库连接,主要是一个框架,突出重点,一看就明白。最适合初学者快速学习使用,里面的条路清晰。
IBATIS连接多数据库参考文档,只供参考,学习。
Ibatis连接ORACLE数据库的小例子
SPRING与IBATIS整合采用保留IBATIS事务,可自己控制回滚!
是《ibatis 开发指南》上的例子改的,不过上面讲的不仔细,我开始学的时候搞了一个晚上才把那个例子跑起来的,相信一些朋友也和我一样,在入门的时候有一点小郁闷,我把整个工程项目打包了供朋友下载,工具是eclipse...
1.每个实体类需要配置各自的“SqlMap.config”在“config/SysConfig.xml”中,SqlMap,db1.Db1SqlMap就是“ibatis/db1/Db1SqlMap.config”,不同的db将分配不同的mapper类。 2.数据库链接统一放在“config/ibatis/...
ibatis自定义数据类型在不支持中文的数据库存储汉字
本工程以“银行账号转账”为例子演示了如何处理Spring、Ibatis结合MySQL数据库使用时的事务操作 本工程编码方式:UTF-8 须执行的SQL语句: CREATE DATABASE `test`; USE `test`; CREATE TABLE `lm_bank_card` ( `...