使用ThreadLocal事务保证线程安全
1.首先先把jdbcUtils的获取连接方法和关闭方法改成由ThreadLocal控制,
2.然后再去dao层把BaseDao的关闭连接给去除,然后dao层的异常要往外抛,不然出错了也没办法rollback。
3.去最高层的要用到事务判断功能的地方使用try 提交 catch回滚功能。
这是jdbcUtils:
package cn.zsp.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
private static DataSource ds;
private static ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();
static{
try {
Properties pro=new Properties();
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
pro.load(is);
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection conn = threadLocal.get();
if (conn==null)
{
try {
conn=ds.getConnection();
threadLocal.set(conn);
conn.setAutoCommit(false);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return conn;
}
public static void commitAndClose(){
Connection conn = threadLocal.get();
if (conn!=null)
{
try {
conn.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//threadLocal用完一定要remove不然会出错 因为底层使用了线程池
threadLocal.remove();
}
public static void rollbackAndClose(){
Connection conn = threadLocal.get();
if (conn!=null)
{
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//threadLocal用完一定要remove不然会出错 因为底层使用了线程池
threadLocal.remove();
}
/*public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}*/
}
因为dao层用到了关闭连接,所以要在这里一起把dao层的关闭连接去掉
package cn.zsp.dao.impl;
import cn.zsp.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public abstract class BaseDao {
/*
这个地方主要是写一些基础的增删改操作让子类继承
*/
private QueryRunner runner=new QueryRunner();
/**
* 增删改通用方法
* @param sql
* @param args
* @return
*/
public int update(String sql,Object ...args)
{
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return runner.update(conn,sql,args);
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException();
}
}
/**
* 查询一个返回一个对象的方法,如果存在返回的不是null,不存在放回null
* @param type
* @param sql
* @param args
* @param <T>
* @return 如果存在返回的不是null,不存在放回null
*/
public <T>T queryForOne(Class<T> type,String sql,Object ...args){
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return runner.query(conn,sql,new BeanHandler<T>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException();
}
}
/**
* 返回多个查询对象,返回的是集合形式
* @param type
* @param sql
* @param args
* @param <T>
* @return
*/
public <T>List<T> queryForList(Class<T> type, String sql, Object ...args)
{
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return runner.query(conn,sql,new BeanListHandler<T>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException();
}
}
/**
* 返回一个单个的值
* @param sql
* @param args
* @return
*/
public Object queryForSingleValue(String sql,Object ...args){
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return runner.query(conn,sql,new ScalarHandler(),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException();
}
}
}
最后在使用到事务的地方使用try catch:
Integer userId = loginUser.getId();
String orderId = null;
try {
orderId = orderService.createOrder(cart, userId);
JdbcUtils.commitAndClose();//没有异常就提交
} catch (Exception e) {
JdbcUtils.rollbackAndClose();//有异常就回滚
}