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

背景

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

基本介绍

“本地线程变量”,可以理解为将变量放到ThreadLocal中,同一个线程中共享,多线程之间资源隔离,不相互干扰,保证了线程安全。

可将ThreadLocal<T>看作是一个Map类型,可以理解为以存取键值对的方式进行存和取,但需要明确一点的是确定了一个ThreadLocal后,其中就只能存取一个键值对,因此其读和取方法也比较简单了:

get、set方法--为读取、设置线程变量中的值;

remove方法  --移除此线程局部变量当前线程的值;

initialValue--返回此线程局部变量的当前线程初始值。

封装Connection

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 采用ThreadLocal封装Connection
 *
 * @author Administrator
 *
 */
public class ConnectionManager {

	//定义ThreadLocal静态变量,确定存取类型为Connection
	private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();

	/**
	 * 得到Connection
	 * @return
	 */
	public static Connection getConnection() {
		Connection conn = connectionHolder.get();
		//如果在当前线程中没有绑定相应的Connection
		if (conn == null) {
			try {
				Class.forName("oracle.jdbc.driver.OracleDriver");
				String url = "jdbc:oracle:thin:@localhost:1521:bjpowern";
				String username = "drp1";
				String password = "drp1";
				conn = DriverManager.getConnection(url, username, password);
				//将Connection设置到ThreadLocal
				connectionHolder.set(conn);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return conn;
	}

	/**
	 * 关闭数据库连接方法
	 * @return
	 */
	public static void closeConnection() {
		Connection conn = connectionHolder.get();
		if (conn != null) {
			try {
				conn.close();
				//从ThreadLocal中清除Connection
				connectionHolder.remove();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 关闭数据库连接方法
	 * @return
	 */
	public static void close(Connection conn) {
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	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();
			}
		}
	}

	/**
	 * 事务开启
	 * @return
	 */
	public static void beginTransaction(Connection conn) {
		try {
			if (conn != null) {
				if (conn.getAutoCommit()) {
					conn.setAutoCommit(false); //手动提交
				}
			}
		}catch(SQLException e) {}
	}

	/**
	 * 事务提交
	 * @return
	 */
	public static void commitTransaction(Connection conn) {
		try {
			if (conn != null) {
				if (!conn.getAutoCommit()) {
					conn.commit();
				}
			}
		}catch(SQLException e) {}
	}

	/**
	 * 事务回滚
	 * @return
	 */
	public static void rollbackTransaction(Connection conn) {
		try {
			if (conn != null) {
				if (!conn.getAutoCommit()) {
					conn.rollback();
				}
			}
		}catch(SQLException e) {}
	}
}

经过了以上的封装,ConnectionManager类控制了线程内Connection的创建与获取,就达到了Dao层方法不需要传递Connection参数便可实现业务逻辑层控制事务的效果,ThreadLocal还可以在其他很多情况下应用,在后面的使用中再进行说明。

总结

多线程是解决高并发时常用的技术,明确线程之间的资源共享,合理分配并控制好资源之间的协调,便可以用好多线程,也是应用多线程的前提,在这方面还很欠缺,多多积累学习!

时间: 2024-12-18 02:56:55

【Java技术点滴】——ThreadLocal封装JDBC事务操作的相关文章

封装JDBC事务操作,执行存储过程测试

Oracle数据库端测试环境见:http://www.cnblogs.com/yshyee/p/4392328.html package com.mw.utils; import java.sql.Connection; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; /** * @author y * @date 2015-4-4 13:33:02 *

【Java技术点滴】——代理模式及其对事务封装

背景 项目中我们会遇到这样的情况:在几个方法中加入相同的代码,这些代码是与业务无关的,并且以后有可能由于考虑不周或需求变动再或者是其他原因,我们需要对他们进行逐一进行改动.举个具体的例子,比如程序中的日志控制.事务控制等,这些功能是与业务无关的,但却需要将它们与我们的逻辑混在一起,达到一些特殊的需求. 这样的情况往往代码都是相同的,可以抽离出来,为了复用,我们可以将这些相同的代码单独封装成的方法,以供其他需要的地方调用,这样对于以后的修改就做到了只修改一处的效果,达到了程序的复用,但另外一个问题

spring jdbc查询 依赖JdbcTemplate这个类模版封装JDBC的操作

1 package cn.itcast.spring.jdbc; 2 3 import java.util.List; 4 5 import org.springframework.jdbc.core.support.JdbcDaoSupport; 6 7 public class PersonDao extends JdbcDaoSupport{ 8 public void update(){ 9 this.getJdbcTemplate().execute("update person se

【Java技术点滴】——XML解析方式比较

为什么? "它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言.它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据.是Internet环境中跨平台的.依赖于内容的技术,也是当今处理分布式结构信息的有效工具."XML被设计用来传输和存储数据: 他的平台无关性.语言无关性.系统无关性,给数据继承与交互带来了极大的方便.也因此使用XML的地方越来越常见. 方式 1.DOM--DocumentObject Model 像操作HTML

【Java技术点滴】——Filter基本使用与扩展

背景 在程序实现的过程中我们往往碰到类似于这样的问题:为了防止后台接收数据不能乱码,我们需要在处理的Servlet中设置请求字符集,就会在每一个Servlet中加上这样的代码: request.setCharacterEncoding("GB18030"); 这样的代码就是在程序中写死了的,设置字符集的功能是不利于维护的,如果将来要修改为另外一种字符集类型,需要在每个Servlet中进行修改.如果要进行封装,同样面临每个Servlet都要调用的问题,而往往这种方法调用是与具体业务需求关

【Java技术点滴】——JSTL教程之分层思想

是什么? JSTL(JSP Standard TagLibrary,JSP标准标签库)是一个不断完善的开放源代码的JSP标准标签库,是Sun的一个标准,由apache的jakarta小组来实现.维护的. 为什么? 使用JSTL的最大的目的是帮助简化JSP页面作者(这个职位称为pageauthor)的日常工作.page author是指负责使用JSP实现Web应用程序表示层的人员.许多page author是不擅长使用任何编程语言的. page author面临着使用一种脚本语言(也因此他们被看成

【Java技术点滴】——精简实现图片处理

 引言: 对于图片的处理是很多项目中都会用到的,如一般的人事管理系统等,处理方式主要分为两大类: 1.图片文件存储与磁盘中,数据库中只保存相对应的文件名: 2.文件采用二进制的形式保存于数据库中. 第二种方案占用空间大,并且对二进制流的操作也较为占用资源,因此采用第一种方案进行处理的情况较为常见,常用于一般的系统应用中,正在进行中的drp项目中用到了图片上传.显示的功能处理,采用commons-fileupload1.1.1版本,可以实现多文件的上传功能. 实现: 引入相关jar包后,对方法

网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别

1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2次. >强烈依赖数据库的驱动jar 解决办法: Class.forName("com.mysql.jdbc.Driver"); 1.1.2 API详解:java.sql.Statement接口: 操作sql语句,并返回相应结果 String sql = "某SQL语句&qu

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

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