(二十四)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数据分析-(10)SQL基础操作之表操作
大家好,我是jacky,很高兴跟大家继续分享MySQL数据分析实战课程,前面我们学习了库层面增删改查的SQL语句,这次课jacky将给大家介绍表层面的增删改查, (一)本课时的学习逻辑 表层面的增删改 ...
- c 判断数字是否无限
/* isinf example */ #include <stdio.h> /* printf */ #include <math.h> /* isinf, sqrt */ ...
- 如何确定哪个SMB客户端/会话在Server 2008R2 Windows文件服务器上打开了特定文件?
参考: http://www.kbase101.com/question/54969.html NetworkOpenedFiles v1.25 https://www.nirsoft.net/ut ...
- csp-s模拟90
T1: 每格的不透明度相当与一个边权,转化为从起点到终点所有路径的最大值.实现最长路,最好用$dijk$. T2: 对于$N=100$,$M=8$,考虑状压$dp$.要用一种状态表示某一行的矩形覆盖情 ...
- java 测试框架 TestNG
Java中print.printf.println的区别 printf主要是继承了C语言的printf的一些特性,可以进行格式化输出 print就是一般的标准输出,但是不换行 println和prin ...
- [maven]maven插件 tomcat7-maven-plugin 的使用
使用 tomcat7-maven-plugin,可以将tomcat内嵌到web项目中,直接运行webapp项目. 第一步.pom.xml的配置: <build> <plugins&g ...
- opencv C++ mask_rcnn
#include <fstream> #include <sstream> #include <iostream> #include <string.h> ...
- unittest-每个模块用例一条一条跑,模块都合在一个表格里面统计的方法
文件目录 文件里面的结构就是常规的 unittest框架的写法 总执行文件 # #coding=utf-8 import unittest, time, os, multiprocessingimpo ...
- 在谷歌中缓存下载视频离线观看,js代码
var download=function(urlInfo) { when(createFile(localFileName)) .then(function (fileInfo) { var dow ...
- HANA到MySQL数据同步方法!
随着各行各业信息化建设的不断发展,异构数据库间的互通.汇聚,挖掘,分析逐渐被提上日程, TreeSoft数据库管理系统,实现了异构数据库的维护.监控.可视化.自动交换同步.目前支持MySQL,Orac ...