0

My upper service class is injected with several services as below:

@Service
@Slf4j
public class LoadService implements ILoadService {

 @Autowired LoadService1 loadService1;

 @Autowired LoadService2 loadService2;

 @Autowired LoadService3 loadService3;

 @Autowired GeneralService generalService;

 @Override
 public int load123() {
   loadService1.load();
   loadService2.load();
   loadService3.load();
 }

While loadService2.load() was executing, I got errors

InvalidDataAccessApiUsageException: detached entity passed to persist: class1

where class2 should be persisted, which has one-to-one relation to class1. and

InvalidDataAccessApiUsageException: detached entity passed to persist .LazyInitializationException: failed to lazily initialize a collection of role

where class3 has a many-to-one relation to class1.

(It was also wired that all load functions from loadServices are almosst the same, but the error only occurred in loadService2)

I understand the error in this way, that the proxies were somehow closed, I found a solution was simply adding @Transactinal upon the upper Service class. Which was not my intention, because I still want to have part of the data even when error occurred.

Does anybody know how to keep the proxies active without setting transactinal! Thanks a lot!

heisthere
  • 374
  • 1
  • 12

1 Answers1

0

I found a solution was simply adding @Transactinal upon the upper Service class. Which was not my intention, because I still want to have part of the data even when error occurred.

You should be able to still achieve this goal using @Transactional(propagation = REQUIRES_NEW) on one or more of the load() methods.

Otherwise, it is possible with an extended-scope EntityManager, but you need to ask yourself what exactly constitutes the lifecycle boundary of the associated PersistenceContext, if not a transaction. It is generally a bad idea to keep such a context open indefinitely.

crizzis
  • 9,978
  • 2
  • 28
  • 47
  • Mmmmh the job of load does, is to load data to database. What i actually meant was, data should be loaded into database until error comes. So I would not like to use transaction at all, even for every single loads – heisthere Feb 14 '22 at 11:44
  • In that case, your starting point will be [here](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/jpa/ExtendedEntityManagerCreator.html). However, I would still caution against ditching transactions completely. You should instead identify the smallest consistent DB change and wrap that change in a `@Transactional` method. Also, if this is a batch DB data loading job, perhaps JPA is not the best of choices due to the overheads it introduces. You might be better off with plain old JDBC. – crizzis Feb 14 '22 at 11:55
  • I think you are right. I should have somehow wrapped it with transaction from smallest point. At the end, I found the main problem was the owner of one-to-one relation? Because in loadService2.load, I saved class2 with class2Repository.save(), where class1 was actually the owner of the relation. So I changed that to class1Repository.save(class1), and problem solved. I still feel wired, because loadService1.load saves class2 by class2Repository.save() and has no problem, any idea? – heisthere Feb 14 '22 at 13:26
  • Difficult to tell without looking at the actual entities and their cascade options – crizzis Feb 14 '22 at 15:15