我目前陷入以下情况:
我正在尝试将对象A保存到数据库中。但A由许多其他对象组成,B,C和B,C由对象D,E组成......有很多嵌套对象,你知道我的意思。让我们调用将A保存为事务1的整个过程。
在事务1的中间,当涉及保存一些对象X(通过多个链接与A有些关联)时,让我们说它是触发保存X的方法saveX()。在saveX()方法中,业务逻辑需要对另一个对象Y执行另一个查询,让我们说该方法是queryY()。
因此,当我们调用queryY()时,当它转到实际从数据库获取所有结果的代码行时,我们有一个例外。让我们把这个时刻称为T时间。
例外是
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: A.b -> B.
所以我认为,EJB容器在T时有点想,当我们需要进行查询时,它需要提交当前事务1并启动事务2来执行查询。显然,与A相关的数据尚未正确保存到数据库中,因此会发生异常。
所以我们需要暂停事务1并在我们执行查询后重新启动它,而不是在T时间提交它。我做了一些研究,发现@TransactionAttribute可以解决问题。有趣的是,如果我将这两个中的一个放在queryY()上作为注释,我发现下面的两个解决方案都起作用(没有异常发生并且应用程序没问题):
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
我阅读了与传单有关的官方文档:http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttributeType.html
REQUIRES_NEW有效是有道理的。但我不明白为什么NOT_SUPPORTED也能正常工作。显然我们需要另一个事务来调用queryY()来完成查询。在NOT_SUPPORTED的解释中,它没有提到它会在暂停第一个事务后启动一个新事务。
所以我的第一个问题是,为什么NOT_SUPPORTED有效? 我的第二个问题是,为什么EJB容器认为事务1已经结束并且需要在T时提交而不是将queryY作为事务1的一部分?
提前致谢!任何帮助将不胜感激!
答案 0 :(得分:0)
这与事务传播无关。您应该使用一个且仅一个事务来保存所有对象。
您收到此错误:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: A.b -> B.
是因为你试图保存A而且A和B之间没有级联。
如果A是父,B是子(具有FK),则将持久/合并操作从A级联到B是有意义的。否则,如果B是父@OneToOne
关联,则需要先保存它。