1. DAO 事务

// 在 DAO 中处理事务真是"小菜一碟"

public void xxx(){
Connection con = null;
try{
con = JdbcUtils.getConnection();
con.setAutoCommit(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){}
}
}

2. Service 才是处理事务的地方

  • DAO 中不是处理事务的地方,因为 DAO 中的每个方法都是对数据库的一次操作, 而 Service 中的方法才是

    对应一个业务逻辑,也就是我们需要在 Service 中的一方法中调用 DAO 的多个方法,而这些方法应该在一个

    事务中.
// 事务需要保证为同一个 Connection
// 可以通过向 DAO 中传递 Connection, 来保证 DAO 的多个方法使用相同的 Connection public class XXXService(){
private XXXDao dao = new XXXDao();
public void serviceMethod(){ // 但是 Connection 对象只能出现在 DAO 中, 因为它是 JDBC 的东西,
// JDBC 的东西是用来连接数据库的, 连接数据库是由 DAO负责, 而事务却
// 应该由 Service 负责. Connection con = null;
try{
con = JdbcUtils.getConnection();
con.setAutoCommit(false); // 向 DAO 中传递 Connection
dao.daoMethod2(con,...);
dao.datMethod3(con,...);
con.commit();
}catch(Exception e){
try{
con.rollback();
} catch(Exception e){}
}finally{
try{
con.close();
}catch(Exception e){}
}
}
}

3. 修改 JdbcUtils

  1. 把对事物的开启和关闭放到 JdbcUtils 中,在 Service 中调用 JdbcUtils 的方法来完成事务的处理,

    但在 Service 中就不会再出现 Connection 了.
  2. DAO 中的方法不用再让 Service 来传递 Connection 了, DAO 会主动从 JdbcUtils 中获取 Connection

    对象, 这样, JdbcUtils 成为了 DAO 和 Service 的中介!

// Service 中的代码
public class XXXService(){
private XXXDao dao = new XXXDao();
public void serviceMethod(){
try{
JdbcUtils.beginTransaction();
dao.daoMethod2();
dao.daoMethod3();
JdbcUtils.commitTransaction();
}catch(Exception e){
JdbcUtils.rollbackTransaction();
}
}
} // JdbcUtils 代码 public class JdbcUtils{
private static ComboPooledDataSource dataSource = new ComboPooledDataSource(); // 它是事务专用连接, 并且每个线程分配一个Connection
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); public static Connection getConnection() throws SQLException{ Connection con = tl.get(); // 获取当前线程的 con // 当 con 不等于 null, 说明已经调用过 beginTransaction() 方法了.表示开启了事务.
if(con != null) return con;
return dataSource.getConnection();
} public static DataSource getDataSource(){
return dataSource();
} // 添加开启事务的方法
// 获取一个 Connection, 设置它的 setAutoCommit(false)
// 还要保证 DAO 中使用的连接是我们刚刚创建的!! /*
* 1. 创建一个 Connection, 设置为手动提交
* 2. 把这个 Connection 给 DAO 用!
* 3. 还要让 commitTransaction 或 rollbackTransaction 可以获取到!!
*/
public static void beginTransaction() throws SQLException { Connection con = tl.get(); if(con != null) throw new SQLException("已经开启了事务,就不要重复开启了!"); con = getConnection(); // 给 con 赋值, 表示事务已经开启了.
con.setAutoCommit(false); tl.set(con); // 把当前线程的连接保存起来.
} // 添加提交事务的方法
// 获取 beginTransaction 提供的 Connection, 然后调用 commit 方法
public static void commitTransaction() throws SQLException { Connection con = tl.get(); // 获取当前线程的专用连接 if(con == null) throw new SQLException("还没有开启事务,不能提交!"); con.commit();
con.close();
// 把它设置为 null, 表示事务已经结束了.
// 下次再去调用 getconnection(),返回的就不是 con 了.
// con = null; 因为有了线程, 所以将 con 直接从线程中移除即可 tl.remove(); // 从 tl 中移除连接
} // 添加回滚事务的方法
// 获取 beginTransaction 提供的 Connection, 然后调用 rollback 方法.
public static void rollbackTransaction() throws SQLException { Connection con = tl.get(); // 获取当前线程的专用连接 if(con == null) throw new SQLException("还没有开启事务,不能回滚!"); con.rollback();
con.close(); tl.remove();
} // 释放连接
public static void releaseConnection(Connection con) throws SQLException{ Connection con = tl.get(); // 获取线程中的事务 // 判断 connection 是不是事务专用, 如果是, 就不关闭
// 如果不是事务专用, 那么就要关闭
// con 是事务专用连接, 如果 con 为 null,表示没有事务.
// 那么, connection 肯定不是事务专用的.
if(con == null) connection.close(); // 如果 con != null, 说明有事务,那么需要判断参数连接是否与 con 相等,
// 如果不相等, 说明 connection 不是事务专用连接.
if(con != connection) connection.close(); }
} // DAO 层代码
public class AccountDao{
public void update(String name, double money) throws SQLException{
QueryRunner qr = new QueryRunner();
String sql = "UPDATE account SET balance=balance+? WHERE name=?";
Object[] params = {money,name}; // 我们需要自己来提供连接, 保证在同一事务中, 多次调用使用的是同一个连接!!
Connection con = JdbcUtils.getConnection();
qr.update(con,sql,params); // 关闭连接
JdbcUtils.releaseConnection(connection);
}
}

参考资料:

Service 事务(JdbcUtils 升级)的更多相关文章

  1. 对于在Dao层,一个DML操作一个事务,升级到Service层,一个用户,一个事务

    原先的连接Connection,只能是来一次,新创建一个连接connection.这样如果事务在Dao层已经默认提交,在service层出错时,对于俩张关联会有俩种不同的结果.为了解决这样的问题,我们 ...

  2. Android入门(十二)SQLite事务、升级数据库

    原文链接:http://www.orlion.ga/610/ 一.事务 SQLite支持事务,看一下Android如何使用事务:比如 Book表中的数据都已经很老了,现在准备全部废弃掉替换成新数据,可 ...

  3. 高并发秒杀系统--Service事务管理与继承测试

    [Spring IoC的类型及应用场景]  [Spring事务使用方式] [Spring事务的特性] [Spring事务回滚的理解] [Service声明式事务的配置] 1.配置事务管理器 2.配置基 ...

  4. windows service 2008 R2 升级 sp1遇到的问题

    因为我的程序是以vs2015开发的,所以在在布署windows service 2008 R2 项目的时候报出 红框里的错,说明要安装.net framework4.6. 感觉so easy,下载一个 ...

  5. spring service事务传播

    spring定义的事务行为有以下几种: REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行. ...

  6. windows service 2008 R2 安装net4.6环境失败,windows service 2008 R2 升级sp1问题

    一.错误 1.因为我的程序是以vs2017开发的,在windows service 2008 R2  IIS部署项目文件报出错误,因此要安装net4.6的环境. 2.windows service 2 ...

  7. sql service 事务与锁

    了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...

  8. ThreadLocal来管理事务

    ThreadLocal (扩展) 1 ThreadLocal API ThreadLocal类只有三个方法: l  void set(T value):保存值: l  T get():获取值: l  ...

  9. 超全面的JavaWeb笔记day19<Service>

    今日内容 l Service事务 l 客户关系管理系统 Service事务 在Service中使用ThreadLocal来完成事务,为将来学习Spring事务打基础! 1 DAO中的事务 在DAO中处 ...

随机推荐

  1. nginx和Tomcat集成后发生的重定向问题分析和解决

    nginx和Tomcat集成后发生的重定向问题分析和解决 Tomcat前端配置一个HTTP服务器应该是大部分应用的标配了,基本思路就是所有动态请求都反向代理给后端的Tomcat,HTTP服务器来处 理 ...

  2. iOS开发-Swift获取手机设备信息(UIDevice)

    使用UiDevice获取设备信息 获取设备名称 let name = UIDevice.currentDevice().name 获取设备系统名称 let systemName = UIDevice. ...

  3. oci学习

    http://www.cnblogs.com/ychellboy/archive/2010/04/16/1713884.html oci官方文档 Call Interface Programmer's ...

  4. js标准化价钱

    //标准化总价钱 s:总价钱,n:保留几位小数 function fmoney(s, n) { n = n > 0 && n <= 20 ? n : 2; s = pars ...

  5. rtp协议详解/rtcp协议详解

    转自:http://www.cnblogs.com/li0803/archive/2010/11/20/1882792.html 1.简介 目前,在IP网络中实现实时语音.视频通信和应用已经成为网络应 ...

  6. 轻松学习JavaScript十四:JavaScript的RegExp对象(正則表達式)

    一RegExp对象概述 RegExp对象表示正則表達式,RegExp是正則表達式的缩写.它是对字符串运行模式匹配的强大工具. RegExp 对象用于规定在文本中检索的内容. 当您检索某个文本时.能够使 ...

  7. poj 2828 Buy Tickets (线段树 单节点 查询位置更新)

    Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 15533   Accepted: 7759 Desc ...

  8. 基于Python3 + OpenCV3.3.1的远程监控程序

    基于Python3 + OpenCV3.3.1的远程监控程序 一.环境配置 OpenCV是一个基于(开源)发行的跨平台计算机视觉库,利用OpenCV能够实现视频图像的捕获. 关于python3中Ope ...

  9. Window安装Anaconda后,conda不是内部或者外部命令

    今天在安装Theano的时候,需要看一下,anaconda已经安装了哪些包.使用命令如下,在控制台,cmd回车输入即可: conda list 但是,显示出错,“conda不是内部或者外部命令”,第一 ...

  10. UI-2-UILabel&UIImageView-补充

    课程要点: 控件之间的继承关系. UILabel UIImageView 利用UIImageView实现帧动画 补充 试图之间的继承关系 昨天学习UIView的时候,了解到UIView里面有以下几个常 ...