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建立高质量事务处理的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  2. 编写高质量代码改善C#程序的157个建议——建议55:利用定制特性减少可序列化的字段

    建议55:利用定制特性减少可序列化的字段 特性(attribute)可以声明式地为代码中的目标元素添加注释.运行时可以通过查询这些托管块中的元数据信息,达到改变目标元素运行时行为的目的.System. ...

  3. (转)用AGG实现高质量图形输出(二)

    本文上接<用AGG实现高质量图形输出(一)>,分别介绍了AGG显示流程中的各个环节. 上次讲了AGG的显示原理并举了一个简单的例子,这一篇文章开始讲AGG工作流程里的每个环节.为了方便对照 ...

  4. Android数据加密概述及多种加密方式 聊天记录及账户加密 提供高质量的数据保护

    Android数据加密概述及多种加密方式 聊天记录及账户加密 提供高质量的数据保护 数据加密又称password学,它是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文.而解密则是通过解密 ...

  5. 使用koa2+es6/7打造高质量Restful API

    前言 如今nodejs变得越来越火热,采用nodejs实现前后端分离架构已被多数大公司所采用. 在过去,使用nodejs大家首先想到的是TJ大神写的express.js,而发展到如今,更轻量,性能更好 ...

  6. 编写高质量代码改善C#程序的157个建议——建议117:使用SSL确保通信中的数据安全

    建议117:使用SSL确保通信中的数据安全 SSL(Secure Socket Layer)最初是由NetScape公司设计的,用于Web安全的网络协议.目前它已经广泛应用到各类网络传输通信中了.SS ...

  7. 编写高质量Python程序(四)库

    本系列文章为<编写高质量代码--改善Python程序的91个建议>的精华汇总. 按需选择 sort() 或者 sorted() Python 中常用的排序函数有 sort() 和 sort ...

  8. 怎样编写高质量的java代码

    代码质量概述     怎样辨别一个项目代码写得好还是坏?优秀的代码和腐化的代码区别在哪里?怎么让自己写的代码既漂亮又有生命力?接下来将对代码质量的问题进行一些粗略的介绍.也请有过代码质量相关经验的朋友 ...

  9. 如何写出高质量的技术博客 这边文章出自http://www.jianshu.com/p/ae9ab21a5730 觉得不错直接拿过来了 好东西要大家分享嘛

        如何写出高质量的技术博客?答案是:如果你想,就一定能写出高质量的技术博客.看起来很唯心,但这就是事实.有足够愿力去做一件目标明确,有良好反馈系统的事情往往很简单.就是不停地训练,慢慢地,你自己 ...

随机推荐

  1. 几种OutOfMemoryError

    JAVA虚拟机OutOfMemoryError主要包括以下四类:java.lang.OutOfMemoryError: Java heap spacejava.lang.OutOfMemoryErro ...

  2. Testcase的编写

    ‘ID’用于记录某一功能: ‘标题’用于表示某一Case:(一个功能有多个Case) ‘优先级’标记Case的重要等级,运行顺序 ‘测试步骤’记录测试流程 1.Given:条件 2.And:进行某些前 ...

  3. 程序员应该知道的几个国外IT网站

    程序员应该知道的几个国外IT网站   摘要:文中总结了几个常用的国外IT网站,下面列举出来供大家学习参考: 导读:文中总结了几个常用的国外IT网站,下面列举出来供大家学习参考: 1. TheServe ...

  4. 给WebAPI的REST接口服务添加测试页面(一)

    当使用WebAPI提供REST服务的时候,一个经常进行的操作是对接口进行测试.Asp.net WebAPI框架本身并没有提供这一接口,不过由于提供的是标准的REST服务,是可以非常方便的使用一些第三方 ...

  5. PHP格式化金钱函数

    实现目的: 对数字进行格式化,以类似¥10,000,000的格式输出. 实现方法: function doFormatMoney($money){ $tmp_money = strrev($money ...

  6. NHibernate 3 Beginner's Guide

    前言 这一章是一个完整的NHibernate的Simple,原文中用Fluent NHibernate做映射,但我使用NHibernate3.2版本,所以3.2的Conformist代替Fluent ...

  7. Matlab Command Window 进度提示

    效果如下,

  8. 微信公众平台——获取access_token、expires_in

    微信公众平台——获取access_token.expires_in 在微信公众平台接口开发中,Access Token占据着重要地位,它相当于进入各种接口的邀请,拿到这个钥匙才拥有调用其他各种特殊接口 ...

  9. 淘宝API开发第一步

    1.登录淘宝开放平台:http://open.taobao.com/ 2.添加网站 (验证完网站后,会提醒“JSSDK以激活提交审核按钮”,这个需要的UV达100,按钮才会亮,审核过程中也得保持UV的 ...

  10. GoF设计模式三作者15年后再谈模式

    Erich Gamma, Richard Helm, 和 Ralph Johnson在GoF设计模式发表15年以后,再谈模式,另外一位作者,也是四色原型的发明者Peter已经过世. 提问者:如今有85 ...