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针对事务问题作出的第三次修改的更多相关文章

  1. 【转】Pandas学习笔记(三)修改&添加值

    Pandas学习笔记系列: Pandas学习笔记(一)基本介绍 Pandas学习笔记(二)选择数据 Pandas学习笔记(三)修改&添加值 Pandas学习笔记(四)处理丢失值 Pandas学 ...

  2. Mac OS 下三种修改Hosts文件的方法

    一.系统偏好设置修改 1.打开系统偏好设置,底部有一个Hosts的快捷入口2.输入ip和hostname后,回车确定,勾选改host即可   二.终端命令行修改 sudo vi /etc/hosts ...

  3. 分布式事务专题笔记(三)分布式事务解决方案之TCC(三阶段提交)

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1.什么是TCC事务 TCC是Try.Confifirm.Cancel三个词语的缩写,TCC要求每个分支 ...

  4. 【Spring】事务的执行原理(三)

    事务的回滚 如果获取事务属性不为空,并且抛出的异常是RuntimeException或者Error类型,调用事务管理器中的rollback方法进行回滚 如果事务属性为空或者抛出的异常不是Runtime ...

  5. SQL Server提高事务复制效率优化(三)订阅初始化优化

    初始化订阅主要是由分发代理分发和应用快照代理之前生成的快照,所以优化的主体是分发代理. 1.初始化订阅 首先在本地创建一个订阅,发布服务器.分发服务器和订阅服务器都在同一台服务器上,仅为了测试生产环境 ...

  6. uvm_tlm_if_base——TLM1事务级建模方法(三)

    文件: src/tlm1/uvm_tlm_ifs.svh 类: uvm_tlm_if_base 这个类没有派生自任何类,在类的中,定义了三类接口:第一类是阻塞性质的普通方法(task),put, ge ...

  7. SqlServer 并发事务:死锁跟踪(三)6种跟踪死锁的方法总结 大神

    http://blog.csdn.net/kk185800961/article/details/42504857

  8. 小丁带你走进git的世界三-撤销修改

    一.撤销指令 git checkout还原工作区的功能 git reset  还原暂存区的功能 git clean  还没有被添加进暂存区的文件也就是git还没有跟踪的文件可以使用这个命令清除他们 g ...

  9. SQL Server提高事务复制效率优化(四)修改数据同步过程优化

    1.原理       我说的数据修改同步过程指的是在快照生成完毕,分发代理将快照应用于订阅服务器完成订阅服务器初始化后,发布服务器后续的更改同步到订阅服务器过程,这也就是我们常常关注的延迟.此过程主要 ...

随机推荐

  1. myeclipse配置问题

    一,配置相关 1,myeclipse配置jdk Window --> Preferences --> Java --> Installed JREs 2.myeclipse配置tom ...

  2. RecyclerView 必知必会(转)

    [腾讯Bugly干货分享]RecyclerView 必知必会 本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com ...

  3. 多媒体开发之---h264格式slice_header

    从Slice_Header学习H.264 写在前面: $     H.264我是结合标准和毕厚杰的书一块学的.看句法语义时最是头疼,一大堆的元素,很需要耐心.标准中在介绍某个元素的语义时,经常会突然冒 ...

  4. 趣味编程:C#中Specification模式的实现(参考答案 - 下)

    一篇文章中我们利用C#语言的特性实现了一种轻量级的Specification模式,它的关键在于抛弃了具体的Specification类型,而是使用一个委托对象代替唯一关键的IsSatisfiedBy方 ...

  5. hiho一下 第二周&第四周:从Trie树到Trie图

    hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihoc ...

  6. unity视频教程

      英雄联盟教程     http://pan.baidu.com/s/1i3rkMS9 密码:bv6r https://pan.baidu.com/share/link?shareid=258985 ...

  7. Linux Samba文件共享服务配置

    http://blog.csdn.net/xht555/article/details/4631063

  8. java拾遗1----XML解析(一) DOM解析

    XML解析技术主要有三种: (1)DOM(Document Object Model)文档对象模型:是 W3C 组织推荐的解析XML 的一种方式,即官方的XML解析技术. (2)SAX(Simple ...

  9. C语言之基本算法12—谁是冠军

    /* ================================================================== 题目:甲乙丙丁四人猜A,B,C,D,E,F6个人谁是冠军,甲 ...

  10. JVM虚拟机参数

    追踪参数: 打印GC简要信息 -XX:+PrintGC 打印GC详细信息 -XX:+PrintGCDetails 打印CG发生的时间戳 -XX:+PrintGCTimeStamps 指定GC log的 ...