ThreadLocal此类是一个以当前线程为key的map对象的构想。
当我们在web开发中,多个浏览器访问的时候,servlet为它们各开线程执行相应代码,而事务的执行依赖于特定的一个Connection对象当中。所以用到了ThreadLocal类来封装<Connection>来取和放。
业务逻辑中不出现 Connection对象,代码风格好
数据库表
1 create table account
2 ( id int primary key,
3 name varchar(20),
4 float money(8,2)
5 )
domain中
1 package cn.itcast.domain;
2
3 import java.io.Serializable;
4
5 public class Account implements Serializable {
6
7 private int id;
8 private String name;
9 private float money;
10 public Account() {
11 }
12 public int getId() {
13 return id;
14 }
15 public void setId(int id) {
16 this.id = id;
17 }
18 public String getName() {
19 return name;
20 }
21 public void setName(String name) {
22 this.name = name;
23 }
24 public float getMoney() {
25 return money;
26 }
27 public void setMoney(float money) {
28 this.money = money;
29 }
30 @Override
31 public String toString() {
32 return "Account [id=" + id + ", name=" + name + ", money=" + money
33 + "]";
34 }
35
36 }
utils中TransactionUtil.java
1 package cn.itcast.utils;
2
3 import java.io.InputStream;
4 import java.sql.Connection;
5 import java.sql.SQLException;
6 import java.util.Properties;
7
8 import javax.sql.DataSource;
9
10 import org.apache.commons.dbcp.BasicDataSourceFactory;
11
12 public class TransactionUtil {
13 private static ThreadLocal<Connection> t=new ThreadLocal<Connection>();
14
15 private static DataSource ds;
16 static{
17 try {
18 InputStream in = TransactionUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
19 Properties props = new Properties();
20 props.load(in);
21 ds = BasicDataSourceFactory.createDataSource(props);
22 } catch (Exception e) {
23 e.printStackTrace();
24 }
25 }
26
27 public static DataSource getDataSource(){
28 return ds;
29 }
30
31 public static Connection getConnection()
32 {
33 Connection con=null;
34 try {
35 con = t.get();// 获取 value,为 Connection对象 用于事务的处理
36 if(con==null)
37 {
38 con=ds.getConnection();
39 t.set(con);
40 }
41 } catch (SQLException e) {
42 e.printStackTrace();
43 }
44 return con;
45 }
46 public static void startTransaction() throws SQLException //把异常抛出去 ,让后面调用 事务 获取异常然后rollback
47 {
48 Connection con=null;
49 try {
50 con = t.get(); //如果前面调用过getConnection(),则con!=null,以下相同
51 if(con==null)
52 {
53 t.set(ds.getConnection());
54 }
55 con.setAutoCommit(false); //开启事务
56 } catch (SQLException e) {
57 e.printStackTrace();
58 throw e;
59 }
60 }
61 public static void commitTransaction() throws SQLException
62 {
63 Connection con=null;
64 try {
65 con = t.get();
66 if(con==null)
67 {
68 t.set(ds.getConnection());
69 }
70 con.commit();
71 } catch (SQLException e) {
72 e.printStackTrace();
73 throw e;
74 }
75 }
76 public static void rollbackTransaction() throws SQLException
77 {
78 Connection con=null;
79 try {
80 con = t.get();
81 if(con==null)
82 {
83 t.set(ds.getConnection());
84 }
85 con.rollback();
86 } catch (SQLException e) {
87 e.printStackTrace();
88 throw e;
89 }
90 }
91 public static void release()
92 {
93 Connection con=null;
94
95 try {
96 con = t.get();
97 if(con!=null)
98 {
99 con.close();
100 t.remove();
101 }
102 } catch (SQLException e) {
103 e.printStackTrace();
104 }
105
106 }
107
108 }
daoImpl中
1 package cn.itcast.dao.impl;
2
3 import java.sql.SQLException;
4
5 import org.apache.commons.dbutils.QueryRunner;
6 import org.apache.commons.dbutils.handlers.BeanHandler;
7
8 import cn.itcast.domain.Account;
9 import cn.itcast.utils.TransactionUtil;
10
11 public class AccountDaoImpl {
12 private QueryRunner qr = new QueryRunner();
13 public void updateAccount(Account c)
14 {
15 try {
16 String sql="update account_table set money=? where name=?";
17 qr.update(TransactionUtil.getConnection(),sql,c.getMoney(),c.getName());
18 } catch (SQLException e) {
19 e.printStackTrace();
20 }
21 }
22
23 public Account findAccount(String accountName)
24 {
25 try {
26 String sql="select * from account_table where name=?";
27 return qr.query(TransactionUtil.getConnection(),sql, new BeanHandler<Account>(Account.class),accountName);
28 } catch (SQLException e) {
29 e.printStackTrace();
30 }
31 return null;
32 }
33 }
serviceImpl中
1 package cn.itcast.ServiceImpl;
2
3 import java.sql.SQLException;
4
5 import cn.itcast.dao.impl.AccountDaoImpl;
6 import cn.itcast.domain.Account;
7 import cn.itcast.utils.TransactionUtil;
8
9 public class AccountServeImpl {
10 public AccountDaoImpl dao=new AccountDaoImpl();
11 public void transe(String name1,String name2,int money)
12 {
13 Account c1=dao.findAccount(name1);
14 Account c2=dao.findAccount(name2);
15
16
17 c1.setMoney(c1.getMoney()-money);
18 c2.setMoney(c2.getMoney()+money);
19
20 try {
21 TransactionUtil.startTransaction();
22 dao.updateAccount(c1);
23 int i=1/0; //发现异常
24 dao.updateAccount(c2);
25 } catch (Exception e) { //一定要用 捕获的异常来捕获
26 try {
27 TransactionUtil.rollbackTransaction();
28 } catch (SQLException e1) {
29 e1.printStackTrace();
30 }
31 e.printStackTrace();
32 }
33 finally
34 {
35 try {
36 TransactionUtil.commitTransaction();
37 TransactionUtil.release();
38 } catch (SQLException e) {
39 e.printStackTrace();
40 }
41 }
42
43 }
44 }
测试
1 @Test
2 public void test() {
3 AccountServeImpl service=new AccountServeImpl();
4 service.transe("chenlongfei", "wangfang", 100);
5 }
利用ThreadLocal建立高质量事务处理
时间: 2024-09-28 07:35:27