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. CentOS 6.9/7通过yum安装指定版本的PostgreSQL扩展PostGIS

    一.安装PostGIS扩展插件(24_10) // 安装EPEL源 # rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-rele ...

  2. android ORM 框架 search

    1. ORMLite 特性: 通过在类上添加注解设置类 强大抽象DAO类 QueryBuilder 可以灵活的构造简单和复杂的查询语句 支持MySQL, Postgres, Microsoft SQL ...

  3. 【java】【mysql】存储微信表情emoji表情

    java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for colum n 'name' at row 1 at com ...

  4. 第六篇 ANDROID窗口系统机制之显示机制

    第六篇 ANDROID窗口系统机制之显示机制 ANDROID的显示系统是整个框架中最复杂的系统之一,涉及包括窗口管理服务.VIEW视图系统.SurfaceFlinger本地服务.硬件加速等.窗口管理服 ...

  5. Xcode的插件的路径

    /Users/dllo/Library/Application\ Support/Developer

  6. Neo4j 使用cypher语言进行查询

    Neo4j是一个Java开发的图数据库,它将结构化数据存储在网络(从数学角度叫做图)上而不是表中.相对于关系数据库来说,图数据库善于处理大量复杂.互连接.低结构化的数据,这些数据变化迅速,需要频繁的查 ...

  7. jquery城市选择案例

    1.代码实例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  8. MySQL索引优化案例

    这里我们分成三种情况进行分析,分别是单表,两表,三表 1.单表 CREATE TABLE IF NOT EXISTS `article`( `id` ) NOT NULL PRIMARY KEY AU ...

  9. windows服务的安装和卸载方法

    安装 创建“安装.bat”文件,用记事本打开此文件,内容为 c:\windows\microsoft.net\framework\v4.0.30319\InstallUtil.exe E:\progr ...

  10. 第三章 线程安全的DateFormat工具类

    1.使用threadLocal包装DateFormat(太复杂,不推荐) 2.使用org.apache.commons.lang3.time.DateFormatUtils下的方法(推荐) DateF ...