




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、一、什么是ThreadLocal早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而
2、不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。线程局部变量并不是Java的新发明,很多语言(如IBM IBM XL FORTRAN)在语法层面就提供线程局部变量。在Java中没有提供在语言级支持,而是变相地通过ThreadLocal的类提供支持。所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。ThreadLocal的接口方法ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:² void set(Objec
3、t value)设置当前线程的线程局部变量的值。² public Object get()该方法返回当前线程所对应的线程局部变量。² public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。² protected ObjectinitialValue()返回该线程局部变量的初始值,该
4、方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。一、来看一个实际案例2.1 同一Service方法中调用多个Dao方法可以看到,我们有一个Ser
5、vice方法,在该Service方法中调用多个Dao方法,所有在该Service方法中的的Dao都处于同一事务中。该Service方法结束后,提交事务;该Service方法中有任何错,回滚事务;2.2 传统的做法来看下面这段伪代码Service层代码:public void serviceMethod()Connection conn=null;tryConnection conn=getConnection();conn.setAutoCommit(false);Dao1 dao1=new Dao1(conn);dao1.doSomething();Dao2 dao2=new Da
6、o2(conn);dao2.doSomething();Dao3 dao3=new Dao3(conn);dao3.doSomething(); mit();catch(Exception e) try conn.rollback();catch(Exception ex)finallytryconn.setAutoCommit(true);catch(Exception e) try
7、0; if(conn!=null) conn.close(); conn=null;catch(Exception e)每个Dao层的代码:Class Dao1private Connection conn=null;public Dao1(Connection conn) this.conn=conn;public void doSomething() PreparedStatement pstmt=null;
8、160; try pstmt=conn.preparedStatement(sql); pstmt.execute catch(Exception e) log.error(e,”Exeception occurred in Dao1.doSomething():”+e.getMessage,e);finall
9、y try if(pstmt!=null) pstmt.close(); pstmt=null; catch(Exception e)如果我一个Service方法有调用一堆dao方
10、法,先不说这样写首先破坏了OOP的封装性原则,如果有一个dao多关了一个conn,那就会导致其它的dao得到的conn为null,这种事在这样的写法下由其当你还有业务逻辑混合在一起时很容易发生。笔者曾经遇见过2个项目,出现out of memory或者是connection pool has been leakage,经查代码就是在每个dao中多关或者在service层中漏关,或者是每个dao有自己的conntionconn=getConnection(),然后还跑到Service层里去关这个connection(那关什么,关个P关!)。当然,如果你说你在写法上绝对promise绝对注意这样的
11、问题不会发生,但是我们来看看下面的这种做法,是否会比上面这个写法更好呢? 2.3 Spring中的做法先来看Spring中的写法。大家应该都很熟悉Spring中的写法了,来看一下它是怎么解决的。Service层public void serviceMethod()try /aop 自动加入connection,并且将conn.setAutoCommit(false);dao1.doSomething();dao2.doSomething();dao3.doSomething();catch(Exception e)
12、; /aop 自动加入rollbackfinally /aop自动加入conn.setAutoCommit(true) /aop 自动加入conn.close(); 这边我们不讲AOP,因为用类反射结合xml很容易将aop 自动。这些东西加入我们的代码中去是不是?我们只管写dao方法,service方法,不需要关心在哪边commit哪边rollback何时connection,spring的声明式事务会帮我们负责,这种风格我们称为“优雅”,各层间耦合度极大程度上的降低,封装性好。因此,我们可以总结出下面这些好处:
13、² Service层的方法只管开启事务(如果讲究点的还会设一个Transaction);² 在该Service层中的所有dao使用该service方法中开启的事务(即connection);² Dao中每次只管getCurrentConnection(获取当前的connection),与进行数据处理² Dao层中如果发生错误就抛回Service层² Service层中接到exception,在catch中rollback,在try未尾commit,在finally块中关闭整个conne
14、ction。这。就是我们所说的ThreadLocal。举个更实际的例子再次来说明ThreadLocal:我们有3个用户访问同一个service方法,该service方法内有3个dao方法为一个完整事务,那么整个web容器内只因该有3个connection,并且每个connection之间的状态,彼此“隔离”。我们下面一起来看我们如何用代码实现类似于Spring的这种做法。首先,根据我们的ThreadLocal的概念,我们先声明一个ConnectionManager的类。2.4 利用ThreadLocal制作ConnectionManagerpublic class Connectio
15、nManager private static ThreadLocal tl = new ThreadLocal(); private static Connection conn = null; public static void BeginTrans(boolean beginTrans) throws
16、 Exception if (tl.get() = null | (Connection) tl.get().isClosed()
17、; conn = SingletonDBConnection.getInstance().getConnection(); conn = new ConnectionSpy(conn);
18、60; if (beginTrans)
19、0; conn.setAutoCommit(false);
20、 tl.set(conn);
21、60; public static Connection getConnection() throws Exception return (Connection) tl.get();
22、60; public static void close() throws SQLException try
23、60; (Connection) tl.get().setAutoCommit(true); catch (Exception e)
24、; (Connection) tl.get().close();
25、60; tl.set(null); public static void commit() throws SQLException try
26、 (Connection) tl.get().commit(); catch (Exception e) &
27、#160; try &
28、#160; (Connection) tl.get().setAutoCommit(true); catch (Exception e)
29、60; public static void rollback() throws SQLException
30、0; try (Connection) tl.get().rollback(); &
31、#160; catch (Exception e) try
32、0; (Connection) tl.get().setAutoCommit(true); catch (Excepti
33、on e) 2.5 利用ThreadLocal改造Service与Dao层Service层(注意红色标粗-好粗yeah,的地方)package .service.impl;public class StudentServiceImpl implements S
34、tudentService public void addStudent(Student std) throws Exception StudentDAO studentDAO = new StudentDAOImpl(); &
35、#160; ClassRoomDAO classRoomDAO = new ClassRoomDAOImpl(); try
36、0; ConnectionManager.BeginTrans(true);
37、0; studentDAO.addStudent(std); classRoomDAO &
38、#160; .addStudentClassRoom(std.getClassRoomId(), std.getsNo();
39、; ConnectionMmit(); catch (Exception e)
40、60; try
41、; ConnectionManager.rollback(); catch (Exception de) &
42、#160;
43、 throw new Exception(e); finally
44、60; try ConnectionManager.close(); &
45、#160; catch (Exception e)
46、60; Look,如果我把上述标粗(没有加红色)的地方,全部用AOP的方式从这块代码的外部“切”进去。是不是一个Spring里的Service方法就诞生了?下面来看一个完整的例子2.6 使用ThreadLocal分离Service、DAO层先来看表结构:T_Student表T_Class
47、Room表T_Student_ClassRoom表需求:很简单,T_ClassRoom表里已经有值了,在插入T_Student表的数据时同时要给这个学生分配一个班级并且插入T_Student_ClassRoom表,这就是一个事务,这两步中有任何一步出错,事务必须回滚。看来工程的结构吧:下面开始放出所有源代码:2.6.1 ConnectionManager类package .util.db;import java.sql.*;public class ConnectionManager
48、 private static ThreadLocal tl = new ThreadLocal(); private static Connection conn = null; public static void BeginTrans(boolean beginTrans) throws Exception
49、0; if (tl.get() = null | (Connection) tl.get().isClosed() conn = DBConnection
50、.getInstance().getConnection(); conn = new ConnectionSpy(conn);
51、60; if (beginTrans)
52、0; conn.setAutoCommit(false);
53、 tl.set(conn); public
54、static Connection getConnection() throws Exception return (Connection) tl.get(); public static void close
55、() throws SQLException try (
56、Connection) tl.get().setAutoCommit(true); catch (Exception e)
57、60; (Connection) tl.get().close(); tl.set(null);
58、; public static void commit() throws SQLException try
59、; (Connection) tl.get().commit(); catch (Exception e)
60、 try
61、 (Connection) tl.get().setAutoCommit(true); catch (Exception e) &
62、#160; public static void rollback() throws SQLException try
63、0; (Connection) tl.get().rollback(); catch (Exception e)
64、60; try
65、60; (Connection) tl.get().setAutoCommit(true); catch (Exception e)
66、; 2.6.2 DBConnection类package .util.db;public class DBConnection private static DBConnection instance = null; pr
67、ivate static String driverClassName = null; private static String connectionUrl = null; private static String userName = null; private static String passwor
68、d = null; private static Connection conn = null; private static Properties jdbcProp = null; private DBConnection()
69、; private static Properties getConfigFromPropertiesFile() throws Exception Properties prop = null;
70、160; prop = JdbcProperties.getPropObjFromFile(); return prop;
71、0; private static void initJdbcParameters(Properties prop) driverClassName = prop.getProperty(Constants.DRIVER_CLASS_NAME);
72、160; connectionUrl = prop.getProperty(Constants.CONNECTION_URL); userName = prop.getProperty(Constants.DB_USER_NAME);
73、60; password = prop.getProperty(Constants.DB_USER_PASSWORD); private static void createConnection() throws
74、Exception Class.forName(driverClassName); conn = DriverManager.getConnection(connec
75、tionUrl, userName, password); public static Connection getConnection() throws Exception return
76、 conn; public synchronized static DBConnection getInstance()throws Exception if (instance = nul
77、l) jdbcProp = getConfigFromPropertiesFile();
78、60; instance = new DBConnection(); &
79、#160; initJdbcParameters(jdbcProp); createConnection(); return instance;
80、 2.6.3 JdbcProperties类package .util.db;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import .URL;import java.util.*;public class JdbcProperties
81、; private static Log logger = LogFactory.getLog(JdbcProperties.class); public static Properties getPropObjFromFile()
82、60; Properties objProp = new Properties(); ClassLoader classLoader = Thread.currentThread()
83、; .getContextClassLoader(); URL url = classLoader.getResource(Cons
84、tants.JDBC_PROPERTIES_FILE); if (url = null)
85、60; classLoader = ClassLoader.getSystemClassLoader(); url = classLoader.getResource(Constants.JDBC_PROPERTIES_FILE);
86、0; File file = new File(url.getFile();
87、60; InputStream inStream = null; try
88、; inStream = new FileInputStream(file); objProp.load(inStream);
89、60; catch (FileNotFoundException e) objProp = null;
90、160; e.printStackTrace(); catch (IOE
91、xception e) e.printStackTrace();
92、60; finally try &
93、#160; if (inStream != null)
94、160; inStream.close();
95、160; inStream = null;
96、60; catch (Exception e)
97、; return objProp
98、; 2.6.4 Resource目录下的pertiesjdbc.driverClassName=com.mysql.jdbc.Driverjdbc.databaseURL=jdbc:mysql:/localhost:3306/mydb?useUnicode=true&characterEncoding=utf8jdbc.username=mysqljdbc.password=password_12.6.5 StudentService接口package .ser
99、vice;import java.util.List;import java.util.Vector;import .bean.*;public interface StudentService public void addStudent(Student std) throws Exception;2.6.6 StudentServiceImpl类package .service.impl;import java.util.ArrayList;import java.
100、util.List;import java.util.Vector;import .util.db.ConnectionManager;import .util.*;import .bean.*;import .dao.*;import .dao.impl.*;import .service.*;public class StudentServiceImpl implements StudentService
101、60; public void addStudent(Student std) throws Exception StudentDAO studentDAO = new StudentDAOImpl();
102、; ClassRoomDAO classRoomDAO = new ClassRoomDAOImpl(); try
103、160; ConnectionManager.BeginTrans(true); studentDAO.addStudent(std);
104、0; classRoomDAO
105、60; .addStudentClassRoom(std.getClassRoomId(), std.getsNo();
106、 ConnectionMmit(); catch (Exception e)
107、60; try ConnectionManager.rollback(
108、); catch (Exception de)
109、 throw new Exception(e);
110、; finally try
111、60; ConnectionManager.close();
112、 catch (Exception e)
113、160; 2.6.7 ClassRoomDAO接口package .dao;import java.util.HashMap;import java.util.List;public interface ClassRoomDAO public void addStudentClassRoom(String roomId, String sNo) throws Ex
114、ception;2.6.8 ClassRoomDAOImpl类package .dao.impl; import java.sql.*;import java.util.*; import .dao.ClassRoomDAO;import .util.db.ConnectionManager; public class ClassRoomDAOImpl implements ClassRoomDAO public
115、void addStudentClassRoom(String roomId, String sNo) throws Exception Connection conn = null;
116、60; PreparedStatement pstmt = null; try
117、160; conn = ConnectionManager.getConnection(); pstmt = conn &
118、#160; .prepareStatement(ClassRoomDAOSql.ADD_STUDENT_CLASSROOM);
119、60; pstmt.setString(1, roomId);
120、; pstmt.setString(2, sNo); pstmt.executeUpdate();
121、; catch (Exception e) throw new Exception("addStudentClassRoom:" + e.getMessage(), e);
122、; finally try
123、60; if (pstmt != null) &
124、#160; pstmt.close();
125、0; pstmt = null;
126、160; catch (Exception e)
127、0;
128、160; 2.6.9 StudentDAO接口package .dao;import java.util.*;import .bean.Student;public interface StudentDAO public void addStudent(Student std) throws Exception;2.6.10 StudentDAOImpl类package .dao.impl; import java.sql
129、.*;import javax.sql.*; import mons.logging.Log;import mons.logging.LogFactory; import .bean.Student;import .dao.StudentDAO;import .util.db.ConnectionManager; import java.util.List;import java.util.ArrayList;import java.util.Vector;import java.text.*;import
130、.util.StringUtil; public class StudentDAOImpl implements StudentDAO private Log logger = LogFactory.getLog(this.getClass(); public void addStudent(Student std) throws Exception
131、60; Connection conn = null; PreparedStatement pstmt = null; &
132、#160; try conn = ConnectionManager.getConnection();
133、160; pstmt = conn.prepareStatement(StudentDAOSql.ADD_STUDENT);
134、0; pstmt.setString(1, std.getsNo(); pstmt.setString(2, std.getsName();
135、160; pstmt.setString(3, std.getsAge();
136、0; pstmt.setString(4, std.getGender(); pstmt.setDate(5, StringUtil.convertStrToDate(std.getSbirt
137、h(); pstmt.executeUpdate();
138、60; catch (Exception e) throw new Exception("addStudent:" + e.getMessage(), e);
139、 finally try
140、0; if (pstmt != null)
141、160; pstmt.close();
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中国新型伞齿布料器市场调查研究报告
- 2025年中国数字报警器数据监测报告
- 2025至2031年中国纤维混纺纱线行业投资前景及策略咨询研究报告
- 2025年中国工业计数器市场调查研究报告
- 肇庆市实验中学高中历史三:第课社会主义建设的思想指南高效课堂教学设计
- 新疆生产建设兵团图木舒克市2024-2025学年六年级数学小升初摸底考试含解析
- 新疆乌鲁木齐2025年高三期初调研测试英语试题含解析
- 新乡医学院三全学院《物流系统优化与仿真》2023-2024学年第一学期期末试卷
- 2025-2030年中国edta铁铵行业发展状况及投资前景规划研究报告
- 兴义民族师范学院《生物与医药仪器分析》2023-2024学年第二学期期末试卷
- 劳动与技术教育课程资源开发和整合
- APQC流程分类框架PCF 版本 中文翻译
- 中国当代文学史课件
- 2022年中考语文二轮专题复习:散文阅读专项练习题汇编(含答案)
- 稿件修改说明(模板)
- 不孕症诊疗流程课件
- 节前安全安全检查表和内容
- 政府供应商分类表
- 北师大版生物八年级下册 9.25.1 发酵技术 课件
- 测量教案5章-es-602g全站仪
- DB33∕T 1230-2020 金属面板保温装饰板外墙外保温系统应用技术规程
评论
0/150
提交评论