浏览 5890 次
锁定老帖子 主题:再论 ThreadLocal
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2004-01-09
public static final ThreadLocal session = new ThreadLocal();; 但是我个人觉得并无必要。 理由如下: 首先虽然servlet是多线程的,但是一般调用hibernate访问数据库都在BO /dao这一层,一般来说这一层都会在action 的 excute 方法中调用,所以拿到的session再excute方法中是有自己堆栈的,所以不会有多线程的问题,那么在sessionFactory.openSession();(这里假设sessionFactory已经建立)在openSession的过程中从连接池拿到connection的过程中肯定排他的,所以说不会产生两个对象拿到同一个session的问题.那就没有必要用到 ThreadLocal不知道我的说法对不对,请大家指点 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-01-09
ThreadLocal和多线程并发没有什么关系。ThreadLocal模式是为了解决单线程内的跨类跨方法调用的,有点AOP的味道。前面已经讲了很多了,还是搜索一下吧。
|
|
返回顶楼 | |
发表时间:2004-01-09
多谢,一句话点醒梦中人。
但是,我还有一个问题:一般情况下应该对connection 尽可能迟的取得,尽早的释放,以获得最高的并发,如果放到ThreadLocal里面到最后filter里面再释放,显然多占用的connection的时间,使统的并发降低。另外由于连接池的使用在重新get connection 也不会使用多少资源。至于事务的控制我觉得放到BO 我认为Po放数据作为和hbm.xml结合作为数据字典用,dao通过冬眠来访问数据库,然后由bo来根据具体业务组织事务(看了这里很多讨论我认为有bo来组织事务显然比用dao来组织事务更灵活,应为对数据库的访问是否编在一个事物里显然改由业务决定!)这样对 bo来说访问的就像是对象数据库一样了! 不知道大家是怎么想的? |
|
返回顶楼 | |
发表时间:2004-01-09
放在bo里面会使你的bo通用性下降。
|
|
返回顶楼 | |
发表时间:2004-01-09
引用 一般情况下应该对connection 尽可能迟的取得,尽早的释放,以获得最高的并发,如果放到ThreadLocal里面到最后filter里面再释放,显然多占用的connection的时间,使统的并发降低
不会的。除非你访问一个页面要好几十秒到几分钟。 引用 另外由于连接池的使用在重新get connection 也不会使用多少资源
在一次调用过程中多次申请归还连接对象,确实不会对性能有太大损失。但是对于编程模型来说,在没有容器管理事务的情况下,你没有办法进行跨类跨方法的事务管理。 引用 至于事务的控制我觉得放到BO
事务放在哪一层处理,哪一层就不具备跨方法调用的能力。假设你的BO1里面有事务处理,BO2也有事务处理。然后你的BO3要调用BO1的某方法,和BO2的某方法,那么一旦你在BO3里面启动事务,然后调用BO1,就会报错,因为事务是扁平的,不能嵌套的。这样的结果会造成在实际项目中,你的BO根本就写不下去了。 其实在很久以前,在论坛开张的时候,我就在精华区发贴详细分析过这个问题了。简单的来说,如果你不采用容器管理事务,那么就用ThreadLocal + Filter(在非Web应用中,在程序执行完毕前释放连接),如果你采用容器管理事务,那么就不需要ThreadLocal,用完就关。 |
|
返回顶楼 | |
发表时间:2004-01-09
很高兴了解了一种跨方法调用session的方法。多谢robbin!
但是还有一个问题:如何组织一个事物:也就是说在什么地方commit,假设有这样几个BO方法:BO1,BO2,BO3,有时候BO1本身作为一个事物,有时候BO3包含BO1所作的事情并且组织成一个事物,那么应该在哪里commit?如果在BO1里面commit,显然BO3调用BO1的时候就不满足事务的原子性要求(因为在BO1里commit了)这个时候虽然实现了session(connection)的跨方法调用却没有解决更本问题,事务的组织。 如果都在filter里面commit,呢么可能这个事务太长,远远的超出了本来需要的长度,会严重影响数据的性能(特别是在压力测试的时候!)。 我们现在都是在BO里面通过调用DAO来获得重用 public UserPO updateUserInformation( int id, String newpassword, String renewpassword, String newusername, String newemail, List roleidlist, int valid); throws LogicException, DAOException { ITxMgr tx = null; UserDAO userdao = new UserDAO();; UserPO user = null; RoleDAO roledao = new RoleDAO();; RolePO role = null; UserRoleDAO userroledao = new UserRoleDAO();; if (newpassword == null); { throw new LogicException( MessageArrayList.PASSWORD_SHOULD_NOT_BE_NULL);; } else { if (!newpassword.equals(renewpassword);); { throw new LogicException( MessageArrayList.REPASSWORD_NOT_EQUAL_PASSWORD);; } } try { tx = HibernateTxMgr.beginTrans( "Update the information of user...");; userdao.joinTx(tx);; user = userdao.getUserByUserID(id);; if(user==null);{ throw new LogicException(MessageArrayList.USER_NOT_EXIST);; } userdao.updateUserInformation( user, newpassword, newusername, newemail, valid);; userroledao.joinTx(tx);; userroledao.deleteUserRoleByUserID(user.getId(););; roledao.joinTx(tx);; for(int i=0;i<roleidlist.size();;i++);{ role = roledao.getRoleByRoleID(((Integer);roleidlist.get(i););.intValue(););; if(role!=null);{ userroledao.addNewUserRole(user,role);; } else { tx.rollback();; throw new LogicException(MessageArrayList.ROLE_NOT_EXIST);; } } } catch (TxMgrException e); { tx.rollback();; logger.fatal(e.toString(););; throw new DAOException(e);; } catch (HibernateException e); { tx.rollback();; logger.fatal(e.toString(););; throw new DAOException(e);; } finally { try { tx.endTrans();; } catch (TxMgrException te); { logger.fatal(te.toString(););; throw new DAOException(te);; } } return user; } 这里tx.endTrans();执行了COMMIT。 如果改用ThreadLocal 在COMMIT的方面如果有好的办法的话,希望ROBBIN能介绍一下 |
|
返回顶楼 | |
发表时间:2004-01-09
总要有一个类来控制事务边界把,ThreadLocal只解决了session阿
|
|
返回顶楼 | |
发表时间:2004-01-09
用ThreadLocal + Filter 只解决了一种通用的粗粒度的控制方法. 你可以用事务容器的方式, 不同的组件设置成不同的事务类型, support, required等.
|
|
返回顶楼 | |