ThreadLocal关键


这是一个网友用threadlocal管理JDBC连接的一个例子,大家认为这样的管理是否存在安全问题?对于高性能,高安全的环境下是否可行?

理论上,这种用法没有问题,只要保证你的服务是在同一个线程中执行的。

关于性能,ThreadLocal的使用不会产生什么问题,也不存在多线程之间的竞争情况。

从代码的可靠性角度来考虑,其中有不少不足的地方。譬如对连接的获取,最好做一个Wrapper,保证不会被意外的关闭。另外,还需要保证服务结束的时候确保事务结束,连接关闭的机制。

最好做一个Wrapper,保证不会被意外的关闭

能否给出你示意意的代码.

假设:一个用户执行一个功能,这个功能有JDBC事务.可能执行时间是10秒.而在这十秒还没执行完,这个用户再点了另一功能,而另一功能所打开的连接则是上一功能的功能对象,我认为这样可能会使同一个连接对象出现混乱,事务出现混乱.
不知道slangmgh 担心的是否是我说的这个问题,或者其它问题
[该贴被leoyu于2007年09月06日 14:24修改过]

况且现在的容器如TOMCAT,自身有线程池,假如程序中某个地方忘了清除threadlocal中的连接对象,这样应该也会出现连接对象混乱,事务混乱了.(当然这点只有程序员自己注意,比如finally中关闭).但对于这些问题,要做到多线程,并发,threadlocal中对象的安全独立性感觉有点难度

>最好做一个Wrapper,保证不会被意外的关闭
>能否给出你示意意的代码.

很简单,你可以用聚合的方式实现一个Connection接口,把该类的close方法设置成什么都不做就可以了。然后在返回连接的时候返回该类的实例。

>假设:一个用户执行一个功能,这个功能有JDBC事务.可能执行时间是10秒.而在这十秒还没执行完,这个用户再点了另一功能,而另一功能所打开的连接则是上一功能的功能对象,我认为这样可能会使同一个连接对象出现混乱,事务出现混乱.

这个没有关系,因为webapp将分配给你新的线程执行你的请求,在该线程中,获取连接的时候就会是新的连接了(这就是ThreadLocal的作用,每个线程只能获取自己设置的变量)。如果你同时有10个请求在执行,那么只有一个ThreadLocal变量,但是不同的线程从该ThreadLocal中获取的对象是不同的。

>况且现在的容器如TOMCAT,自身有线程池,假如程序中某个地方忘了清除threadlocal中的连接对象,这样应该也会出现连接对象混乱,事务混乱了.(当然这点只有程序员自己注意,比如finally中关闭).

这个问题很关键,要做到这一点,你最好在框架中统一处理,譬如在调用服务前执行开始事务,在服务执行完成后,根据服务执行结果处理事务是否提交或者回滚。如果将它交给每个服务本身来做,会出现问题的。

所有的框架都会有这个问题(如果将事务处理交给应用自己处理的话)。

>但对于这些问题,要做到多线程,并发,threadlocal中对象的安全独立性感觉有点难度

应该没有你想像的那么难。你需要对多线程这个概念再理解的透一点。

>程序中某个地方忘了清除threadlocal中的连接对象
这点非常关键,可以做一个专门close的filter进行关闭。

比如我最近在JdonFramework中支持Hibernate3工作中,将HIbernate的Session保存到ThreadLocal中,然后做一个CloseSessionInViewFilter,在最后将threadLocal中对象进行清除,包括事务进行commit。这不象Spring的OpenSessionInViewFilter,我认为Session可以有应用程序自己打开,不必在表现层就打开,但是关闭必须有一个总阀门关闭,这样,可以充分利用Hibernate的懒加载机制,这个机制是很有魅力的,但是需要Session一直打开。

本人在用Hibernate的过程中通过一个Filter来集中关闭Hibernate 的session,
遇到过同一集合被2个不同的session关联的问题,开始想在出现问题的代码前编码关闭session的时候没能解决,后来看那个session工厂的时候发现内部实现用了ThreadLocal类,突然明白 ,要在有特殊需要的地方关闭session必须要保证在同一线程中才能保证关闭了想要关闭的session...........
[该贴被xiaojiang51于2007-11-07 16:17修改过]

>要在有特殊需要的地方关闭session必须要保证在同一线程中才能保证关闭了想要关闭的session

正确,所以需要ThreadLocal。

写的挺好,不过,这样写代码我觉的不好
原因:
第一:事务管理应该和连接工厂合为一个类,没有必要分开两个类
第二:你的业务中搀杂了非业务操作,我觉的不好,业务层只定义业务相关的操作接口,不需要有一个基类,就是是一种偶合,因为你的事务管理实际上就是连接管理,为什么每一个业务都有带一个连接管理,业务和连接没有任何关系
第三:不建议使用ThreadLocal来管理连接,你看看代码,基本上业务Bean是每次都new一个,而且每个方法操作完了事务结束,这还有必要使用ThreadLocal吗?还有必要建一个事务类吗?还不如使用连接池