采用ThreadLocal维护Connection

在以前的项目中,也曾经使用过事务的机制,总结说来一共有三种(其实本质都是一样的,只是表现形式不同):

第一种:在数据库中直接写在存储过程中(这个最简单,这里不再说明,存在的问题是代码完全不能复用,那里使用要单独写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-08-07 08:30:58

采用ThreadLocal维护Connection的相关文章

【java项目实战】ThreadLocal封装Connection,实现同一线程共享资源

线程安全一直是程序员们关注的焦点.多线程也一直是比較让人头疼的话题,想必大家以前也遇到过各种各种的问题.我就不再累述了.当然,解决方案也有非常多,这篇博文给大家提供一种非常好的解决线程安全问题的思路. 首先.我们先简单的认识一下ThreadLocal,之后是实例+解析,最后一句话总结. 1.认识一下ThreaLocal 认识ThreadLocal必需要通过api文档,不只具有说服力,并且它会给你更加全面的解释.以下我我给大家从api文档上截取一张图,并标出来了七点需要重点理解的内容,实例过后的解

Java代码质量改进之:使用ThreadLocal维护线程内部变量

在上文中,<Java代码质量改进之:同步对象的选择>,我们提出了一个场景:火车站有3个售票窗口,同时在售一趟列车的100个座位.我们通过锁定一个靠谱的同步对象,完成了上面的功能. 现在,让我们反过来,每个窗口负责一趟车.比如一号窗口就卖1号列车的票,二号窗口就卖2号列车的票.不过它们需要同时开始卖票. 一:ThreadLocal的最简应用 首先,既然是各卖各的火车了,那么,就不需要同步了.于是代码又回归到: 但是当前的代码肯定是不对的,每个线程访问的都是同一个火车的ticket,并且还会出现超

采用动态代理对事务进行封装

在上篇博客中介绍了使用ThreadLocal维护Connection的方法,这样做的最大的好处就是不用来回的传递Connection了,但是我们有会发现在我们使用事务的时候不可避免的会写许多重复的代码,这些都是与业务逻辑无关的: Connection conn = ConnectionManage.GetConnection(); ConnectionManage.beginTransaction(conn); ConnectionManage.commitTransaction(conn);/

【Java技术点滴】——ThreadLocal封装JDBC事务操作

背景 在Java程序实现中,我们往往应用到事务的机制,在业务层进行事务开启,创建数据库连接,调用Dao层方法进行数据库访问,过程中需要将数据库连接Connection作为参数传递给Dao层方法.显而易见,这样的实现不利于Dao层方法的复用,当在不使用事务的情况下,我们是需要在Dao层方法中创建数据库连接的,这样Dao层方法免去Connection参数就可以使得方法更加独立.明确了,怎样解决这样的尴尬?对于此,我们使用了ThreadLocal进行解决. 基本介绍 "本地线程变量",可以理

【Java】JDBC数据库连接

[是什么] JDBC全称JAVADataBaseConnectivity,即Java数据库连接,它是一种可执行SQL语句的Java API.程序员可以通过JDBCAPI连接到关系数据库,并使用结构化查询语句(即SQL)完成对数据库的查询.更新. [作用] 简单地说,JDBC可做三件事:与数据库建立连接.发送 操作数据库的语句并处理结果.下列代码段给出了以上三步的基本示例(太经典了就直接从百科中截取啦): 1.数据库建立连接: Connection con = DriverManager.getC

理解Java ThreadLocal

ThreadLocal是什么 早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序. ThreadLocal很容易让人望文生义,想当然地认为是一个"本地线程".其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些. 当使用ThreadLocal维护变量

Java之ThreadLocal原理分析

简介 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序.当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思.所以,在Java中编写线程局部变量

ThreadLocal简介

ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序. 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本. 从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思. 所以

ThreadLocal类的实现用法

ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名为ThreadLocalVar更加合适.线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突. 从线程的角度看,每个线程都保持一个对其线程局部变量副本