Spring Async breaks JPA - detached entity passed to persist
up vote
0
down vote
favorite
Using H2 and JPA my REST app worked well before Ansyc, but after implementation breaks the JPA persistence model.
Here is the case:
My repository has a method JpaRepository.save()
but when called from a separate thread, it throws InvalidDataAccessApiUsageException
error.
My Controller calls the Service which calls the Repository to insert a new object, and I get the following error:
InvalidDataAccessApiUsageException: detached entity passed to persist: TransactionalEntity; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: TransactionalEntity]
CONTROLLER:
@Autowired
@Qualifier("depositIntentService")
private TransactionIntentService depositIntentService;
@PostMapping("/services/transactions/deposit")
public CompletableFuture<ResponseEntity<TransactionIntent>> deposit(@Valid @RequestBody TransactionClientRequest request) {
CompletableFuture<TransactionIntent> depositIntentFuture =
transactionIntentFactory.createDepositIntent(
request.entity.id,
Money.of(CurrencyUnit.of(request.money.currency), request.money.amount));
return depositIntentFuture.thenApply(intent -> {
TransactionIntent publishedIntent = depositIntentService.attemptPublish(intent); //<-- causes error
ResponseEntity.ok(publishedIntent)
});
}
SERVICE:
@Component
@Repository
public abstract class TransactionIntentServiceImpl implements TransactionIntentService{
@Autowired
private TransactionIntentRepository transactionIntentRepo;
@Transactional
public TransactionIntent attemptPublish(TransactionIntent intent){
transactionIntentRepo.save(intent); //<-- Throws error: ...detached entity passed to persist
}
}
REPOSITORY
@Repository
public interface TransactionIntentRepository extends JpaRepository<TransactionIntent, Long>{
}
Any ideas how to support JPA persistance in an Async environment?
Thanks!
Update1
FACTORY
@Component
public class TransactionIntentFactory {
@Autowired
private UserService userService;
@Async("asyncExecutor")
public CompletableFuture<TransactionIntent> createDepositIntent(long beneficiaryId, Money money) {
CompletableFuture<User> bank = userService.findByUsername("bankItself@bank.com");
CompletableFuture<User> user = userService.find(beneficiaryId);
CompletableFuture<Void> allUserFutures = CompletableFuture.allOf(bank, user);
return allUserFutures.thenApply(it -> {
User userSource = bank.join();
User userBeneficiary = user.join();
TransactionIntent intent = new TransactionIntentBuilder()
.status(new TransactionIntentStatus(TRANSFER_STATUS.CREATED, "Deposit"))
.beneficiary(userBeneficiary)
.source(userSource)
.amount(money)
.build();
return intent;
});
}
}
ENTITY
@Entity
public class TransactionIntent {
@Id
@GeneratedValue
public long id;
public final Money amount;
public final Date createdAt;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionIntentStatus status;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity beneficiary; //to
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity source; //from
TransactionIntent(){
this.amount= null;
this.createdAt = null;
this.status = null;
this.beneficiary = null;
this.source = null;
}
public TransactionIntent(TransactionIntentBuilder builder) {
this.amount = builder.amount;
this.createdAt = new Date();
this.status = builder.status;
this.beneficiary = builder.beneficiary;
this.source = builder.source;
}
}
java spring hibernate spring-data-jpa h2
add a comment |
up vote
0
down vote
favorite
Using H2 and JPA my REST app worked well before Ansyc, but after implementation breaks the JPA persistence model.
Here is the case:
My repository has a method JpaRepository.save()
but when called from a separate thread, it throws InvalidDataAccessApiUsageException
error.
My Controller calls the Service which calls the Repository to insert a new object, and I get the following error:
InvalidDataAccessApiUsageException: detached entity passed to persist: TransactionalEntity; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: TransactionalEntity]
CONTROLLER:
@Autowired
@Qualifier("depositIntentService")
private TransactionIntentService depositIntentService;
@PostMapping("/services/transactions/deposit")
public CompletableFuture<ResponseEntity<TransactionIntent>> deposit(@Valid @RequestBody TransactionClientRequest request) {
CompletableFuture<TransactionIntent> depositIntentFuture =
transactionIntentFactory.createDepositIntent(
request.entity.id,
Money.of(CurrencyUnit.of(request.money.currency), request.money.amount));
return depositIntentFuture.thenApply(intent -> {
TransactionIntent publishedIntent = depositIntentService.attemptPublish(intent); //<-- causes error
ResponseEntity.ok(publishedIntent)
});
}
SERVICE:
@Component
@Repository
public abstract class TransactionIntentServiceImpl implements TransactionIntentService{
@Autowired
private TransactionIntentRepository transactionIntentRepo;
@Transactional
public TransactionIntent attemptPublish(TransactionIntent intent){
transactionIntentRepo.save(intent); //<-- Throws error: ...detached entity passed to persist
}
}
REPOSITORY
@Repository
public interface TransactionIntentRepository extends JpaRepository<TransactionIntent, Long>{
}
Any ideas how to support JPA persistance in an Async environment?
Thanks!
Update1
FACTORY
@Component
public class TransactionIntentFactory {
@Autowired
private UserService userService;
@Async("asyncExecutor")
public CompletableFuture<TransactionIntent> createDepositIntent(long beneficiaryId, Money money) {
CompletableFuture<User> bank = userService.findByUsername("bankItself@bank.com");
CompletableFuture<User> user = userService.find(beneficiaryId);
CompletableFuture<Void> allUserFutures = CompletableFuture.allOf(bank, user);
return allUserFutures.thenApply(it -> {
User userSource = bank.join();
User userBeneficiary = user.join();
TransactionIntent intent = new TransactionIntentBuilder()
.status(new TransactionIntentStatus(TRANSFER_STATUS.CREATED, "Deposit"))
.beneficiary(userBeneficiary)
.source(userSource)
.amount(money)
.build();
return intent;
});
}
}
ENTITY
@Entity
public class TransactionIntent {
@Id
@GeneratedValue
public long id;
public final Money amount;
public final Date createdAt;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionIntentStatus status;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity beneficiary; //to
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity source; //from
TransactionIntent(){
this.amount= null;
this.createdAt = null;
this.status = null;
this.beneficiary = null;
this.source = null;
}
public TransactionIntent(TransactionIntentBuilder builder) {
this.amount = builder.amount;
this.createdAt = new Date();
this.status = builder.status;
this.beneficiary = builder.beneficiary;
this.source = builder.source;
}
}
java spring hibernate spring-data-jpa h2
Are you setting the id of the TransactionIntent in the TransactionIntentFactory? If so, this could be the cause of this error. Having the code for the createDepositIntent factory method would be helpful. Providing the annotations/source for the TransactionIntent entity would be useful as well.
– C. Springer
Nov 12 at 4:52
@C.Springer The intent it is not set by me but is annotated w/ 'Id' and 'GeneratedValue' and so set by the db. Please see updates for the Factory and Entity code. Thanks
– KasparTr
Nov 12 at 5:11
The problem is that the TransactionalEntity (User) is attached on another thread than the TransactionIntent. When I remove the 'cascade=CascadeType.ALL' it doesn't throw the error. But doing so means I that there is a separate "persistence" on each thread. How can I operate on a single instance of the jpa persistance?
– KasparTr
Nov 12 at 11:55
I had a similar problem with a project using Spring Integration once upon a time. My solution as I remember it was to store just the id of the object being referenced in the database and defer actual retrieval to the code/thread actually doing the persistence. In your case, there would need to be some sort of pre-persist operation (presumably in attemptPublish) that would tell the TransactionIntent object to load the appropriate objects into the current HibernateSession and then persist the object.
– C. Springer
Nov 12 at 12:35
I wanted to add some food for thought here and suggest that you reconsider your heavy use of CompletableFuture altogether. For example, your service returns a CompletableFuture when retrieving User objects but then calls join(), thus being executed serially. In this case the future is added complexity. Perhaps another, more Hibernate-friendly, solution would involve the creation of some Serializable, throw-away value object that represents the pending transaction that could be passed across threads. The code in the future would then perform all persistence/lookup operations.
– C. Springer
Nov 12 at 13:17
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
Using H2 and JPA my REST app worked well before Ansyc, but after implementation breaks the JPA persistence model.
Here is the case:
My repository has a method JpaRepository.save()
but when called from a separate thread, it throws InvalidDataAccessApiUsageException
error.
My Controller calls the Service which calls the Repository to insert a new object, and I get the following error:
InvalidDataAccessApiUsageException: detached entity passed to persist: TransactionalEntity; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: TransactionalEntity]
CONTROLLER:
@Autowired
@Qualifier("depositIntentService")
private TransactionIntentService depositIntentService;
@PostMapping("/services/transactions/deposit")
public CompletableFuture<ResponseEntity<TransactionIntent>> deposit(@Valid @RequestBody TransactionClientRequest request) {
CompletableFuture<TransactionIntent> depositIntentFuture =
transactionIntentFactory.createDepositIntent(
request.entity.id,
Money.of(CurrencyUnit.of(request.money.currency), request.money.amount));
return depositIntentFuture.thenApply(intent -> {
TransactionIntent publishedIntent = depositIntentService.attemptPublish(intent); //<-- causes error
ResponseEntity.ok(publishedIntent)
});
}
SERVICE:
@Component
@Repository
public abstract class TransactionIntentServiceImpl implements TransactionIntentService{
@Autowired
private TransactionIntentRepository transactionIntentRepo;
@Transactional
public TransactionIntent attemptPublish(TransactionIntent intent){
transactionIntentRepo.save(intent); //<-- Throws error: ...detached entity passed to persist
}
}
REPOSITORY
@Repository
public interface TransactionIntentRepository extends JpaRepository<TransactionIntent, Long>{
}
Any ideas how to support JPA persistance in an Async environment?
Thanks!
Update1
FACTORY
@Component
public class TransactionIntentFactory {
@Autowired
private UserService userService;
@Async("asyncExecutor")
public CompletableFuture<TransactionIntent> createDepositIntent(long beneficiaryId, Money money) {
CompletableFuture<User> bank = userService.findByUsername("bankItself@bank.com");
CompletableFuture<User> user = userService.find(beneficiaryId);
CompletableFuture<Void> allUserFutures = CompletableFuture.allOf(bank, user);
return allUserFutures.thenApply(it -> {
User userSource = bank.join();
User userBeneficiary = user.join();
TransactionIntent intent = new TransactionIntentBuilder()
.status(new TransactionIntentStatus(TRANSFER_STATUS.CREATED, "Deposit"))
.beneficiary(userBeneficiary)
.source(userSource)
.amount(money)
.build();
return intent;
});
}
}
ENTITY
@Entity
public class TransactionIntent {
@Id
@GeneratedValue
public long id;
public final Money amount;
public final Date createdAt;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionIntentStatus status;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity beneficiary; //to
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity source; //from
TransactionIntent(){
this.amount= null;
this.createdAt = null;
this.status = null;
this.beneficiary = null;
this.source = null;
}
public TransactionIntent(TransactionIntentBuilder builder) {
this.amount = builder.amount;
this.createdAt = new Date();
this.status = builder.status;
this.beneficiary = builder.beneficiary;
this.source = builder.source;
}
}
java spring hibernate spring-data-jpa h2
Using H2 and JPA my REST app worked well before Ansyc, but after implementation breaks the JPA persistence model.
Here is the case:
My repository has a method JpaRepository.save()
but when called from a separate thread, it throws InvalidDataAccessApiUsageException
error.
My Controller calls the Service which calls the Repository to insert a new object, and I get the following error:
InvalidDataAccessApiUsageException: detached entity passed to persist: TransactionalEntity; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: TransactionalEntity]
CONTROLLER:
@Autowired
@Qualifier("depositIntentService")
private TransactionIntentService depositIntentService;
@PostMapping("/services/transactions/deposit")
public CompletableFuture<ResponseEntity<TransactionIntent>> deposit(@Valid @RequestBody TransactionClientRequest request) {
CompletableFuture<TransactionIntent> depositIntentFuture =
transactionIntentFactory.createDepositIntent(
request.entity.id,
Money.of(CurrencyUnit.of(request.money.currency), request.money.amount));
return depositIntentFuture.thenApply(intent -> {
TransactionIntent publishedIntent = depositIntentService.attemptPublish(intent); //<-- causes error
ResponseEntity.ok(publishedIntent)
});
}
SERVICE:
@Component
@Repository
public abstract class TransactionIntentServiceImpl implements TransactionIntentService{
@Autowired
private TransactionIntentRepository transactionIntentRepo;
@Transactional
public TransactionIntent attemptPublish(TransactionIntent intent){
transactionIntentRepo.save(intent); //<-- Throws error: ...detached entity passed to persist
}
}
REPOSITORY
@Repository
public interface TransactionIntentRepository extends JpaRepository<TransactionIntent, Long>{
}
Any ideas how to support JPA persistance in an Async environment?
Thanks!
Update1
FACTORY
@Component
public class TransactionIntentFactory {
@Autowired
private UserService userService;
@Async("asyncExecutor")
public CompletableFuture<TransactionIntent> createDepositIntent(long beneficiaryId, Money money) {
CompletableFuture<User> bank = userService.findByUsername("bankItself@bank.com");
CompletableFuture<User> user = userService.find(beneficiaryId);
CompletableFuture<Void> allUserFutures = CompletableFuture.allOf(bank, user);
return allUserFutures.thenApply(it -> {
User userSource = bank.join();
User userBeneficiary = user.join();
TransactionIntent intent = new TransactionIntentBuilder()
.status(new TransactionIntentStatus(TRANSFER_STATUS.CREATED, "Deposit"))
.beneficiary(userBeneficiary)
.source(userSource)
.amount(money)
.build();
return intent;
});
}
}
ENTITY
@Entity
public class TransactionIntent {
@Id
@GeneratedValue
public long id;
public final Money amount;
public final Date createdAt;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionIntentStatus status;
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity beneficiary; //to
@OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity source; //from
TransactionIntent(){
this.amount= null;
this.createdAt = null;
this.status = null;
this.beneficiary = null;
this.source = null;
}
public TransactionIntent(TransactionIntentBuilder builder) {
this.amount = builder.amount;
this.createdAt = new Date();
this.status = builder.status;
this.beneficiary = builder.beneficiary;
this.source = builder.source;
}
}
java spring hibernate spring-data-jpa h2
java spring hibernate spring-data-jpa h2
edited Nov 12 at 11:46
Billy Frost
1,74798
1,74798
asked Nov 12 at 3:29
KasparTr
470321
470321
Are you setting the id of the TransactionIntent in the TransactionIntentFactory? If so, this could be the cause of this error. Having the code for the createDepositIntent factory method would be helpful. Providing the annotations/source for the TransactionIntent entity would be useful as well.
– C. Springer
Nov 12 at 4:52
@C.Springer The intent it is not set by me but is annotated w/ 'Id' and 'GeneratedValue' and so set by the db. Please see updates for the Factory and Entity code. Thanks
– KasparTr
Nov 12 at 5:11
The problem is that the TransactionalEntity (User) is attached on another thread than the TransactionIntent. When I remove the 'cascade=CascadeType.ALL' it doesn't throw the error. But doing so means I that there is a separate "persistence" on each thread. How can I operate on a single instance of the jpa persistance?
– KasparTr
Nov 12 at 11:55
I had a similar problem with a project using Spring Integration once upon a time. My solution as I remember it was to store just the id of the object being referenced in the database and defer actual retrieval to the code/thread actually doing the persistence. In your case, there would need to be some sort of pre-persist operation (presumably in attemptPublish) that would tell the TransactionIntent object to load the appropriate objects into the current HibernateSession and then persist the object.
– C. Springer
Nov 12 at 12:35
I wanted to add some food for thought here and suggest that you reconsider your heavy use of CompletableFuture altogether. For example, your service returns a CompletableFuture when retrieving User objects but then calls join(), thus being executed serially. In this case the future is added complexity. Perhaps another, more Hibernate-friendly, solution would involve the creation of some Serializable, throw-away value object that represents the pending transaction that could be passed across threads. The code in the future would then perform all persistence/lookup operations.
– C. Springer
Nov 12 at 13:17
add a comment |
Are you setting the id of the TransactionIntent in the TransactionIntentFactory? If so, this could be the cause of this error. Having the code for the createDepositIntent factory method would be helpful. Providing the annotations/source for the TransactionIntent entity would be useful as well.
– C. Springer
Nov 12 at 4:52
@C.Springer The intent it is not set by me but is annotated w/ 'Id' and 'GeneratedValue' and so set by the db. Please see updates for the Factory and Entity code. Thanks
– KasparTr
Nov 12 at 5:11
The problem is that the TransactionalEntity (User) is attached on another thread than the TransactionIntent. When I remove the 'cascade=CascadeType.ALL' it doesn't throw the error. But doing so means I that there is a separate "persistence" on each thread. How can I operate on a single instance of the jpa persistance?
– KasparTr
Nov 12 at 11:55
I had a similar problem with a project using Spring Integration once upon a time. My solution as I remember it was to store just the id of the object being referenced in the database and defer actual retrieval to the code/thread actually doing the persistence. In your case, there would need to be some sort of pre-persist operation (presumably in attemptPublish) that would tell the TransactionIntent object to load the appropriate objects into the current HibernateSession and then persist the object.
– C. Springer
Nov 12 at 12:35
I wanted to add some food for thought here and suggest that you reconsider your heavy use of CompletableFuture altogether. For example, your service returns a CompletableFuture when retrieving User objects but then calls join(), thus being executed serially. In this case the future is added complexity. Perhaps another, more Hibernate-friendly, solution would involve the creation of some Serializable, throw-away value object that represents the pending transaction that could be passed across threads. The code in the future would then perform all persistence/lookup operations.
– C. Springer
Nov 12 at 13:17
Are you setting the id of the TransactionIntent in the TransactionIntentFactory? If so, this could be the cause of this error. Having the code for the createDepositIntent factory method would be helpful. Providing the annotations/source for the TransactionIntent entity would be useful as well.
– C. Springer
Nov 12 at 4:52
Are you setting the id of the TransactionIntent in the TransactionIntentFactory? If so, this could be the cause of this error. Having the code for the createDepositIntent factory method would be helpful. Providing the annotations/source for the TransactionIntent entity would be useful as well.
– C. Springer
Nov 12 at 4:52
@C.Springer The intent it is not set by me but is annotated w/ 'Id' and 'GeneratedValue' and so set by the db. Please see updates for the Factory and Entity code. Thanks
– KasparTr
Nov 12 at 5:11
@C.Springer The intent it is not set by me but is annotated w/ 'Id' and 'GeneratedValue' and so set by the db. Please see updates for the Factory and Entity code. Thanks
– KasparTr
Nov 12 at 5:11
The problem is that the TransactionalEntity (User) is attached on another thread than the TransactionIntent. When I remove the 'cascade=CascadeType.ALL' it doesn't throw the error. But doing so means I that there is a separate "persistence" on each thread. How can I operate on a single instance of the jpa persistance?
– KasparTr
Nov 12 at 11:55
The problem is that the TransactionalEntity (User) is attached on another thread than the TransactionIntent. When I remove the 'cascade=CascadeType.ALL' it doesn't throw the error. But doing so means I that there is a separate "persistence" on each thread. How can I operate on a single instance of the jpa persistance?
– KasparTr
Nov 12 at 11:55
I had a similar problem with a project using Spring Integration once upon a time. My solution as I remember it was to store just the id of the object being referenced in the database and defer actual retrieval to the code/thread actually doing the persistence. In your case, there would need to be some sort of pre-persist operation (presumably in attemptPublish) that would tell the TransactionIntent object to load the appropriate objects into the current HibernateSession and then persist the object.
– C. Springer
Nov 12 at 12:35
I had a similar problem with a project using Spring Integration once upon a time. My solution as I remember it was to store just the id of the object being referenced in the database and defer actual retrieval to the code/thread actually doing the persistence. In your case, there would need to be some sort of pre-persist operation (presumably in attemptPublish) that would tell the TransactionIntent object to load the appropriate objects into the current HibernateSession and then persist the object.
– C. Springer
Nov 12 at 12:35
I wanted to add some food for thought here and suggest that you reconsider your heavy use of CompletableFuture altogether. For example, your service returns a CompletableFuture when retrieving User objects but then calls join(), thus being executed serially. In this case the future is added complexity. Perhaps another, more Hibernate-friendly, solution would involve the creation of some Serializable, throw-away value object that represents the pending transaction that could be passed across threads. The code in the future would then perform all persistence/lookup operations.
– C. Springer
Nov 12 at 13:17
I wanted to add some food for thought here and suggest that you reconsider your heavy use of CompletableFuture altogether. For example, your service returns a CompletableFuture when retrieving User objects but then calls join(), thus being executed serially. In this case the future is added complexity. Perhaps another, more Hibernate-friendly, solution would involve the creation of some Serializable, throw-away value object that represents the pending transaction that could be passed across threads. The code in the future would then perform all persistence/lookup operations.
– C. Springer
Nov 12 at 13:17
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255602%2fspring-async-breaks-jpa-detached-entity-passed-to-persist%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Are you setting the id of the TransactionIntent in the TransactionIntentFactory? If so, this could be the cause of this error. Having the code for the createDepositIntent factory method would be helpful. Providing the annotations/source for the TransactionIntent entity would be useful as well.
– C. Springer
Nov 12 at 4:52
@C.Springer The intent it is not set by me but is annotated w/ 'Id' and 'GeneratedValue' and so set by the db. Please see updates for the Factory and Entity code. Thanks
– KasparTr
Nov 12 at 5:11
The problem is that the TransactionalEntity (User) is attached on another thread than the TransactionIntent. When I remove the 'cascade=CascadeType.ALL' it doesn't throw the error. But doing so means I that there is a separate "persistence" on each thread. How can I operate on a single instance of the jpa persistance?
– KasparTr
Nov 12 at 11:55
I had a similar problem with a project using Spring Integration once upon a time. My solution as I remember it was to store just the id of the object being referenced in the database and defer actual retrieval to the code/thread actually doing the persistence. In your case, there would need to be some sort of pre-persist operation (presumably in attemptPublish) that would tell the TransactionIntent object to load the appropriate objects into the current HibernateSession and then persist the object.
– C. Springer
Nov 12 at 12:35
I wanted to add some food for thought here and suggest that you reconsider your heavy use of CompletableFuture altogether. For example, your service returns a CompletableFuture when retrieving User objects but then calls join(), thus being executed serially. In this case the future is added complexity. Perhaps another, more Hibernate-friendly, solution would involve the creation of some Serializable, throw-away value object that represents the pending transaction that could be passed across threads. The code in the future would then perform all persistence/lookup operations.
– C. Springer
Nov 12 at 13:17