在以前的项目中,也曾经使用过事务的机制,总结说来一共有三种(其实本质都是一样的,只是表现形式不同):
第一种:在数据库中直接写在存储过程中(这个最简单,这里不再说明,存在的问题是代码完全不能复用,那里使用要单独写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.避免了参数的传来传去。
时间: 2024-10-11 04:39:10