之漫谈使用ThreadLocal改进你的层次的划分Word下载.docx
- 文档编号:18270005
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:33
- 大小:218.12KB
之漫谈使用ThreadLocal改进你的层次的划分Word下载.docx
《之漫谈使用ThreadLocal改进你的层次的划分Word下载.docx》由会员分享,可在线阅读,更多相关《之漫谈使用ThreadLocal改进你的层次的划分Word下载.docx(33页珍藏版)》请在冰豆网上搜索。
该方法返回当前线程所对应的线程局部变量。
publicvoidremove()
将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK5.0新增的方法。
需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protectedObjectinitialValue()
返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。
这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。
ThreadLocal中的缺省实现直接返回一个null。
值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<
T>
。
API方法也相应进行了调整,新版本的API方法分别是voidset(Tvalue)、Tget()以及TinitialValue()。
一、来看一个实际案例
2.1
同一Service方法中调用多个Dao方法
可以看到,我们有一个Service方法,在该Service方法中调用多个Dao方法,所有在该Service方法中的的Dao都处于同一事务中。
该Service方法结束后,提交事务;
该Service方法中有任何错,回滚事务;
2.2
传统的做法
来看下面这段伪代码
Service层代码:
publicvoidserviceMethod(){
Connectionconn=null;
try{
Connectionconn=getConnection();
conn.setAutoCommit(false);
Dao1dao1=newDao1(conn);
dao1.doSomething();
Dao2dao2=newDao2(conn);
dao2.doSomething();
Dao3dao3=newDao3(conn);
dao3.doSomething();
mit();
}catch(Exceptione){
try{
conn.rollback();
}catch(Exceptionex){}
}finally{
conn.setAutoCommit(true);
}catch(Exceptione){}
if(conn!
=null){
conn.close();
conn=null;
}
每个Dao层的代码:
ClassDao1{
privateConnectionconn=null;
publicDao1(Connectionconn){
this.conn=conn;
publicvoiddoSomething(){
PreparedStatementpstmt=null;
pstmt=conn.preparedStatement(sql);
pstmt.execute…
…
log.error(e,”ExeceptionoccurredinDao1.doSomething():
”+e.getMessage,e);
if(pstmt!
pstmt.close();
pstmt=null;
}catch(Exceptione){}
如果我一个Service方法有调用一堆dao方法,先不说这样写首先破坏了OOP的封装性原则,如果有一个dao多关了一个conn,那就会导致其它的dao得到的conn为null,这种事在这样的写法下由其当你还有业务逻辑混合在一起时很容易发生。
笔者曾经遇见过2个项目,出现outofmemory或者是connectionpoolhasbeenleakage,经查代码就是在每个dao中多关或者在service层中漏关,或者是每个dao有自己的conntionconn=getConnection(),然后还跑到Service层里去关这个connection(那关什么,关个P关!
)。
当然,如果你说你在写法上绝对promise绝对注意这样的问题不会发生,但是我们来看看下面的这种做法,是否会比上面这个写法更好呢?
2.3Spring中的做法
先来看Spring中的写法。
大家应该都很熟悉Spring中的写法了,来看一下它是怎么解决的。
Service层
//aop自动加入connection,并且将conn.setAutoCommit(false);
//aop自动加入rollback
//aop自动加入conn.setAutoCommit(true)
//aop自动加入conn.close();
这边我们不讲AOP,因为用类反射结合xml很容易将aop自动。
这些东西加入我们的代码中去是不是?
我们只管写dao方法,service方法,不需要关心在哪边commit哪边rollback何时connection,spring的声明式事务会帮我们负责,这种风格我们称为“优雅”,各层间耦合度极大程度上的降低,封装性好。
因此,我们可以总结出下面这些好处:
Service层的方法只管开启事务(如果讲究点的还会设一个Transaction);
在该Service层中的所有dao使用该service方法中开启的事务(即connection);
Dao中每次只管getCurrentConnection(获取当前的connection),与进行数据处理
Dao层中如果发生错误就抛回Service层
Service层中接到exception,在catch{}中rollback,在try{}未尾commit,在finally块中关闭整个connection。
这。
就是我们所说的ThreadLocal。
举个更实际的例子再次来说明ThreadLocal:
我们有3个用户访问同一个service方法,该service方法内有3个dao方法为一个完整事务,那么整个web容器内只因该有3个connection,并且每个connection之间的状态,彼此“隔离”。
我们下面一起来看我们如何用代码实现类似于Spring的这种做法。
首先,根据我们的ThreadLocal的概念,我们先声明一个ConnectionManager的类。
2.4
利用ThreadLocal制作ConnectionManager
publicclassConnectionManager{
privatestaticThreadLocaltl=newThreadLocal();
privatestaticConnectionconn=null;
publicstaticvoidBeginTrans(booleanbeginTrans)throwsException{
if(tl.get()==null||((Connection)tl.get()).isClosed()){
conn=SingletonDBConnection.getInstance().getConnection();
conn=newConnectionSpy(conn);
if(beginTrans){
conn.setAutoCommit(false);
}
tl.set(conn);
publicstaticConnectiongetConnection()throwsException{
return(Connection)tl.get();
publicstaticvoidclose()throwsSQLException{
try{
((Connection)tl.get()).setAutoCommit(true);
}catch(Exceptione){
((Connection)tl.get()).close();
tl.set(null);
publicstaticvoidcommit()throwsSQLException{
((Connection)tl.get()).commit();
publicstaticvoidrollback()throwsSQLException{
((Connection)tl.get()).rollback();
2.5
利用ThreadLocal改造Service与Dao层
Service层(注意红色标粗-好粗yeah,的地方)
packagesky.org.service.impl;
publicclassStudentServiceImplimplementsStudentService{
publicvoidaddStudent(Studentstd)throwsException{
StudentDAOstudentDAO=newStudentDAOImpl();
ClassRoomDAOclassRoomDAO=newClassRoomDAOImpl();
ConnectionManager.BeginTrans(true);
studentDAO.addStudent(std);
classRoomDAO
.addStudentClassRoom(std.getClassRoomId(),std.getsNo());
ConnectionMmit();
try{
ConnectionManager.rollback();
}catch(Exceptionde){
thrownewException(e);
}finally{
ConnectionManager.close();
Look,如果我把上述标粗(没有加红色)的地方,全部用AOP的方式从这块代码的外部“切”进去。
是不是一个Spring里的Service方法就诞生了?
下面来看一个完整的例子
2.6
使用ThreadLocal分离Service、DAO层
先来看表结构:
T_Student表
T_ClassRoom表
T_Student_ClassRoom表
需求:
很简单,T_ClassRoom表里已经有值了,在插入T_Student表的数据时同时要给这个学生分配一个班级并且插入T_Student_ClassRoom表,这就是一个事务,这两步中有任何一步出错,事务必须回滚。
看来工程的结构吧:
下面开始放出所有源代码:
2.6.1ConnectionManager类
packagesky.org.util.db;
importjava.sql.*;
conn=DBConnection.getInstance().getConnection();
2.6.2DBConnection类
publicclassDBConnection{
privatestaticDBConnectioninstance=null;
privatestaticStringdriverClassName=null;
privatestaticStringconnectionUrl=null;
privatestaticStringuserName=null;
privatestaticStringpassword=null;
privatestaticPropertiesjdbcProp=null;
privateDBConnection(){
privatestaticPropertiesgetConfigFromPropertiesFile()throwsException{
Propertiesprop=null;
prop=JdbcProperties.getPropO
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 漫谈 使用 ThreadLocal 改进 层次 划分
![提示](https://static.bdocx.com/images/bang_tan.gif)