问题描述:

I am currently stuck in the following scenario:

I am trying to save object A into database. But A is made up by a lot of other objects, B, C, and B, C consists of objects D,E...there a a lot of nested objects, you know what I mean. Let call the whole process of saving A as transaction 1.

In the middle of transaction 1, when it comes to saving some object X(which is somewhat associated to A by a number of links), let's say it is the method saveX() that triggers saving X. In the saveX() method, the business logic requires to do another query for another object Y, let's say the method is queryY().

So when we call queryY(), and when it goes to the line of code that actually get all the results from the database, we have an exception. Let's call this moment as T time.

The exception is

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: A.b -> B.

So what I think is, EJB container somewhat thinks at T time, when we need to do a query, it needs to commit the current transaction 1 and start transaction 2 to execute the query. And obviously the data related to A is not properly saved to the database yet, so the exception occurs.

So We need to somewhat suspend transaction 1 and resume it after we did the query instead of committing it at T time. I did some research and I found @TransactionAttribute can solve the problem. The funny thing is that, I found out both solutions below works(no exception occurs and application is all right) if I put one of the two on the queryY() as an annotation:

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

I read the official doc related to the annoation: http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttributeType.html

It makes sense that REQUIRES_NEW works. But I don't understand why NOT_SUPPORTED works as well. Obviously we need another transaction to call queryY() to finish the query. And in the explanation of NOT_SUPPORTED, it does not mention it will start a new transaction after suspend the first transaction.

So my first question is, why NOT_SUPPORTED works?

My second question is, why EJB container thinks the transaction 1 is ended and it needs to be committed at T time instead of regarding queryY as a part of transaction 1?

Thanks in advance! Any help will be appreciated!

网友答案:

This is not related to transaction propagation. You should use one and only one transaction to save all your objects.

This error that you get:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: A.b -> B.

Is because you try to save A and there's no cascade between A and B.

If A is the parent and B is the child (having a FK), then cascading the persist/merge operation from A to B makes sense. Otherwise, if B is a parent @OneToOne association, you need to save that first.

相关阅读:
Top