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. php中在局部作用域内访问全局变量

    php中,由于作用域的限制,导致变量的访问限制: 1.局部作用域内不能访问全局变量 2.全局作用域内不能访问局部变量 对于第一种情况,如下代码将不能正常运行: <?php //局部作用域(函数内 ...

  2. VB的第一个项目

     前言-----本人也是刚刚接触VB,企业的VB代码基本能看的懂,但是自己开发,只能呵呵.一般在刚学习一门新的语言时,很容易发生一些自己相当然的认识错误,so,记下并分享开发学习的过程,望指正.--- ...

  3. Python课程之字典

    字典(dict) 一.定义:字典类型在其他语言中又称为map,是一种映射类型,并且{key:value}无序,其关键字必须为不可变类型(如:元组/字符串),在同一个字典中关键字必须互不相同(若出现相同 ...

  4. Aurora学习笔记连载一:仿真平台搭建

    由于公司项目需要,需要学习Aurora协议,才有了这样的连载学习笔记,也算是对自己学习的一份记录吧. 对于Aurora是什么,大家自行百度. 当然,Kevin也在此先提醒大家,本套学习笔记不是你想学就 ...

  5. PILE读书笔记_基础知识

    程序的构成 Linux下二进制可执行程序的格式一般为ELF格式. 我们可以用readelf命令来读取二进制的信息. ELF文件的主要内容就是由各个section及symbol表组成的. 下面来分别介绍 ...

  6. opencv模块介绍

    opencv主要模块介绍: [calib3d]——其实就是就是Calibration(校准)加3D这两个词的组合缩写.这个模块主要是相机校准和三维重建相关的内容.基本的多视角几何算法,单个立体摄像头标 ...

  7. JS DOM -- 关于回车键盘事件执行事件

    一.需求制作一个模拟对话框, 二. 1.需要发送后,输入框清空 2.按enter键可发送 三.代码部分 <!DOCTYPE HTML> <html> <head> ...

  8. vue 事件处理器

    事件处理器 1.监听事件 可以用v-on指令监听DOM事件来触发一些js代码. 2.方法事件处理器 许多事件处理的逻辑都很复杂,所以直接把js代码写在v-on指令中是不可行的.因此v-on可以接受一个 ...

  9. PLSQL快捷键设置

    1.在PL/SQL Developer中编写sql语句时,如果无法自动提示字段那是一件痛苦的事情,工作效率又低,在此演示下如何在PL/SQL Developer工具中自动提示字段,让开发者省时又省心, ...

  10. ini_set() php.ini设置的功能

    ini_set()具有更改php.ini设置的功能.此函数接收两个参数:需要调整的配置变量名,以及变量的新值. [c-sharp] view plaincopyprint? <?php ini_ ...