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,一经查实,立即删除!

相关文章

c++ const限定符

const限定符 const对像一旦创建,其值就不能发生改变。const对象必须初始化 const int i get_size();//正确,运行时初始化。 const int j 1;//正确,编译时初始化。j 2;//错误,j是一个常量,试图对其赋值行为将发生错误…

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…

c++ 参数传递

参数传递: 形参(parameter)和实参(argument): int num (int a, int b); int num (int a, int b){return ab; }//在函数的声明或者定义里,由由0个或多个形参组成的列表。int main(){int n1,m1;co…

c++定义成员函数

1.定义和声明成员函数的方式和普通函数差不多。成员函数的声明必须在类的内部,他的定义则即可以在类的内部也可以在类的外部。非成员函数的定义和声明都在类的外部。 struct Sales_data{std::string isbn() const { return bookNo; }double avg_price() const;std:…

java拖动图片拼图_求教,我的这个拼图程序中的移动图片的改怎么做

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼public class button extends JPanel implements MouseListener, ActionListener {/****/private static final long serialVersionUID 1L;private JButton[] button;private ImageIcon[] puzzlep;private JButton kbbutton;priva…

c++函数返回值是一个引用

函数返回值是一个引用的情况: 1.值是如何被返回的: 返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。 如果函数返回引用,则该引用仅是它所引对象的一个别名。 2.不能返回局部对象的引用或指针:…

java视频压缩 lz4_一种视频序列帧的压缩方法、解压方法及装置与流程

技术特征:1.一种视频序列帧的压缩方法,其特征在于,包括:在视频帧数据压缩时,对解析到的第一帧视频帧数据使用lz4算法进行压缩并保存至视频文件中;对之后解析到的每一帧视频帧数据都与之前一帧视频帧数据进行…

c++ 构造函数

构造函数: 类通过一个或几个特殊的成员函数来控制其对象的初始化进程,这些函数叫构造函数。构造函数的任务是初始化类对象的数据成员。 构造函数名字和类名相同,构造函数没有返回类型。构造函数也有一个可能为空的参数列表和一个可能为空的…

js java post提交_如何从Express.js发送Post请求到另一个服务器(Java)?

小编典典您正在重复请求,并为发布请求重新分配变量。我已经更新了您的代码并与requestb.in一起对其进行了测试var express require(express);var querystring require(querystring);var http require(http);var app express();app.get(/, function (req, res) {…

c++ 访问控制与封装

访问控制与封装 文章目录访问说明符:友元:封装好处:class Sales_data{public://作为接口的一部分,构造函数和部分成员函数isbn,combine紧跟在public说明符之后。Sales_data() default;Sales_data(const std::string &…

c++ 命名空间的using声明

命名空间的using声明: 除了内置类型之外,c语言还定义了一个内容丰富的抽象数据类型库。 访问库中名字的一个简单方法就是通过using。 我们用到的库函数基本上都属于命名空间std,可以通过::(作用域操作符)从左侧作用…

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文件…

用java画海绵宝宝_java 方法的重载

方法的重载:一个类中允许出现一个以上的同名方法,必须保证同名方法的参数列表不同好处:方便阅读,优化程序设计重载规则:重载方法名相同,但每个重载方法都必须有一个独一无二的参数类型列表,方法…

Java 构造方法

Java构造方法: 通过构造方法,在对象最初被创建时就完成对其成员变量的初始化。 构造方法特点: 构造方法名称和类名相同。构造方法不返回任何数据,也不用void声明。在创建对象时,系统自动调用类的构造方法。构造方法…

ajax 链接java_如何使用ajax将下拉菜单链接到表

以下是实现您的功能的示例静态代码 . 您可以使用sql和php添加动态内容 .的index.phpCource 1Cource 2Cource 3Cource 4$("#courses").change(function(){var course $(this).val();$.post(data.php, {course: course}, function(response){// your drop down box is…

Java 作用域修饰符

Java作用域修饰符 在java语言中,可以使用访问修饰符来规定对类、变量、方法和构造方法的访问。 文章目录一、访问修饰符二、非访问修饰符一、访问修饰符 1.私有的访问修饰符private: 声明为私有访问类型的变量只能通过类中的公共方法被外部类访问。 …

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 创建对象

Java 创建对象 声明:Person p1; 声明一个对象,包括对象名称(p1)和对象类型(Person)。 实例化:p1 new Person(); 使用关键字new创建一个对象。 声明和实例化连起来可以写成:Person …