危险的Hibernate映射共用class及其解决

使用hibernate对于有交集字段结构或结构一样的表,有时候会很“正常”的想到一种“偷懒”的办法,就是让一个hbm映射定义映射到多个TABLE。例如表维表(或代码表)有结构:

 <class name="LabelValueCodeBase" abstract="true">
  <meta attribute="sync-DAO">false</meta>
  <composite-id name="id" class="LabelValueCodePK">
   <key-property name="value" column="VALUE" type="string" />
   <key-property name="langFlag" column="LANG_FLAG" type="string" />
  </composite-id>

  <property name="label" column="LABEL" type="string" not-null="true" length="50" />
 </class>

那么可能对该结构进行扩充出几个同样的hbm定义:
 <union-subclass
  name="my.model.LabelValueCode"
  extends="LabelValueCodeBase"
  entity-name="yesNoCode"
  table="YES_NO_CODE"
 />

 <union-subclass
  name="my.model.LabelValueCode"
  extends="LabelValueCodeBase"
  entity-name="sexCode"
  table="SEX_CODE"
 />

然后在一个事务里查询此两表,例如:
String hintStr = "您" + LabelValueCodeDAO.getYesNodeByValue("0").getLabel() + "是管理员用户,性别:" + LabelValueCodeDAO.getYesNodeByValue("0").getLabel();

如果 YES_NO_CODE 表里,字符串"0"对应的编码是“不是”,而SEX_CODE表里字符串"0"对应的的编码是“男”。那么我期望的结果是显示:您不是管理员用户,性别:男

但是实际运行的结果变成了:您不是管理员用户,性别:不是

这样就让人纳闷了,难道查询出错了?打开hibernate输出各SQL功能在控制台看到的SQL在查询器里执行,也是获得正确的结果。最后仔细一行行的跟踪,突然发现忽略了一个重大问题。就是hibernate一级缓存机制。

hiberante一级缓存是根据class的OID进行命中检测的,而两个表使用的是同一个class,因此,查询getYesNodeByValue("0")时,查询了VALUE为0,LANG_FLAG为zh_CN的对象并加入缓存。而随后的getYesNodeByValue("0")查询对象的OID也是VALUE为0,LANG_FLAG为zh_CN,于是把前一次查询的对象在cache命中了!于是便成了实际的错误输出结果。

因此,解决办法是,要么采用不同的class来对不同的表进行管理,要么就是。在查询出来对象后,使用evict强制从hibernate session中解除:

stringBuffer.append("您");
LabelValueCode labelValueCode = LabelValueCodeDAO.getYesNodeByValue("0");
stringBuffer.append(labelValueCode.getLabel());
getSession().evict(labelValueCode);
stringBuffer.append("是管理员用户,性别:");
stringBuffer.append("LabelValueCodeDAO.getYesNodeByValue("0").getLabel();

 

这样便得到了期望的结果。

此错误“症状”仅在多表映射一个class文件并且ID机制一样,并在一个事务使用不同表时才发生,常见于查询多表长事务或open session in view方式。如果多次查询不在一个事务中,则不会存在这个问题。因此多表映射共用class必须小心使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值