前几天,公司的老司机在群里发了一个问题供大家探讨:
刚遇到一个hibernate的问题,项目框架是struts2+ spring +hibernate3问题,在action层,分别调用了2个service 方法,比如叫aService.mergeEntity(entity)和bService.updateEntity(entity);
参数都有一个entity对象这个 entity 是hibernate的一个entity
然后呢在第一个aService方法里 调用了hibernate的merge(entity);
然后在第二个bService方法里调用了hibernate的update(entity);
那么第二个bService方法会不会报错,如果报错,是什么错误,怎么解决?
我的回答:分为2种情况。当entity是瞬时态的时候(即entity没有id),由于merge的机制关系(可参考http://blog.csdn.net/hurahura/article/details/51933454;http://blog.csdn.net/ml5271169588/article/details/6734981),merge生成了另一个持久态对象entity2并在事务结束时将其持久化至数据库中,但entity本身仍是瞬时态的,这时对瞬时态对象执行update就会报一个对象id为空的错误;当entity是游离态时(有id),不会报错。
之后老司机说了,他碰到的情况是entity已经手动set了一个id(这里我和他对于手动set id后对象是否是游离态产生了分歧,但与此题关系不大暂不讨论),在update时然后报了session中已有一个id相同的对象的错误。
那么我是不服的,在我看来当entity有id时,虽然merge方法从数据库中取出了一个id相同的持久态对象entity2,但由于事务边界是在service层的,aService的方法执行完之后事务提交、session关闭、entity2从持久态变为游离态,再执行bService方法时,新的session中没有同id的持久态对象了,就不会报错。
为了证明我的观点,我就选用了手头上一个SSH项目开始了我的实验:
情景一:entity为瞬时态,即没有id
可以看到,此时与我的第一段回答相同,是由于merge的机制导致的错误。
情景二:entity set了一个数据库中已存在的id
此时居然报错了!且与老司机所说的错误相同:session中已存在了一个id相同的对象,为了证实此错误是由于session没有关闭,merge产生的entity2仍是持久态(即仍与session关联),我又设置了
情景三:在同一个service方法下对entity进行merge和update
可以看到,与情景二错误相同,那么应该可以证实是session没有关闭引起的错误(其实这里是不严谨的,仅是猜测,因为我对于底层的session不熟悉,不知道如何手动关闭T^T)。之后证实spring确实配置了OpenSessionInView方法使session保持开启(关于OpenSessionInView可以参考
http://www.iteye.com/topic/32001)
情景四:entity set了一个数据库中不存在的id
当entity的id在数据库中不存时,从打印出来的hibernate语句中可以看到,merge在select对象无果时去insert了,但因为我的主键策略是sequence,merge产生的entity2的id与entity并不同,所以没有报错。(这里算是抓住老司机的一个漏洞,扳回半城)。
解决方案:第二个update方法用merge代替,因为第二个merge会找到第一个merge产生的entity2(此时entity2还在session中,仍是持久态)作为entity的持久态,就不会像update一样报出session中已存在了一个id相同的对象的错误了。这也是merge最主要的用法(多数情况下我们都用saveOrUpdate)。
至此,所有情况分析完毕。虽然看似是一段明显不合理的程序,但分析出来的错误原因却出人意料,其中也涉及到了对象状态、merge机制、spring管理下的session、主键策略等多个知识点。所以就算是一小段程序,要想写好,也需要我们对各个细节融会贯通,我要学习的还有很多啊!
相关推荐
Hibernate中session的merge以及update方法
Hibernate merge、update与saveOrUpdate方法的区别
非常经典的SQL经验,适合于数据库初学者及长期从事软件开发者
Araxis Merge 软件入门使用教程 Araxis Merge 软件入门使用教程 Araxis Merge 软件入门使用教程 Araxis Merge 软件入门使用教程 pdf
Merge into写法,含两种,带实例说明
里面给大家内嵌了Araxis Merge v6.5和Araxis Merge 2017两个版本,并配备了使用说明。 Araxis Merge v6.5:免安装版本,解压直接运行merge.exe即可正常使用(目前好像不支持Win10系统了,但是我同事的win10可以用,...
oracle merge into的使用,开发必备的。
当ID在数据库中能找到的时候,update与merge的执行效果都是更新数据,发出update语句; 如果没有设置ID的话,则这个对象就当作瞬态处理: 用update的话,由于没有ID,所以会报异常,merge此时则会保存数据,根据ID...
android merge 标签使用介绍
详细介绍了使用 BULK COLLECT 进行批量操作 提高sql的执行效率 使用MERGE INTO USING 一条sql搞定 新增和修改 使用connect by 进行递归树查询
Araxis Merge 是一个可视化的文件比较、合并和同步的软件,能够方便的被软件工程师和 web 站点开发者使用快速精确地比较、了解和联合不同版本的源文件;进行版本和质量控制,创建 HTML 或是 XML 报告。
Android中include和merge标签的基本使用方法
android中include和merge标记的区别和使用
merge在include使用下优化布局文件
Hibernate中的merge使用详情解说
oracle同一个表中使用merge
Mybatis批量foreach merge into的用法,这是介绍Mybatis批量foreach merge into的用法的文档
我们能够在事务之外调用这个方法,这也是我不喜欢使用这个方法保存数据的原因。 假如两个实体之间有关系(例如employee表和address表有一对一关系),如果在没有事务的情况下调用这个方法保存employee这个实体,...
merge 比较工具 merge 比较工具merge 比较工具
# how to use ? 包含使用教程,使用中有任何问题可以私信作者。 # For windows:打开 cygwin 终端,执行 ...# 使用 last commit 作为 merge title # 提供可选的指定委派人功能 # 提供可选的 Accept merge request 功能