weixin_42297864 2008-12-07 22:44
浏览 207
已采纳

openSessionInView引出的奇怪问题

appfuse那套东西,Spring+Hibernate,在Controller层写下如下语句,[color=red]目的是根据视图层的修改内容更新
[code="java"]
sellerSellItem[/color]:
SellerSellItem sellerSellItem = ....(根据视图层生成)
sellerSellItem.setSellerSellReport(sellerSellReport);
sellerSellReport.addSellerSellItem(sellerSellItem);
//sellerSellItemManager.save(sellerSellItem); [color=red]//1.[/color]
sellerSellReportManager.save(sellerSellReport); [color=red]//2[/color]
[/code]
注:sellerSellReport是主表,sellerSellItem是明细.使用了OpenSessionInView.
具体dao实现(service层从略):
[code="java"]
public T save(T object) {
super.getHibernateTemplate().saveOrUpdate(object); [color=red]//3[/color]
super.getHibernateTemplate().flush();
return object;
}
[/code]

问题来了:
1)如果屏蔽语句1,则sellerSellItem根本无法更新(不报错),但是可以新增;
[code="java"]
sellerSellItem[/color]:
SellerSellItem sellerSellItem = ....(根据视图层生成)
sellerSellItem.setSellerSellReport(sellerSellReport);
sellerSellReport.addSellerSellItem(sellerSellItem);
sellerSellReportManager.save(sellerSellReport); [color=red]//2[/color]

service略
dao层:
public T save(T object) {
super.getHibernateTemplate().saveOrUpdate(object); [color=red]//3[/color]
super.getHibernateTemplate().flush();
return object;
}
[/code]
2)如果屏蔽语句2,则sellerSellItem更新时报错:org.hibernate.NonUniqueObjectException,新增时成功.
[code="java"]
sellerSellItem[/color]:
SellerSellItem sellerSellItem = ....(根据视图层生成)
sellerSellItem.setSellerSellReport(sellerSellReport);
sellerSellReport.addSellerSellItem(sellerSellItem);
//sellerSellItemManager.save(sellerSellItem); [color=red]//1.[/color]

service略
dao层:
public T save(T object) {
super.getHibernateTemplate().saveOrUpdate(object); [color=red]//3[/color]
super.getHibernateTemplate().flush();
return object;
}
[/code]
3)将语句3改成merge,屏蔽语句2,靠,更新倒是无问题,新增时一下就直接新增两条同样的记录.(采用merge必须立即flush,否则在service层不能得到id,从而产生各种问题);
[code="java"]
sellerSellItem[/color]:
SellerSellItem sellerSellItem = ....(根据视图层生成)
sellerSellItem.setSellerSellReport(sellerSellReport);
sellerSellReport.addSellerSellItem(sellerSellItem);
sellerSellItemManager.save(sellerSellItem); [color=red]//1.[/color]

service略
dao层:
public T save(T object) {
super.getHibernateTemplate().merge(object); [color=red]//3[/color]
super.getHibernateTemplate().flush();
return object;
}
[/code]
4)将语句3改成merge,屏蔽语句1,更晕,这时实际上新增已正确了,sellerSellReport中已保存有正确的sellerSellItem,但真正的sellerSellItem却并不正确(没有id,处于游离状态),也就是sellerSellItem与sellerSellReport.sellerSellItem此时居然不同步!
[code="java"]
sellerSellItem[/color]:
SellerSellItem sellerSellItem = ....(根据视图层生成)
sellerSellItem.setSellerSellReport(sellerSellReport);
sellerSellReport.addSellerSellItem(sellerSellItem);
sellerSellReportManager.save(sellerSellReport); [color=red]//2[/color]

service略
dao层:
public T save(T object) {
super.getHibernateTemplate().merge(object); [color=red]//3[/color]
super.getHibernateTemplate().flush();
return object;
}
[/code]
5)不得已,先将sellerSellItem游离掉吧.结果发现用尽手段都不能游离掉,什么getHibernateTemplate().contains(obj)和getHibernateTemplate().evict(obj)根本不起作用似的.
[code="java"]
sellerSellItem[/color]:
SellerSellItem sellerSellItem = ....(根据视图层生成)
sellerSellItem.setSellerSellReport(sellerSellReport);
sellerSellReport.addSellerSellItem(sellerSellItem);
sellerSellReportManager.save(sellerSellReport); [color=red]//2[/color]

service略
dao层:
public T save(T object) {
supre.getHibernateTemplate().evict(object);
super.getHibernateTemplate().merge(object); [color=red]//3[/color]
super.getHibernateTemplate().flush();
return object;
}
[/code]

请高人给出解决措施啊,呵呵.
看了源码,分析如下:
1)第一种方式,即利用主表更新子表的方式,由于采用了openSessionInView,在sellerSellReport中已存在id相同的sellerSellItem,所以sellerSellReport.addSellerSellItem(sellerSellItem)这句语句根本就相当于未执行.如果修改SellerSellItem的equals和hasCode方法,则sellerSellReport中会同时存在两个id相等的sellerSellItem,同样会报NonUniqueObjectException;
2)第二种方式,即直接更新子表的方式.由于session中已存在一个id相同的sellerSellItem,当然会报NonUniqueObjectException;
3)第三种方式,相当于更新子表,使用merge语句,经跟踪发现:在执行merge时和执行flush时会分别插入一条记录.进一步跟踪的结果:在执行merge时,是更新子表sellerSellItem,但主表sellerSellReport.sellerSellItem并未更新(不同步!);于是继续进行flush时,会更新主表,导致sellerSellItem重新被增加进去.
4)第四种方式,相当于更新主表,使用merge语句,发现更新后的主表的sellerSellReport.sellerSellItem有id,而sellerSellItem却没有id,居然有这种情况!也就是说merge语句慎用于一对多和多对多的情形.
5)evict不是不起作用,而是因为evict必须是对于get或load或find出来的真正的持久对象才能使其游离(开始以为Session的contains方法是利用持久化对象的equals和hashCode方法来的,结果发现不是这样,而是有个什么什么包装了一次,忘了).

唉,实在是想不到办法了,请各位帮忙,谢了先^_^

  • 写回答

1条回答 默认 最新

  • iteye_10573 2008-12-13 05:50
    关注

    try

    [code="java"]
    sellerSellItem[/color]:

    SellerSellItem sellerSellItem = ....(根据视图层生成)

    sellerSellItem.setSellerSellReport(sellerSellReport);

    SellerSellItem item = sellerSellItemManager.save(sellerSellItem);

    sellerSellReport.addSellerSellItem(item);

    service略

    dao层:

    public T save(T object) {

    T persist = super.getHibernateTemplate().merge(object);
    super.getHibernateTemplate().flush();

    return persist;

    }
    [/code]

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 请问有用MZmine处理 “Waters SYNAPT G2-Si QTOF质谱仪在MSE模式下采集的非靶向数据” 的分析教程吗
  • ¥50 opencv4nodejs 如何安装
  • ¥15 adb push异常 adb: error: 1409-byte write failed: Invalid argument
  • ¥15 nginx反向代理获取ip,java获取真实ip
  • ¥15 eda:门禁系统设计
  • ¥50 如何使用js去调用vscode-js-debugger的方法去调试网页
  • ¥15 376.1电表主站通信协议下发指令全被否认问题
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥15 复杂网络,变滞后传递熵,FDA
  • ¥20 csv格式数据集预处理及模型选择