DAO中的事务
其实在DAO中处理事务真的是“小菜一碟”
try{
con.commit();
}catch(Exception e){
con.rollback();
}
但是dao层中只能是对账户金额的修改而不是业务的处理
service层中也可以使用刚才的格式,使用con会暴露出service直接使用数据库的问题

我们希望这样来处理事务:
public class XXXService(){
private XXXDao dao=new XXXDao();
public void serviceMethod(){
try{
JdbcUtils.beginTransaction();
dao.daoMethod1(...);
dao.daoMethod2(...);
JdbcUtils.commitTransaction();
}catch(Exception e){
JdbcUtils.rollbackTransaction();
}
}
}
修改后:

package cn.itcast.cn;

import java.sql.Connection;
import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JdbcUtils {
/*
* 配置文件的恶魔人配置!要求你必须给出c3p0-config。xnl!
*/
private static ComboPooledDataSource dataSource=new ComboPooledDataSource("oracle-config");
/**
* 它是事务专用连接
*/
private static Connection con=null;
/**
* 使用连接池返回一个连接对象
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
//当con!=null,表示已经调用过beginTransaction方法了
if(con!=null) return con;
return dataSource.getConnection();
} /**
* 返回连接池对象
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 1、开启一个Connection,设置它的setAutoCommit(false)
* 2、还要保证dao中使用的连接是我们刚刚创建的
* ------------------------
* 1、创建一个Connection,设置为手动提交
* 2、把这个Connection给dao用
* 3、还要让commitTransaction或rollbackTransaction可以获取到
* @throws SQLException
*/
public static void beignTransaction() throws SQLException{
if(con!=null) throw new SQLException("已经开始了事务,就不要继续开启事务了!");
con=getConnection();
con.setAutoCommit(false);
}
/**
* 提交事务
* 获取之前开启的Connection,兵提交
* @throws SQLException
*/
public static void commitTransaction() throws SQLException{
if(con==null) throw new SQLException("还没有开启事务,不能提交!");
con.commit();
con.close();
con=null;//因为前面的close()不会销毁连接而是放回连接池
}
/**
* 回滚事务
* 获取之前开启的Connection,兵回滚
* @throws SQLException
*/
public static void rollbackTransaction() throws SQLException{
if(con==null) throw new SQLException("还没有开启事务,不能提交!");
con.rollback();
con.close();
con=null;//因为前面的close()不会销毁连接而是放回连接池
}
}
package cn.itcast.cn;

import java.sql.Connection;
import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; public class AccountDao {
public static void update(String name,double money) throws SQLException{
QueryRunner qr=new QueryRunner();
String sql="UPDATE account SET balance=balance+? WHERE aname=?";
Object[] params={money,name}; //我们需要自己来提供连接,保证多次调用使用的是同一个连接
Connection con=JdbcUtils.getConnection();
qr.update(con, sql, params);
}
}
package cn.itcast.cn;

import java.sql.SQLException;

import org.junit.Test;

@SuppressWarnings("static-access")
public class Demo1 {
private AccountDao dao=new AccountDao();
@Test
public void serviceMethod(){
try{
JdbcUtils.beignTransaction();
dao.update("zs", -1000);
dao.update("lisi", +1000);
JdbcUtils.commitTransaction();
}catch(Exception e){
try {
JdbcUtils.rollbackTransaction();
} catch (SQLException e1) {
e1.printStackTrace();
}
} }
}

针对前面的针对多线程并发问题和代码复杂度问题作出的再次优化:

package cn.itcast.cn;

import java.sql.Connection;
import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JdbcUtils {
/*
* 配置文件的恶魔人配置!要求你必须给出c3p0-config。xnl!
*/
private static ComboPooledDataSource dataSource=new ComboPooledDataSource();
/**
* 它是事务专用连接
*/
private static ThreadLocal<Connection> t1=new ThreadLocal<Connection>();
/**
* 使用连接池返回一个连接对象
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
//当con!=null,表示已经调用过beginTransaction方法了
Connection con=t1.get();
if(con!=null) return con;
return dataSource.getConnection();
} /**
* 返回连接池对象
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 1、开启一个Connection,设置它的setAutoCommit(false)
* 2、还要保证dao中使用的连接是我们刚刚创建的
* ------------------------
* 1、创建一个Connection,设置为手动提交
* 2、把这个Connection给dao用
* 3、还要让commitTransaction或rollbackTransaction可以获取到
* @throws SQLException
*/
public static void beignTransaction() throws SQLException{
Connection con=t1.get();
if(con!=null) throw new SQLException("已经开始了事务,就不要继续开启事务了!");
con=getConnection();
con.setAutoCommit(false);
t1.set(con);//把连接保存起来
}
/**
* 提交事务
* 获取之前开启的Connection,兵提交
* @throws SQLException
*/
public static void commitTransaction() throws SQLException{
Connection con=t1.get();
if(con==null) throw new SQLException("还没有开启事务,不能提交!");
con.commit();
con.close();
// con=null;//因为前面的close()不会销毁连接而是放回连接池
t1.remove();//从t1中移除连接
}
/**
* 回滚事务
* 获取之前开启的Connection,兵回滚
* @throws SQLException
*/
public static void rollbackTransaction() throws SQLException{
Connection con=t1.get();
if(con==null) throw new SQLException("还没有开启事务,不能提交!");
con.rollback();
con.close();
// con=null;//因为前面的close()不会销毁连接而是放回连接池
t1.remove();
} public static void releaseConnection(Connection connection) throws SQLException{
/*
*判斷它是不是中事務專用,如果是就不關閉
*如果不是就要關閉
*/
//如果con==null,說明沒有事務,那麼connection一定不是事務專用的
Connection con=t1.get();
if(con==null) connection.close();
if(con!=connection) connection.close(); }
}
package cn.itcast.cn;

import java.sql.Connection;
import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
/**
* 这个类中的方法自己来处理连接的问题
* 无需外界传递
* 怎么处理的呢?
* 通过JdbcUtils.getConnection()得到连接!有可能是事务连接也有可能是普通连接
* JdbcUtils.releaseConnection()完成连接的释放
* @author Administrator
*
*/
public class TxQueryRunner extends QueryRunner{ @Override
public int[] batch(String sql, Object[][] params) throws SQLException {
/**
* 得到连接
* 执行父类方法
* 释放连接
* 返回值
*/
Connection con=JdbcUtils.getConnection();
int[] result=super.batch(con, sql, params);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public <T> T query(String sql, Object param, ResultSetHandler<T> rsh)
throws SQLException {
Connection con=JdbcUtils.getConnection();
T result=super.query(con, sql, param,rsh);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh)
throws SQLException {
Connection con=JdbcUtils.getConnection();
T result=super.query(con,sql, params, rsh);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
throws SQLException {
Connection con=JdbcUtils.getConnection();
T result=super.query(con,sql, rsh,params);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
Connection con=JdbcUtils.getConnection();
T result=super.query(con,sql, rsh);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public int update(String sql) throws SQLException {
Connection con=JdbcUtils.getConnection();
int result=super.update(con,sql);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public int update(String sql, Object param) throws SQLException {
Connection con=JdbcUtils.getConnection();
int result=super.update(con,sql,param);
JdbcUtils.releaseConnection(con);
return result;
} @Override
public int update(String sql, Object... params) throws SQLException {
Connection con=JdbcUtils.getConnection();
int result=super.update(con,sql,params);
JdbcUtils.releaseConnection(con);
return result;
} }
package cn.itcast.cn;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

public class AccountDao {
public static void update(String name,double money) throws SQLException{
// QueryRunner qr=new QueryRunner();
QueryRunner qr=new TxQueryRunner();
String sql="UPDATE account SET balance=balance+? WHERE aname=?";
Object[] params={money,name}; //我们需要自己来提供连接,保证多次调用使用的是同一个连接
// Connection con=JdbcUtils.getConnection();
// qr.update(con, sql, params);
// JdbcUtils.releaseConnection(con);
qr.update(sql,params);
}
} package cn.itcast.cn; import java.sql.SQLException; import org.junit.Test; @SuppressWarnings("static-access")
public class Demo1 {
private AccountDao dao=new AccountDao();
@Test
public void serviceMethod() throws Exception{
try{
JdbcUtils.beignTransaction();
dao.update("zs", -1000);
if(true) throw new RuntimeException("不好依稀");
dao.update("lisi", +1000);
JdbcUtils.commitTransaction();
}catch(Exception e){
try {
JdbcUtils.rollbackTransaction();
} catch (SQLException e1) {
e1.printStackTrace();
}
throw e;
} }
}

最新文章

  1. 【leetcode】两数之和
  2. VA01复制单据,更新定价日期和价格
  3. IOS第八天(1:UITableViewController团购,数据转模型,xib显示数据)
  4. (13)odoo翻译
  5. 自学Java过程
  6. Get current time and date on Android
  7. ogg实现oracle到sql server 2005的同步
  8. 「python」: arp脚本的两种方法
  9. SQL点滴23—T-SQL中的除法
  10. Echart图表相关配置项的设置
  11. duilib 绘制IP控件
  12. git使用:本地项目推送到gitlab
  13. 厘摩(centimorgan,cM)到底是啥鬼
  14. ES学习
  15. mac系统上mysql开启外网访问
  16. [PHP]算法-归并排序的PHP实现
  17. fastjson 反序列化漏洞笔记,比较乱
  18. 笔记本U盘安装CentOS 7
  19. 事件驱动模型 IO多路复用 阻塞IO与非阻塞IO select epool
  20. 如何自定义CollectionView中每个元素的大小和间距

热门文章

  1. 使用strace,lstrace,truss来跟踪程序的运行过程
  2. android bug archive
  3. python selenium2示例 - email发送
  4. diamond源码阅读-目录监控
  5. systemctl使用说明
  6. java.lang.IllegalStateException: ImageView no longer exists. You should not use this PhotoViewAttacher any more.
  7. 【BZOJ3060】[Poi2012]Tour de Byteotia 并查集
  8. H - Funny Car Racing
  9. python字符串基本方法
  10. spring web app的结构