需求
-
当单击提交按钮,付款方向收款方按照输入的金额转账。 使用事务进行控制
-
分析
1.ThreadLocal
在“事务传递参数版”中,我们必须修改方法的参数个数,传递连接对象,才可以完成整个事务操作。如果不传递参数,是否可以完成?在JDK中给我们提供了一个工具类:ThreadLocal,此类可以在一个线程中共享数据。
java.lang.ThreadLocal,该类提供了线程局部 (thread-local) 变量,用于在当前线程中共享数据。ThreadLocal工具类底层就是一个Map,key存放的当前线程,value存放需要共享的数据
-
//模拟ThreadLocal类
public class ThreadLocal{
private Map<Thread,Object> map = new HashMap<Thread,Object>();
public void set(Connection conn){
map.put(Thread.currentThread(),conn); //以当前线程对象作为key
}
public Object get(){
return map.get(Thread.currentThread()); //只有当前线程才能取出value数据
}
}
ThreadLocal:实现在当前线程下共享数据【范围小很多】
类似于ServletContext在当前应用下共享数据【范围大一些】
结论:向ThreadLocal对象中添加的数据只能在当前线程下使用。 -
思路
-
代码
package com.itheima.utils;
import java.sql.Connection;
public class ConnectionManager {
private static ThreadLocal<Connection> t = new ThreadLocal<>();
public static Connection getConnection() throws Exception {
//1.从ThreadLocal中获取connection对象
Connection connection = t.get();
//2.第一次获取的时候ThreadLocal中还没有存储connection对象 因此获取之后,将connection存入到ThreadLocal中,这样后面同一个线程就可以获取到了
if(connection==null){
connection = C3P0Utils.getConnection();
t.set(connection);
}
return connection;
}}
-
UserService
-
package com.itheima.service;
import com.itheima.dao.TransferDao;
import com.itheima.utils.C3P0Utils;
import com.itheima.utils.ConnectionManager;import java.sql.Connection;
import java.sql.SQLException;public class TransferService {
/**
* 转账业务
* @param from 付款方
* @param to 收款方
* @param money 转账金额
* @return 转账是否成功 true|false
*/
public boolean transfer(String from, String to, double money) throws Exception {/********1.手动开启事务*******/
Connection connection = ConnectionManager.getConnection();
connection.setAutoCommit(false);try {
//1.处理业务【判断付款方 收款方是否存在 转账金额是否合理 假设一切正常】
//2.调用dao
TransferDao transferDao = new TransferDao();
//2.1:付款方钱减少
int rows1 = transferDao.reduceMoney(from,money);//人为制作异常 用于测试
//int i = 1/0;//2.2:收款方钱增加
int rows2 = transferDao.addMoney(to,money);
//3.根据dao处理结果判断转账是否成功 并返回
if(rows1>0 && rows2>0){
//转账成功 提交事务
connection.commit();
return true;
}else{
//转账失败 回滚事务
connection.rollback();
return false;
}
} catch (Exception e) {
e.printStackTrace();
//发生异常 回滚事务
connection.rollback();
return false;
}}
} -
UserDao
-
package com.itheima.dao;
import com.itheima.utils.C3P0Utils;
import com.itheima.utils.ConnectionManager;
import org.apache.commons.dbutils.QueryRunner;import java.sql.Connection;
import java.sql.SQLException;public class TransferDao {
/**
* 付款方钱减少
* @param from
* @param money
* @return
*/
public int reduceMoney(String from, double money) throws Exception {
//1.操作数据库
//注意:多个操作使用同一个connection时,才能进行事务控制 所以此时创建QueryRunner对象时使用无参构造方法
QueryRunner queryRunner = new QueryRunner();
String sql = "update account set money = money-? where name=?";
return queryRunner.update(ConnectionManager.getConnection(),sql,money,from);
}/**
* 收款方钱增加
* @param to
* @param money
* @return
*/
public int addMoney(String to, double money) throws Exception {
//1.操作数据库
QueryRunner queryRunner = new QueryRunner();
String sql = "update account set money = money+? where name=?";
return queryRunner.update(ConnectionManager.getConnection(),sql,money,to);
}
}