java service 事物_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 的中介!

4d4654cb8073884b5d90b7475ea5bc6f.png

// 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 tl = new ThreadLocal();

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);

}

}

参考资料:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/560494.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 8.0 sinffer_jpcap 配置方法,问题解决,模拟sniffer程序。(附JAVA程序,jar,dll包等环境)...

一、 Eclipse环境下安装与配置Jpcap相关源程序、jpcap jar包,dll包,帮助文档。1、下载安装winpcap2、jpcap官方文件中lib包下,有两个文件,jpcap.dll和jpcap.jar。jpcap.dll-->JAVA安装路径/jre1.6.0_06/bin (JRE目录)jpcap.j…

mysql工作中遇到的问题_MySQL工作中遇到的问题记录

1:log_slave_updates:从库1搭建级联从库2,从库1需要开启log_slave_updates,修改/etc/my.cnf,增加一行log_slave_updates1,重启数据库。http://blog.itpub.net/12679300/viewspace-1319263/2:ERROR 1418 (HY…

java 基本格式

java基本格式: 所有的java程序必须放在一个类之中才可以执行。 主方法main是整个java程序的入口,所有程序都是从public static void main(String[] args)开始运行的。 类定义有两种形式: public class:文件名和类名一致。每一个*.java文件…

python xgboost实战_史上最详细的XGBoost实战

0. 环境介绍Python 版 本: 3.6.2操作系统  : Windows集成开发环境: PyCharm1. 安装Python环境安装Python首先,我们需要安装Python环境。本人选择的是64位版本的Python 3.6.2。去Python官网https://www.python.org/选择相应的版本…

java web导入tomcat_记一次在服务器上导入javaweb 项目的经历---tomcat服务器-Go语言中文社区...

1. 导入数据库远程linux服务器mysql数据库导入和导出.sql文件大部分情况本地开发环境为windows,部署的服务器为Linux,本地数据库导出.sql文件后需要远程导入服务器,具体如下。首先连接服务器,即服务器ip,协议&#xff…

java 2d绘图 stroke_Java标准教程:Java 2D绘图--第4章使用Text

Java标准教程:Java 2D绘图--第4章使用Text本节介绍文本API的用法,以及他们的渲染能力。至今为止,您已经有了基本的Java 2D文本API,同时知道如何设置字体和位置,以及绘制文本。本节扩展了这些知识,同时更深入…

java 定义和导入包

java定义和导入包: 为了更好地组织类,java提供了包机制。把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。同一个包中的类名不同,不同包中类名可以相同。同时调用两个不同包中相同类名的类时,应该加…

php李捷,【问题解答】蝶泳手外划的作用

一直以来总是弄不明白,蝶泳手外划的作用,以及正确的外划动作,请指教。”我:先上两个图,您自己分析一下:我:蝶泳的划手路线和打腿的幅度和力度是相匹配的,如果打腿幅度小频率快&#…

ltrim函数php,php ltrim函数怎么用?

php ltrim()函数用于删除字符串左边的空格或其他预定义字符,语法为“ltrim(string,charlist)”,参数string指定需要处理的字符串,参数charlist指定要从字符串中删除哪些字符;然后返回已修改的字符串。php ltrim函数作用&#xff1…

java strcpy,详解C语言中strcpy()函数与strncpy()函数的使用

C语言strcpy()函数:复制字符串头文件:#include 定义函数:char *strcpy(char *dest, const char *src);函数说明:strcpy()会将参数src 字符串拷贝至参数dest 所指的地址。返回值:返回参数dest 的字符串起始地址。附加说…

使用github+hexo搭建静态blog

解决了个人博客图片不显示问题。解决了打开页面产生404问题。学习了如何更换界面主题。学习了如何使用Git。 注:这篇文章仅仅是入个门,了解一下怎么使用githubhexo创个静态blog,具体blog细节比如个人介绍,评论插件,音…

java 安卓调试,Android Studio(二十一):调试你的应用

Android Studio包含了一个调试器,允许你调试运行在Android虚拟机或连接的Android设备的应用。通过Android Studio的调试器,你可以:1、 选择你调试设备的app2、 为你的代码设置断点3、 在运行时检测变量和表达式4、 截图和录像通过点击工具栏中…

mysql hammerdb,[料理佳餚] 用 HammerDB 來執行資料庫 TPC-C 效能量測

TPC-C 模擬的情境TPC-C 模擬的情境是一個大型的商品批發商,擁有若干個倉庫,每個倉庫擁有 100000 件商品庫存、負責為 10 個地區供貨,每個地區服務 3000 名客戶,每名客戶平均一筆訂單有 10 項商品,所有訂單中約 1% 在其…

axure 鼠标变成手,Axure教程|鼠标移入移出自动显示与隐藏三级菜单

前几天因工作需要做一个鼠标移入显示隐藏菜单,鼠标移出自动隐藏菜单,做的时候觉得没有什么问题,做完后预览就发现一个很严重的问题,就是鼠标移出一级菜单向二级菜单时二级菜单不显示,或者二级菜单显示三级菜单不显示。…

php websocket应用实例,php使用websocket示例详解

下面我画了一个图演示 client 和 server 之间建立 websocket 连接时握手部分,这个部分在 node 中可以十分轻松的完成,因为 node 提供的 net 模块已经对 socket 套接字做了封装处理,开发者使用的时候只需要考虑数据的交互而不用处理连接的建立…

java basic data type,java基本数据类型--Basic Datatypes

Variables are nothing but reserved memory locations to store values. This means that when you create a variable you reserve some space in the memory.---说的好有道理Based on the data type of a variable, the operating system allocates memory and decides what…

adminer.php下载,Adminer.php

Adminer.php就是原来的phpMinAdmin,这是用PHP编写的数据库管理工具,支持mysql、mariadb、postgresql、sqlite、MS SQL、Oracle等多种数据库,虽然是一个源码,但是可以使用用户们和密码直接连接到数据库的服务器,既可以对…

windows下如何在命令行里切换到任意目录

切换到C盘中的某个文件夹,比如AppData,可以执行命令cd AppData; 但如果想切换到D盘,输入cd d:是不行的; 如果我们要切换盘符的目录,正确的用法是在cd 和路径中间 增加一个“/d”,如cd /d d: 也可以不用cd指令&#x…

Java基础 系统注解 @Override @Deprecated @SuppressWarnings 使用的方法及原因

Java 系统注解 为什么用?: 好处:使用系统定义的注解,可以在编译时对程序进行检查。 注解用在包、类、字段、方法、局部变量、方法参数等的前面,对这些元素进行说明和注释。 Override Override用来修饰一个方法&am…

单片机实验:交通灯控制

实验要求 按照电路要求在Protues中设计电路图,或者使用开发板。编程实现如下功能: 用单片机端口作输出口,控制四个方向共12个发光二极管亮灭,模拟交通灯管理。功能描述如下:初始态为四个路口的红灯全亮之后&#xff0…