Service 事务(JdbcUtils 升级)
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
- 把对事物的开启和关闭放到 JdbcUtils 中,在 Service 中调用 JdbcUtils 的方法来完成事务的处理,
但在 Service 中就不会再出现 Connection 了. - 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 升级)的更多相关文章
- 对于在Dao层,一个DML操作一个事务,升级到Service层,一个用户,一个事务
原先的连接Connection,只能是来一次,新创建一个连接connection.这样如果事务在Dao层已经默认提交,在service层出错时,对于俩张关联会有俩种不同的结果.为了解决这样的问题,我们 ...
- Android入门(十二)SQLite事务、升级数据库
原文链接:http://www.orlion.ga/610/ 一.事务 SQLite支持事务,看一下Android如何使用事务:比如 Book表中的数据都已经很老了,现在准备全部废弃掉替换成新数据,可 ...
- 高并发秒杀系统--Service事务管理与继承测试
[Spring IoC的类型及应用场景] [Spring事务使用方式] [Spring事务的特性] [Spring事务回滚的理解] [Service声明式事务的配置] 1.配置事务管理器 2.配置基 ...
- windows service 2008 R2 升级 sp1遇到的问题
因为我的程序是以vs2015开发的,所以在在布署windows service 2008 R2 项目的时候报出 红框里的错,说明要安装.net framework4.6. 感觉so easy,下载一个 ...
- spring service事务传播
spring定义的事务行为有以下几种: REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行. ...
- windows service 2008 R2 安装net4.6环境失败,windows service 2008 R2 升级sp1问题
一.错误 1.因为我的程序是以vs2017开发的,在windows service 2008 R2 IIS部署项目文件报出错误,因此要安装net4.6的环境. 2.windows service 2 ...
- sql service 事务与锁
了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...
- ThreadLocal来管理事务
ThreadLocal (扩展) 1 ThreadLocal API ThreadLocal类只有三个方法: l void set(T value):保存值: l T get():获取值: l ...
- 超全面的JavaWeb笔记day19<Service>
今日内容 l Service事务 l 客户关系管理系统 Service事务 在Service中使用ThreadLocal来完成事务,为将来学习Spring事务打基础! 1 DAO中的事务 在DAO中处 ...
随机推荐
- php中在局部作用域内访问全局变量
php中,由于作用域的限制,导致变量的访问限制: 1.局部作用域内不能访问全局变量 2.全局作用域内不能访问局部变量 对于第一种情况,如下代码将不能正常运行: <?php //局部作用域(函数内 ...
- VB的第一个项目
前言-----本人也是刚刚接触VB,企业的VB代码基本能看的懂,但是自己开发,只能呵呵.一般在刚学习一门新的语言时,很容易发生一些自己相当然的认识错误,so,记下并分享开发学习的过程,望指正.--- ...
- Python课程之字典
字典(dict) 一.定义:字典类型在其他语言中又称为map,是一种映射类型,并且{key:value}无序,其关键字必须为不可变类型(如:元组/字符串),在同一个字典中关键字必须互不相同(若出现相同 ...
- Aurora学习笔记连载一:仿真平台搭建
由于公司项目需要,需要学习Aurora协议,才有了这样的连载学习笔记,也算是对自己学习的一份记录吧. 对于Aurora是什么,大家自行百度. 当然,Kevin也在此先提醒大家,本套学习笔记不是你想学就 ...
- PILE读书笔记_基础知识
程序的构成 Linux下二进制可执行程序的格式一般为ELF格式. 我们可以用readelf命令来读取二进制的信息. ELF文件的主要内容就是由各个section及symbol表组成的. 下面来分别介绍 ...
- opencv模块介绍
opencv主要模块介绍: [calib3d]——其实就是就是Calibration(校准)加3D这两个词的组合缩写.这个模块主要是相机校准和三维重建相关的内容.基本的多视角几何算法,单个立体摄像头标 ...
- JS DOM -- 关于回车键盘事件执行事件
一.需求制作一个模拟对话框, 二. 1.需要发送后,输入框清空 2.按enter键可发送 三.代码部分 <!DOCTYPE HTML> <html> <head> ...
- vue 事件处理器
事件处理器 1.监听事件 可以用v-on指令监听DOM事件来触发一些js代码. 2.方法事件处理器 许多事件处理的逻辑都很复杂,所以直接把js代码写在v-on指令中是不可行的.因此v-on可以接受一个 ...
- PLSQL快捷键设置
1.在PL/SQL Developer中编写sql语句时,如果无法自动提示字段那是一件痛苦的事情,工作效率又低,在此演示下如何在PL/SQL Developer工具中自动提示字段,让开发者省时又省心, ...
- ini_set() php.ini设置的功能
ini_set()具有更改php.ini设置的功能.此函数接收两个参数:需要调整的配置变量名,以及变量的新值. [c-sharp] view plaincopyprint? <?php ini_ ...