在日常的项目开发中,我们知道有时候一些业务业务逻辑操作,必须在一块执行,要么全部执行成功,要么全部执行失败,这就要求我们在程序代码中对需要执行的sqlyu语句加上事务来执行、管理。
在dbutils工具中,对事务管理主要用到了ThreadLocal<T>这个容器(类似于容器),将开启事务的连接绑定到当前线程上去。
原理:将开启事务的链接保存到当前线程上,开启事务,在下面调用的Dao都是从当前线程获得的链接都是已经开启过事务的连接,最后在提交事务,关闭连接即可
实现代码如下:
1.JDBCUtil_c3p0.java
package com.nyist.dbutils.Utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;public class JDBCUtil_c3p0 {
private static ThreadLocal<Connection> t1 = new ThreadLocal<Connection>(); //定义一个ThreadLocal 来保存绑定再当前线程上的链接
private static ComboPooledDataSource cs = null;
static{
cs = new ComboPooledDataSource();
}
public static DataSource getDataSource(){
return cs;
}
public static Connection getConnection() throws SQLException{
try {
//得到当前线程上绑定的链接开启事务
Connection conn = t1.get();
if(conn==null){
conn = cs.getConnection(); //从数据库连接池里得到一个链接
t1.set(conn); //将得到的连接绑定到当前线程上
}
return conn; //返回该连接
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//开启事务
public static void startTransaction(){
try {
//得到当前线程上绑定的链接开启事务
Connection conn = t1.get();
if(conn==null){
conn = getConnection();
t1.set(conn);
}
conn.setAutoCommit(false); //开启事务
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//提交事务
public static void commitTransaction(){
try{
Connection conn = t1.get(); //得到当前线程上绑定的连接
if(conn != null){ //如果得到的连接不为空
conn.commit(); //提交事务
}
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//关闭数据库连接 从map容器中删除掉关闭掉的连接
public static void closeConnection() throws SQLException{
try{
Connection conn = t1.get(); //得到当前线程上绑定的连接
if(conn != null){ //如果得到的连接不为空
conn.close(); //关闭事务
}
}finally{
t1.remove(); //**重点,千万要牢记** 解除当前线程上的绑定--从threadLocal中移除关闭的链接
//如果不将关闭的连接从ThreadLocal容器中移除,ThreadLocal容器越老越大,最终会将内存耗尽
}
}
}
2.BusinessService.java
package com.nyist.dbutils.service;
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.Test;
import com.nyist.dbutils.Utils.JDBCUtil_c3p0;
import com.nyist.dbutils.dao.AccountDao;
import com.nyist.dbutils.model.Account;public class BussinessSercice {
@Test
public void test1() throws SQLException{
transfer2(2, 1, 200);
}
public void transfer1(int sourceid,int targerid,double money) throws SQLException{
Connection conn = null;
try{
conn = JDBCUtil_c3p0.getConnection(); //拿到数据库链接
conn.setAutoCommit(false); //开启事务管理
AccountDao dao = new AccountDao(conn);
Account saccount =dao.find(sourceid);
Account taccount =dao.find(targerid);
saccount.setMoney(saccount.getMoney()-money);
taccount.setMoney(taccount.getMoney()+money);
dao.update(taccount);
dao.update(saccount);
conn.commit();
}finally{
if(conn != null)
conn.close();
}
}
//用上ThreadLoca2
public void transfer2(int sourceid,int targerid,double money) throws SQLException{
try{
//1.上来先开启事务
JDBCUtil_c3p0.startTransaction();
//2.调用Dao
AccountDao dao = new AccountDao();
Account saccount =dao.find(sourceid);
Account taccount =dao.find(targerid);
saccount.setMoney(saccount.getMoney()-money);
taccount.setMoney(taccount.getMoney()+money);
dao.update(taccount);
dao.update(saccount);
//3.提交事务
JDBCUtil_c3p0.commitTransaction();
}finally{
//4.关闭连接
JDBCUtil_c3p0.closeConnection();
}
}
}