JdbcUtils针对事务问题作出的第三次修改
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;
} }
}
JdbcUtils针对事务问题作出的第三次修改的更多相关文章
- 【转】Pandas学习笔记(三)修改&添加值
Pandas学习笔记系列: Pandas学习笔记(一)基本介绍 Pandas学习笔记(二)选择数据 Pandas学习笔记(三)修改&添加值 Pandas学习笔记(四)处理丢失值 Pandas学 ...
- Mac OS 下三种修改Hosts文件的方法
一.系统偏好设置修改 1.打开系统偏好设置,底部有一个Hosts的快捷入口2.输入ip和hostname后,回车确定,勾选改host即可 二.终端命令行修改 sudo vi /etc/hosts ...
- 分布式事务专题笔记(三)分布式事务解决方案之TCC(三阶段提交)
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 1.什么是TCC事务 TCC是Try.Confifirm.Cancel三个词语的缩写,TCC要求每个分支 ...
- 【Spring】事务的执行原理(三)
事务的回滚 如果获取事务属性不为空,并且抛出的异常是RuntimeException或者Error类型,调用事务管理器中的rollback方法进行回滚 如果事务属性为空或者抛出的异常不是Runtime ...
- SQL Server提高事务复制效率优化(三)订阅初始化优化
初始化订阅主要是由分发代理分发和应用快照代理之前生成的快照,所以优化的主体是分发代理. 1.初始化订阅 首先在本地创建一个订阅,发布服务器.分发服务器和订阅服务器都在同一台服务器上,仅为了测试生产环境 ...
- uvm_tlm_if_base——TLM1事务级建模方法(三)
文件: src/tlm1/uvm_tlm_ifs.svh 类: uvm_tlm_if_base 这个类没有派生自任何类,在类的中,定义了三类接口:第一类是阻塞性质的普通方法(task),put, ge ...
- SqlServer 并发事务:死锁跟踪(三)6种跟踪死锁的方法总结 大神
http://blog.csdn.net/kk185800961/article/details/42504857
- 小丁带你走进git的世界三-撤销修改
一.撤销指令 git checkout还原工作区的功能 git reset 还原暂存区的功能 git clean 还没有被添加进暂存区的文件也就是git还没有跟踪的文件可以使用这个命令清除他们 g ...
- SQL Server提高事务复制效率优化(四)修改数据同步过程优化
1.原理 我说的数据修改同步过程指的是在快照生成完毕,分发代理将快照应用于订阅服务器完成订阅服务器初始化后,发布服务器后续的更改同步到订阅服务器过程,这也就是我们常常关注的延迟.此过程主要 ...
随机推荐
- Django下实现HelloWorld
我的实现工具:window10 在window10 下面,实现第一个Django的HelloWorld项目. 1.创建一个项目 确保你的电脑上装了python和Django.我的是在python2.7 ...
- 01 mongodb 的特点
mongoDB 介绍(特点.优点.原理) 介绍:MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. 特点:高性能.易部署.易使用,存 ...
- 推荐一个android 日期时间选择器(转)
最近接触了日期选择的功能,那么肯定得需要一个日期选择控件,Android 系统有自带的 DatePicker 控件,但是不说这个控件有多 难看吧,现在 Android 手机版本那么多,用户弹出来的控件 ...
- shell 遍历所有文件包括子目录
1.代码简单,但是难在校验,不像python那么好理解 建议在Notepad++下编辑. 2.注意引用linux命令的`是[tab]键上面那个 3.if[] 这里 Error : syntax er ...
- mysql windows安装
http://blog.csdn.net/tossgoon/article/details/44412491 1.从该地址http://dev.mysql.com/downloads/mysql/中选 ...
- 小贝_php+redis简单实例
php+redis简单实例 一.说明 因为redis是c/s架构.从这个角度上.不论什么符合redis的client要求的.都能够与redis进行通讯.官方提供了非常多的client. php在web ...
- Java引用类型作为形参和返回值
一.什么是引用类型 在Java中引用类型包括三种:类.抽象类.接口. 二.引用类型作为形参使用 1.类作为形参 /** * 类作为形参,实际传递的是该类的对象 */ class Student { p ...
- Cocos2d-x中使用第三方so库
项目中假设使用到第三方的SDK,大多数是以.so动态共享库的文件打包给我们使用.怎样使用他们,见以下分析. 1.获得库文件 假如我们得到的库文件是libxxx.so(注:关于.so文件的命名方式,可百 ...
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
[BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...
- Hibernate 表连接hql语句
现有两个表 user 表 和 VIPcard 表 UserVo user VIPcardVo 中含有 UserVo user select v from VIPCardVo v left join ...