在以前的项目中,也曾经使用过事务的机制,总结说来一共有三种(其实本质都是一样的,只是表现形式不同):
第一种:在数据库中直接写在存储过程中(这个最简单,这里不再说明,存在的问题是代码完全不能复用,那里使用要单独写sql语句)
第二种:采用分层的思想进行设计,在D层进行方法的封装(这个很像直接写在数据库中存在的问题和上面的也一样——复用问题)。
第三种:在D层只写细粒度的操作方法,在上一层或者其他层开启事务进行组装,这种方法往往涉及到Connection的传递问题,当然在我原来的博客中也有写放在静态变量中D层用的时候直接取得。当然这样做是没有考虑线程安全的问题的。如果进行传递也是一件很麻烦的事。
我们采用ThreadLocal维护Connection可以避免这种情况。
ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。
ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联,即在同一个线程,可以共享该资源。
采用ThreadLocal维护Connection实例
package com.hanyi.drp.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 采用ThreadLocal维护Connection
* @author hanyi
*
*/
public class ConnectionManage {
//用于保存connection
private static ThreadLocal<Connection> connectionHolder=new ThreadLocal<Connection>();
/**
* 获取连接
* @return
*/
public static Connection GetConnection()
{
Connection conn=connectionHolder.get();
if(conn==null)
{
try {
JdbcConfig jdbcConfig=XmlConfigReader.GetInstance().getJdbcConfig();
Class.forName(jdbcConfig.getDriverName());
conn=DriverManager.getConnection(jdbcConfig.getUrl(),jdbcConfig.getUserName(),jdbcConfig.getPassword());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectionHolder.set(conn);
}
return conn;
}
//关闭连接
public static void closeConnection() {
Connection conn = connectionHolder.get();
if (conn != null) {
try {
conn.close();
//从ThreadLocal中清除Connection
connectionHolder.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭Statement(用于执行静态 SQL 语句并返回它所生成结果的对象。)
public static void close(Statement pstmt) {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭结果集
public static void close(ResultSet rs ) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//开启事务
public static void beginTransaction(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false); //手动提交
}
}
}catch(SQLException e) {}
}
//提交事务
public static void commitTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.commit();
}
}
}catch(SQLException e) {}
}
//回滚事务
public static void rollbackTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.rollback();
}
}
}catch(SQLException e) {}
}
}
这样操作完全解决了一起的问题:1.细粒度代码的完全复用。2.保证了线程的安全。3.避免了参数的传来传去。