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.原理 我说的数据修改同步过程指的是在快照生成完毕,分发代理将快照应用于订阅服务器完成订阅服务器初始化后,发布服务器后续的更改同步到订阅服务器过程,这也就是我们常常关注的延迟.此过程主要 ...
随机推荐
- cocos2d-x 2.x 支持多个方向屏幕翻转
主要改动 RootViewController.mm 的 supportedInterfaceOrientations 方法 1.四个方向 UIInterfaceOrientationMaskAll ...
- SVN版本号控制软件-图片含义具体解释
转载请注明出处:http://blog.csdn.net/zhuwentao2150/article/details/51195154 自己定义SVN图标显示风格 SVN的图标是能够自己定义风格的 右 ...
- ios8 一些运行问题
iOS10相册相机闪退bughttp://www.jianshu.com/p/5085430b029fiOS 10 因苹果健康导致闪退 crashhttp://www.jianshu.com/p/5 ...
- PHP中使用POST发送请求的常用方式
前提概要: 在PHP进行项目开发过程中,使用post发送请求的情况很多,以下总结了项目中主要用的两种方式. 总结下: 在我接触到的项目中用到第二种情况较多,比如写:短信接口.....总体来说比较简单便 ...
- 读《《图解TCP-IP》》有感
读<<图解TCP/IP>>有感 TCP/IP 近期几天读完<<图解TCP/IP>>,收获蛮多,记得上学时读stevens的<<TCP/IP具 ...
- One Person Game(概率+数学)
There is a very simple and interesting one-person game. You have 3 dice, namelyDie1, Die2 and Die3. ...
- spring boot ajax post 前后端
1 传输的数据格式是json 1.1 前端ajax json的所有的key都必须是双引号引用的,并且最外层也要用双引号引用.例如 "{"a":b, "b&quo ...
- java对IO的操作
import java.io.*; public class HelloWorld { //Main method. public static void main(String[] args) { ...
- 使用oracle10g官方文档找到监听文件(listener.ora)的模板
***********************************************声明*************************************************** ...
- kettle连接资源库设置
到这里你是登陆不上去的,需要创建或更新按钮,因为需要在你的数据库里创建关于kettle的数据表,来存储资源库 点执行就可以了 一般情况下kettle资源库自动给你创建两个用户: 工具->资源库- ...