我们通过SqlSessionFactory.openSession()方法创建出SqlSession对象时,自动提交事务默认是关闭的,即每次用SqlSession对象执行sql操作时必须显式commit()否则操作无效.源码如下:
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
从源码可以看出boolean autoCommit=false.因此在使用SqlSession对象调用相应的方法去执行sql语句时必须要手动调用commit()方法提交事务修改操作才会生效.
但是如果通过mapper动态代理的方式获取DAO对象后去执行sql语句就不需要执行commit()方法来提交事务,这是为什么呢?我们来看一下源码:
1.获取mapper动态代理对象
public T getMapper(Class type) {
return this.configuration.getMapper(type, this);
}
此时,在真正执行sql的时候会通过MapperMethod对象调用execute(SqlSession sqlSession, Object[] args)方法,源码如下:
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
接着跟踪源码就可以发现,最终的执行时由Statement或PreparedStatement对象去真正的执行sql语句.
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
int var6;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
stmt = this.prepareStatement(handler, ms.getStatementLog());
var6 = handler.update(stmt);
} finally {
this.closeStatement(stmt);
}
return var6;
}
追踪源码到此就应该知道为什么采用mapper动态代理的方式不需要手动提交事务了.因为Mysql默认都是自动提交事务的,此时使用Statement或PreparedStatement对象去真正的执行sql语句时并没有显式关闭自动提交事务,所以不需要手动提交.这就是为什么使用SqlSession去执行sql时要手动提交事务而使用mapper动态代理的方式不需要.
补充知识(JDBC连接的创建代码):
public class JDBCTest12 {
/**
* @param args
*/
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
String url = "jdbc:mysql://127.0.0.1:3366/bjpowernode";
String user = "root";
String password = "0987";
conn = DriverManager.getConnection(url, user, password);
//关闭事务的自动提交,开始事务
conn.setAutoCommit(false);
//3.定义SQL语句构架
String sql = "select job,ename,sal from emp_bak where job = ? for update";
//4.进行SQL语句的预编译
ps = conn.prepareStatement(sql);
//5.进行赋值
ps.setString(1, "MANAGER");
//6.执行SQL语句
rs = ps.executeQuery();
//7.处理查询结果集
while(rs.next()){
String job = rs.getString("job");
String ename = rs.getString("ename");
double sal = rs.getDouble("sal");
System.out.println(job + " " + ename + " " + sal);
}
//提交事务
conn.commit();
} catch (Exception e) {
try {
//事务的回滚
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
//关闭资源
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class JDBCTest06
{
public static void main(String[] args){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
//1.注册驱动
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);
//2.获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3366/bjpowernode","root","111");
//3.获取数据库操作对象
stmt = conn.createStatement();
//4.执行SQL语句:DQL语句->处理查询结果集
String sql = "select e.ename,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal";
rs = stmt.executeQuery(sql);
/*
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
*/
//5.处理查询结果集
while(rs.next()){
/*
String ename = rs.getString("ename");
double sal = rs.getDouble("sal");
int grade = rs.getInt("grade");
*/
//不建议以下写法:程序可读性不强
String ename = rs.getString(1);
double sal = rs.getDouble(2);
int grade = rs.getInt(3);
System.out.println(ename + " " + sal + " " + grade);
}
}catch(Exception e){
e.printStackTrace();
}finally{
//6.关闭资源
if(rs != null){
try{
rs.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(stmt != null){
try{
stmt.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}