SessionFactory与Session现在感觉是Hibernate的精髓,却也容易误解.今天通过跨库出现错误感觉通了一点------Hibernate呼叫Session的顺序(当然有点猜测的味道)
1)产生Session:一般的的当Dao被显示的使用时,由于Spring的管理他会调用getCurrentSession()来获得当前Session.
注释:这里感觉是一切罪恶的源头,如果你的DAO使用了hibernateTemplate的话在,在Spring配置中尼就会发现(至少我的项目是这样的):
<bean id="houseInfoDao" class="com.dgsoft.data.biz.info.dao.house.HouseDaoImpl">
<property name="hibernateTemplate">
<ref bean="hibernateTemplateInfo" /> //注意这里的Info
</property>
</bean>
<bean id="hibernateTemplateInfo" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactoryInfo" />//这个不用说就是Info所对应库sessionFactory
</property>
<property name="jdbcExceptionTranslator">//看命名是针对Jdbc异常
<ref bean="jdbcExceptionTranslatorInfo" />
</property>
</bean>
也就是说对于getCurrentSession()方法来说,他会先调用该Dao所属的SessionFactory看看里面有没有存在Session.这引出了第二步
2)查询该DAO所属的SessionFactory,查看里面是否有Session,有则返回该Session而没有则建立返回.注意:显然的当不同的Dao显示调用时,可能由于他们属于不同的库就会生成不同的Session(SessionFactory不同就不可能生成相同的Session).这里可以简单的认为Session是这个库专有的,当你显示调用Dao是就会生成该库的专有session(毕竟session也是connect的拥有者)。
3)由于显示调用Dao并且肯定对库进行操作因而会绑定事物,也就是说会死锁该库的部分数据,但是由于库与库之间有关系(主要是表与表的关联)其他库的专有Session可以通过这个关联操作该库数据(注意为什么说Session是库专有的,是由于Session当访问其他库时必须通过关联,若没有关联则无法访问,这是有限制的。不过当他对对方库进行操作也会在对方库中添加事物------JTA产生的原因。)
这就是问题所在。当我有个Service中有两个Dao而他们不属于同一个库。而一个DaoA改变该库中的一个表A而另一个DaoB通过关联对表A进行操作,显然两个Session两个不同的事物,而不幸的是他们操作的是表A的同一条记录(事物最小级别好像就是”条”),因而你会很容易的发现出现了死锁.
解决方法:
1)将两个库变为一个SessionFactory进行管理,由于只出来一个Session就不会出现两个事物之间死锁的问题!
2)在查阅hibernateTemplate的信息时无意发现了一个方法public final void setSessionFactory(SessionFactory sessionFactory),也就是说对于DAO我们可以显示的绑定到指定的SessionFactory,这样如果临时的将DaoA的SessionFactory设成DaoB对应的,应该也能解决死锁问题.(就是不知道代价如何)