(二十四)JDBC应用的事务管理(转账事例)
目录
利用 Dbutils
进行事务操作(以转账为例)
我们只在dao层进行增删改查操作。切忌在dao层直接进行转账的业务逻辑 ;
我们在services层开启一个连接,在连接上开启事务,然后在这个链接上进行多条sql操作 ;
·老方说,其实上面那样写,还是不优雅的;优雅的写法:spring事务管理或者使用 ThreadLocal 类 ;
(备注:经常听到spring的大名,很好奇spring到底是怎样的存在呢,现在还没学,很少好奇!)
转账实现方式(不优雅的方式)
dao层代码:
public class EmployeeDao1 {
public void setConnection(Connection connection) {
this.connection = connection;
}
private Connection connection;
public EmployeeDao1() {
}
public EmployeeDao1(Connection connection) {
this.connection = connection;
}
public void update(Employee e) throws SQLException {
// 不要将连接池作为参数,这里我们要用事务
QueryRunner runner = new QueryRunner();
String sql = "update employee set money = ? where name = ?";
Object[] params = {e.getMoney(), e.getName()};
runner.update(connection, sql, params);
}
public Employee find(int id) throws SQLException {
QueryRunner runner = new QueryRunner();
String sql = "select * from employee where id =?";
Employee employee = runner.query(connection,sql,new BeanHandler<Employee>(Employee.class),id);
return employee;
}
}
services层进行调用:
/**
* 转账的基础版本(不优雅的实现)
*
* @param sourceId 源账户的id
* @param targetId 目标账户的id
* @param money 转换的金额
*/
public void transaction1(int sourceId, int targetId, int money) throws SQLException {
Connection connection = null;
try {
// 获取连接
connection = JdbcDataSourceUtils.getConnection();
System.out.println(" --- "+connection);
// 开启事务
connection.setAutoCommit(false);
// 获取Dao层对象,将开启事务的连接 传递进去
EmployeeDao1 dao1 = EmployeeFactory.getDao1(connection);
// 查找用户
Employee s = dao1.find(sourceId);
Employee t = dao1.find(targetId);
// 转账逻辑 a减b增
s.setMoney(s.getMoney() - money);
t.setMoney(t.getMoney() + money);
// 进行转换
dao1.update(s);
dao1.update(t);
// 提交事务
connection.commit();
} finally {
connection.close();
}
}
我们可以看到,我们在调用dao层,需要传进去连接,还需要在连接上,开启事务,最后还有提交。每次进行类似的逻辑,都需要 重复 这样的逻辑代码。
ThreadLocal 类
其实内部就是一个Map集合 ;
·ThreadLocal 类在 J2EE 中很重要,它可以在线程内共享数据 ;以后在services、dao层之间传递数据,就不需要再利用方法参数传递了
利用方法参数,太死板了;我们就可以选择 ThreadLocal 类来完成了。用法:写一个工具类,内部维护着一个 ThreadLocl 对象;
不要说什么域,存数据,我就问下,dao层有request对象吗,能取到域中数据吗。。。
·许多框架使用了这个类 ;
·以后学框架,不但要学会用法,也要学习下源码,实现原理。。
·现在我们学的时事务,是一个services里面的多个dao操作的事务。
·以后还要学习多个services为一个事务,就需要用到过滤器了,可以保证一次请求以内的所有操作,都在一个事务里面。
转账实现方式(优雅的方式)
dao层代码:(很简短)
public class EmployeeDao2 {
public void update(Employee e) throws SQLException {
// 不要将连接池作为参数,这里我们要用事务
QueryRunner runner = new QueryRunner();
String sql = "update employee set money = ? where name = ?";
Object[] params = {e.getMoney(), e.getName()};
runner.update(JdbcDataSourceUtils.getConnection(), sql, params);
}
public Employee find(int id) throws SQLException {
QueryRunner runner = new QueryRunner();
String sql = "select * from employee where id =?";
Employee employee = runner.query(JdbcDataSourceUtils.getConnection(),sql,new BeanHandler<Employee>(Employee.class),id);
return employee;
}
}
services层代码:
/**
* 转账逻辑 优雅的实习方式
* @param sourceId 源客户id
* @param targetId 目标客户id
* @param money 转账金额
* @throws SQLException
*/
public void transaction2(int sourceId, int targetId, int money) throws SQLException {
try{
// 在线程上绑定已经开启事务的连接
JdbcDataSourceUtils.startTransaction();
// 获取dao层实例
EmployeeDao2 dao2 = EmployeeFactory.getDao2() ;
// 查找用户
Employee s = dao2.find(sourceId) ;
Employee t = dao2.find(targetId) ;
// 转账逻辑 a减b增
s.setMoney(s.getMoney() - money);
t.setMoney(t.getMoney() + money);
// 进行转换
dao2.update(s);
dao2.update(t);
// 提交事务
JdbcDataSourceUtils.commitTransaction();
}finally {
JdbcDataSourceUtils.closeConnetion();
}
}
其中涉及到的工具类代码:(ThreadLoacl类的使用)
/**
* 获取连接,如若线程上已经绑定连接,则返回线程上绑定的连接,否则则从连接池中获取一个连接返回
*
* @return 连接
*/
public static Connection getConnection() {
// 先判断线程上是否有Connection
Connection connection = tl.get();
if (null == connection) {
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
return connection;
}
/**
* 为当前线程绑定一个开启事务的连接
*/
public static void startTransaction() {
// 先判断线程上是否有Connection
// get 也是由执行这个方法的线程调用
Connection connection = tl.get();
if (null == connection) {
try {
connection = dataSource.getConnection();
tl.set(connection);
// 开启事务
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
/**
* 提交事务
*/
public static void commitTransaction() {
try {
Connection connection = tl.get();
if (connection != null) {
connection.commit();
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 关闭连接
*/
public static void closeConnetion() {
try {
Connection connection = tl.get();
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
// 哪一个线程调用这个方法,就按照线程为key去移除对应的Connection
tl.remove();
}
}
(二十四)JDBC应用的事务管理(转账事例)的更多相关文章
- 二十四 Redis消息订阅&事务&持久化
Redis数据类型: Redis控制5种数据类型:String,list,hash,set,sorted-set 添加数据,删除数据,获取数据,查看有多少个元素,判断元素是否存在 key通用操作 JR ...
- VMware vSphere 服务器虚拟化之二十四 桌面虚拟化之手动池管理物理机
VMware vSphere 服务器虚拟化之二十四 桌面虚拟化之手动池管理物理机 VMwareView手动池可以管理物理计算机 说明: 环境基于实验二十三 1.准备一台Windows 7的物理计算机名 ...
- [原]Jenkins(十四)---jenkins示例:admin管理所有项目,新建用户只能看部分项目
/** * lihaibo * 文章内容都是根据自己工作情况实践得出. *如有错误,请指正 * 版权声明:本博客欢迎转发,但请保留原作者信息! http://www.cnblogs.com/horiz ...
- (C/C++学习笔记) 二十四. 知识补充
二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...
- 第三百二十四节,web爬虫,scrapy模块介绍与使用
第三百二十四节,web爬虫,scrapy模块介绍与使用 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了 ...
- 创建JDBC模板简化代码、JDBC应用的事务管理以及连接池的作用
一.创建JDBC模板简化代码 一个简单的查询.要做这么一大堆事情,并且还要处理异常,我们不防来梳理一下: 1.获取connection 2.获取statement 3.获取resultset 4 ...
- FreeSql (二十四)Linq To Sql 语法使用介绍
原本不支持 IQueryable 主要出于使用习惯的考虑,如果继承 IQueryable,编写代码的智能总会提示出现一堆你不想使用的方法(对不起,我有强迫症),IQueryable 自身提供了一堆没法 ...
- 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用
目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...
- 设计模式学习(二十四):Spring 中使用到的设计模式
设计模式学习(二十四):Spring 中使用到的设计模式 作者:Grey 原文地址: 博客园:设计模式学习(二十四):Spring 中使用到的设计模式 CSDN:设计模式学习(二十四):Spring ...
- Bootstrap<基础二十四> 缩略图
Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstrap 通过缩略图为此提供了一种简便的方式.使用 Bootstrap 创建缩略图的步骤如下: 在图像周围添加带有 ...
随机推荐
- MySQL数据分析-(14)表补充:字符集
大家好,我是jacky朱元禄,很高兴继续跟大家学习<MySQL数据分析实战>,本节课程jacky分享的主题是表补充之字符集 在分享课程之前,jacky在跟大家强调一下逻辑的重要性,我们学习 ...
- Python学习日记(五)——初识函数(set、深浅拷贝、三目运算、函数、全局变量和局部变量)
基本数据类型补充 set set集合,是一个无序且不重复的元素集合 #创建 s = {11,22,33,44}#类似字典 s = set() #转换 l = (11,22,33,44) s1 = se ...
- 冲刺总结——Day7
[今日进展] 代码整合 码云链接:https://gitee.com/jxxydwt1999/20175215-java/tree/master/GoldPoint 功能测试 注册 登录 运行 [燃尽 ...
- Mybatis按照SQL查询字段的顺序返回查询结果,使用resultType="java.util.LinkedHashMap"
在使用Mybatis开发时,Mybatis返回的结果集就是个map,当返回map时只需要做好SQL映射就好了,减少了代码量,简单便捷,缺点是不太方便维护,但是写大量的vo类去返回也挺累的,这个看你个人 ...
- export default {} 和new Vue()区别?
export default 的用法:相当于提供一个接口给外界,让其他文件通过 import 来引入使用. 而对于 new Vue({})部分, 只是创建一个Vue的实例 就是相当于创建一个根组件 h ...
- [Scikit-learn] *2.3 Clustering - DBSCAN: Density-Based Spatial Clustering of Applications with Noise
http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html#sklearn.cluster.DBSCAN ...
- java+上传大文件
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 先说下要求: PC端全平台支持,要求支持Windows,Mac,Linux 支持所 ...
- JAVA 基础编程练习题21 【程序 21 求阶乘】
21 [程序 21 求阶乘] 题目:求 1+2!+3!+...+20!的和 程序分析:此程序只是把累加变成了累乘. package cskaoyan; public class cskaoyan21 ...
- MLN Alchemy
1. 前言: 本文主要参考Alchemy Tutorial, washington主页上挂出的所有Alchemy项目(包括Alchemy1.0, Alchemy2.0, AlchemyLite)都无法 ...
- Python3 Selenium自动化web测试 ==>FAQ:Unittest测试报告生成文件名加测试完成时间字符串
测试代码,虽然有点笨重,以后再修改: if __name__ == '__main__': report = os.path.join('D:/Python36/report/report.html' ...