概述
我们的dao层只是和数据库打交道的中间件,不涉及我们的业务逻辑,一般一个事务代表一个业务边界,所以我们的事务应该定义在service层上,由于我们的service是单例的,如何保证我当前的操作是线程安全的(即是在同一个连接上做的操作)。解决方案是使用ThreadLocal,它是线程绑定的变量,提供线程局部变量(ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。),我们将连接绑定在当前的线程上。
public class JdbcUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(JdbcUtil.class);
private static ThreadLocal<Connection> currentConnection = new ThreadLocal<>();
private static DataSource dataSource;
static{
try {
var in = JdbcUtil.class.getClassLoader().getResourceAsStream("dbcp-config.properties");
var prop = new Properties();
prop.load(in);//数据源中已设置事务为手动提交
dataSource = BasicDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
LOGGER.error(e.getMessage(),e);
}
}
private JdbcUtil() {
}
/**
* 通过数据源获取连接对象
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
//从当前线程获取Connection对象
var conn = currentConnection.get();
if(conn == null){//如果连接为空,应该创建一个连接并且绑定到当前线程之上
conn = dataSource.getConnection();
//currentConnection.set(conn);
}
return conn;
}
/**
* 获取数据源
* @return 数据源
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 开启一个事务
*/
public static void beginTransaction(){
try {
var conn = currentConnection.get();
//如果连接不为空,表示当前事务没有结束(自动提交),不能开启新的事务
if(conn != null) {
throw new SQLException("事务已经开启,在没有结束当前事务时,不能再开启事务!");
}
conn = dataSource.getConnection();
//开启事务
conn.setAutoCommit(false);
currentConnection.set(conn);
} catch (SQLException e) {
LOGGER.error(e.getMessage(),e);
}
}
/**
* 提交一个事务
*/
public static void commit(){
try {
var conn = currentConnection.get();
if(conn == null) {
throw new SQLException("当前没有事务,不能提交事务!");
}
//提交事务
conn.commit();
conn.close();
currentConnection.remove();
} catch (SQLException e) {
LOGGER.error(e.getMessage(),e);
}
}
/**
* 回滚一个事务
*/
public static void rollback(){
try {
var conn = currentConnection.get();
if(conn == null) {
throw new SQLException("当前没有事务,不能回滚事务!");
}
//提交事务
conn.rollback();
conn.close();
currentConnection.remove();
} catch (SQLException e) {
LOGGER.error(e.getMessage(),e);
}
}
/**
* 释放资源
* 拿连接是从当前线程上的,释放应该将当前线程上的Connection对象移除掉
* @param rs 结果集
* @param stat 语句对象
* @param conn 连接对象
*/
public static void free(ResultSet rs, Statement stat,Connection conn){
try {
if(rs != null)
rs.close();
} catch (SQLException e) {
LOGGER.error(e.getMessage(),e);
}finally {
try {
if(stat != null)
stat.close();
} catch (SQLException e) {
LOGGER.error(e.getMessage(),e);
}finally {
try {
if(conn != null) {
currentConnection.remove();
conn.close();
}
} catch (SQLException e) {
LOGGER.error(e.getMessage(),e);
}
}
}
}
}
最后
以上就是含蓄酸奶为你收集整理的jdbc事务控制的全部内容,希望文章能够帮你解决jdbc事务控制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复