利用ThreadLocal建立高质量事务处理
ThreadLocal此类是一个以当前线程为key的map对象的构想。
当我们在web开发中,多个浏览器访问的时候,servlet为它们各开线程执行相应代码,而事务的执行依赖于特定的一个Connection对象当中。所以用到了ThreadLocal类来封装<Connection>来取和放。
业务逻辑中不出现 Connection对象,代码风格好
数据库表
create table account
( id int primary key,
name varchar(20),
float money(8,2)
)
domain中
package cn.itcast.domain; import java.io.Serializable; public class Account implements Serializable { private int id;
private String name;
private float money;
public Account() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMoney() {
return money;
}
public void setMoney(float money) {
this.money = money;
}
@Override
public String toString() {
return "Account [id=" + id + ", name=" + name + ", money=" + money
+ "]";
} }
utils中TransactionUtil.java
package cn.itcast.utils; import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; public class TransactionUtil {
private static ThreadLocal<Connection> t=new ThreadLocal<Connection>(); private static DataSource ds;
static{
try {
InputStream in = TransactionUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties props = new Properties();
props.load(in);
ds = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
} public static DataSource getDataSource(){
return ds;
} public static Connection getConnection()
{
Connection con=null;
try {
con = t.get();// 获取 value,为 Connection对象 用于事务的处理
if(con==null)
{
con=ds.getConnection();
t.set(con);
}
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
public static void startTransaction() throws SQLException //把异常抛出去 ,让后面调用 事务 获取异常然后rollback
{
Connection con=null;
try {
con = t.get(); //如果前面调用过getConnection(),则con!=null,以下相同
if(con==null)
{
t.set(ds.getConnection());
}
con.setAutoCommit(false); //开启事务
} catch (SQLException e) {
e.printStackTrace();
throw e;
}
}
public static void commitTransaction() throws SQLException
{
Connection con=null;
try {
con = t.get();
if(con==null)
{
t.set(ds.getConnection());
}
con.commit();
} catch (SQLException e) {
e.printStackTrace();
throw e;
}
}
public static void rollbackTransaction() throws SQLException
{
Connection con=null;
try {
con = t.get();
if(con==null)
{
t.set(ds.getConnection());
}
con.rollback();
} catch (SQLException e) {
e.printStackTrace();
throw e;
}
}
public static void release()
{
Connection con=null; try {
con = t.get();
if(con!=null)
{
con.close();
t.remove();
}
} catch (SQLException e) {
e.printStackTrace();
} } }
daoImpl中
package cn.itcast.dao.impl; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler; import cn.itcast.domain.Account;
import cn.itcast.utils.TransactionUtil; public class AccountDaoImpl {
private QueryRunner qr = new QueryRunner();
public void updateAccount(Account c)
{
try {
String sql="update account_table set money=? where name=?";
qr.update(TransactionUtil.getConnection(),sql,c.getMoney(),c.getName());
} catch (SQLException e) {
e.printStackTrace();
}
} public Account findAccount(String accountName)
{
try {
String sql="select * from account_table where name=?";
return qr.query(TransactionUtil.getConnection(),sql, new BeanHandler<Account>(Account.class),accountName);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
serviceImpl中
package cn.itcast.ServiceImpl; import java.sql.SQLException; import cn.itcast.dao.impl.AccountDaoImpl;
import cn.itcast.domain.Account;
import cn.itcast.utils.TransactionUtil; public class AccountServeImpl {
public AccountDaoImpl dao=new AccountDaoImpl();
public void transe(String name1,String name2,int money)
{
Account c1=dao.findAccount(name1);
Account c2=dao.findAccount(name2); c1.setMoney(c1.getMoney()-money);
c2.setMoney(c2.getMoney()+money); try {
TransactionUtil.startTransaction();
dao.updateAccount(c1);
int i=1/0; //发现异常
dao.updateAccount(c2);
} catch (Exception e) { //一定要用 捕获的异常来捕获
try {
TransactionUtil.rollbackTransaction();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
finally
{
try {
TransactionUtil.commitTransaction();
TransactionUtil.release();
} catch (SQLException e) {
e.printStackTrace();
}
} }
}
测试
@Test
public void test() {
AccountServeImpl service=new AccountServeImpl();
service.transe("chenlongfei", "wangfang", 100);
}
利用ThreadLocal建立高质量事务处理的更多相关文章
- 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本
建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...
- 编写高质量代码改善C#程序的157个建议——建议55:利用定制特性减少可序列化的字段
建议55:利用定制特性减少可序列化的字段 特性(attribute)可以声明式地为代码中的目标元素添加注释.运行时可以通过查询这些托管块中的元数据信息,达到改变目标元素运行时行为的目的.System. ...
- (转)用AGG实现高质量图形输出(二)
本文上接<用AGG实现高质量图形输出(一)>,分别介绍了AGG显示流程中的各个环节. 上次讲了AGG的显示原理并举了一个简单的例子,这一篇文章开始讲AGG工作流程里的每个环节.为了方便对照 ...
- Android数据加密概述及多种加密方式 聊天记录及账户加密 提供高质量的数据保护
Android数据加密概述及多种加密方式 聊天记录及账户加密 提供高质量的数据保护 数据加密又称password学,它是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文.而解密则是通过解密 ...
- 使用koa2+es6/7打造高质量Restful API
前言 如今nodejs变得越来越火热,采用nodejs实现前后端分离架构已被多数大公司所采用. 在过去,使用nodejs大家首先想到的是TJ大神写的express.js,而发展到如今,更轻量,性能更好 ...
- 编写高质量代码改善C#程序的157个建议——建议117:使用SSL确保通信中的数据安全
建议117:使用SSL确保通信中的数据安全 SSL(Secure Socket Layer)最初是由NetScape公司设计的,用于Web安全的网络协议.目前它已经广泛应用到各类网络传输通信中了.SS ...
- 编写高质量Python程序(四)库
本系列文章为<编写高质量代码--改善Python程序的91个建议>的精华汇总. 按需选择 sort() 或者 sorted() Python 中常用的排序函数有 sort() 和 sort ...
- 怎样编写高质量的java代码
代码质量概述 怎样辨别一个项目代码写得好还是坏?优秀的代码和腐化的代码区别在哪里?怎么让自己写的代码既漂亮又有生命力?接下来将对代码质量的问题进行一些粗略的介绍.也请有过代码质量相关经验的朋友 ...
- 如何写出高质量的技术博客 这边文章出自http://www.jianshu.com/p/ae9ab21a5730 觉得不错直接拿过来了 好东西要大家分享嘛
如何写出高质量的技术博客?答案是:如果你想,就一定能写出高质量的技术博客.看起来很唯心,但这就是事实.有足够愿力去做一件目标明确,有良好反馈系统的事情往往很简单.就是不停地训练,慢慢地,你自己 ...
随机推荐
- kali下更新软件时,总是报错,说下列签名无效 解决办法
解决办法就是重新获取下签名key wget -q -O - https://archive.kali.org/archive-key.asc | apt-key add
- Struts2 @ResultPath注释示例
在Struts 2中, @ResultPath 注解用于控制Struts2找到存储的结果或JSP页面.默认情况下,它会找到结果页在 “WEB-INF/content/” 文件夹. 不知道为什么在Str ...
- 计蒜之道 初赛 第三场 题解 Manacher o(n)求最长公共回文串 线段树
腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...
- 【JS】 JS毫秒值转化为正常格式 或者正常格式转化为毫秒值
1.毫秒值转化为正常时间格式 最简单的方法 new Date(后台传来的毫秒值).toLocaleDateString() 就是这个样子 2.毫秒值转化为自定义的时间格式 本页面重写一下 toLo ...
- KindEditor编辑器常用操作
创建编辑器: ar editor=KindEditor.create('#nr'); 设置编辑器内容: editor.html('编辑器内容'); 移除编辑器: editor.remove();
- C++UI框架
WTL都算不上什么Framework,就是利用泛型特性对Win API做了层封装,设计思路也没摆脱MFC的影响,实际上用泛型做UI Framework也只能算是一次行为艺术,这个思路下继续发展就会变得 ...
- client_thread.c server_thread.c
client_thread.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> ...
- Django的restful api三方包:djangorestframework
文档位置:https://www.django-rest-framework.org/ 代码位置:https://github.com/encode/django-rest-framework/tre ...
- Powerdesigner数据库建模--概念模型--ER图
目标: 本文主要介绍PowerDesigner中概念数据模型 CDM的基本概念. 一.概念数据模型概述 数据模型是现实世界中数据特征的抽象.数据模型应该满足三个方面的要求: 1)能够比较真实地模拟现实 ...
- hybrid app开发中用到的html5新特性localStorage、sessionStorage和websql database
近期在项目中进行hybrid app开发,项目中有大量的js代码执行在android设备上. 使用到了非常多HTML5的新特性,之前没有遇到过,不了解.这里记录下添加点前端的知识.混合式app开发中. ...