在Dao中处理事务:
public void xxx(){ 在dao中应该是对数据库的基本访问,不应该存在业务
Connection con =null;
try{
con=JdbcUtils.getConnection();
con.setAutoCommitted(false);
QueryRunner qr=new QueryRunner();
String sql = ......;
Object[] params=....;
qr.update(con,sql,params);
sql=.....;
Object[] params=....;
qr.update(con,sql,params);
con.commit();
}catch(Exception e){
try{
if(con!=null) con.rollback();
}catch(Exception e){}
}finally{
try{
con.close();
}catch(Exception e){}
}
}
在service中处理业务:
public class xxxService(){ service中不应该出现connection,它只应该在dao中出现
private xxxDao dao = new xxxDao();
public void serviceMethod(){
Connextion con = null;
try{
con=JdbcUtils.getConnection();
con.setAutoCommitted(false);
dao.daoMethod1(con,....);
dao.daoMethod2(con,....);
con.commint();
}catch(Exception e){
try{
if(con!=null) con.rollback();
}catch(Exception e){}
}finally{
try{
con.close();
}catch(Exception e){}
}
}
}
我们希望可以这样来处理事务
public class xxxService(){
private XXXDao dao = new XXXDao();
public void serviceMethod(){
try{
JdbcUtils.beginTransaction(); //为con赋值,它不再为null
dao.daoMethod1(...); //内部会调用JdbcUtils.getConnection(),如果con不为null,那么返回的是con,多次调用dao方法,返回的是同一个Connection
dao.daoMethod2(...);
JdbcUtils.commitTransaction();//调用con.commit()
}catch(Exception e){
JdbcUtils.rollbackTransaction();//调用con.rollback()
}
}
}
JdbcUtils源码:
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
//事务专用连接
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
/**
* 使用连接池返回一个连接对象
*/
public static Connection getConnection() throws SQLException {
Connection con = tl.get();
//当con不等于null,说明已经调用过了beginTransaction()方法了,表示开启了事务
if(con!=null) return con;
return dataSource.getConnection();
}
/**
* 返回连接池对象
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
*开启事务
* 1.获取一个connection,设置它的setAutoCommit(false)
* 2.还要保证dao中使用的连接是我们刚刚创建的!
* --------
* 1.创建一个connection,设置为手动提交
* 2.把这个connection给dao使用
* 3.还要让commitTransaction或rollbackTransaction可以获取到!
* @return
*/
public static void beginTransaction() throws SQLException {
Connection con = tl.get();
if(con != null) throw new SQLException("已经开启了事务,就不能重复开启了!");
//1.给con赋值!
//2.给con设置为手动提交!
con = getConnection();
con.setAutoCommit(false);
tl.set(con);//把当前线程的连接保存起来
}
/**
* 提交事务
* 1.获取beginTransaction提供的connection,然后调用commit方法
*/
public static void commitTransaction() throws SQLException {
Connection con = tl.get();//获取当前线程的专用连接
if(con == null) throw new SQLException("没有开启事务,不能提交");
/*
1.直接使用con.commit()
*/
con.commit();
con.close();
//把它设置为null,表示事务已经结束了,下次再去调用getConnection返回的就不是con了
tl.remove();//从tl中移除连接
}
/**
* 提交事务
* 1.获取beginTransaction提供的connection,然后调用rollback方法
*/
public static void rollbackTransaction() throws SQLException {
Connection con = tl.get();
if(con == null) throw new SQLException("还没有开启事务,不能回滚");
/*
1.直接使用con,rollback()
*/
con.rollback();
con.close();
tl.remove();
}
/**
* 释放连接
* @param connection
*/
public static void releaseConnection(Connection connection) throws SQLException {
Connection con = tl.get();
/**
* 判断他是不是事务专用,如果是,就不关闭!
* 如果不是事务专用,那么就关闭
*/
//如果con == null,说明现在没有事务,那么connection一定不是事务专用的!
if(con == null) connection.close();
//如果con != null,说明有实物,那么需判断参数连接是否与con相等,若不等,说明参数连接不是事务专用连接
if(con != connection) connection.close();
}