I am trying to migrate an application from EJB3 + JTA + JPA (EclipseLink). Currently, this application makes use of application managed persistent context due to an unknown number of databases on design time.
The application managed persistent context allows us to control how to create EntityManager (e.g. supply different datasources JNDI to create proper EntityManager for specific DB on runtime).
E.g.
Map properties = new HashMap(); properties.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA"); //the datasource JNDI is by configuration and without prior knowledge about the number of databases //currently, DB JNDI are stored in a externalized file //the datasource is setup by operation team properties.put(PersistenceUnitProperties.JTA_DATASOURCE, "datasource-jndi"); properties.put(PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false"); properties.put(PersistenceUnitProperties.SESSION_NAME, "xxx"); //create the proper EntityManager for connect to database decided on runtime EntityManager em = Persistence.createEntityManagerFactory("PU1", properties).createEntityManager(); //query or update DB em.persist(entity); em.createQuery(...).executeUpdate();
When deployed in a EJB container (e.g. WebLogic), with proper TransactionAttribute (e.g. TransactionAttributeType.REQUIRED), the container will take care of the transaction start/end/rollback.
Now, I am trying to migrate this application to Spring Boot.
The problem I encounter is that there is no transaction started even after I annotate the method with @Transactional(propagation = Propagation.REQUIRED)
.
The Spring application is packed as an executable JAR file and run with embadded Tomcat.
When I try to execute those update APIs, e.g. EntityManager.persist(..)
, EclipseLink always complains about:
javax.persistence.TransactionRequiredException: 'No transaction is currently active'
Sample code below:
//for data persistence @Service class DynamicServiceImpl implements DynamicService { //attempt to start a transaction @Transactional(propagation = Propagation.REQUIRED) public void saveData(DbJndi, EntityA){ //this return false that no transaction started TransactionSynchronizationManager.isActualTransactionActive(); //create an EntityManager based on the input DbJndi to dynamically //determine which DB to save the data EntityManager em = createEm(DbJndi); //save the data em.persist(EntityA); } } //restful service @RestController class RestController{ @Autowired DynamicService service; @RequestMapping( value = "/saveRecord", method = RequestMethod.POST) public @ResponseBody String saveRecord(){ //save data service.saveData(...) } } //startup application @SpringBootApplication class TestApp { public static void main(String[] args) { SpringApplication.run(TestApp.class, args); } } persistence.xml ------------------------------------------- <persistence-unit name="PU1" transaction-type="JTA"> <properties> <!-- comment for spring to handle transaction??? --> <!--property name="eclipselink.target-server" value="WebLogic_10"/ --> </properties> </persistence-unit> ------------------------------------------- application.properties (just 3 lines of config) ------------------------------------------- spring.jta.enabled=true spring.jta.log-dir=spring-test # Transaction logs directory. spring.jta.transaction-manager-id=spring-test -------------------------------------------
My usage pattern does not follow most typical use cases (e.g. with known number of DBs - Spring + JPA + multiple persistence units: Injecting EntityManager).
Can anybody give me advice on how to solve this issue?
Is there anybody who has ever hit this situation that the DBs are not known in design time?
Thank you.