我正在尝试从EJB3 + JTA + JPA(EclipseLink)迁移应用程序。目前,该应用程序利用应用程序管理的持久上下文,因为设计时间数据库数量未知。
应用程序管理的持久化上下文允许我们控制如何创建EntityManager(例如,提供不同的数据源JNDI以在运行时为特定的DB创建正确的EntityManager)。
EG
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();
当部署在EJB容器(例如WebLogic)中时,使用适当的TransactionAttribute(例如TransactionAttributeType.REQUIRED),容器将负责事务的开始/结束/回滚。
现在,我正在尝试将此应用程序迁移到Spring Boot。我遇到的问题是,即使我用@Transactional(propagation = Propagation.REQUIRED)
注释方法后也没有启动事务。
Spring应用程序打包为可执行的JAR文件,并使用嵌入式Tomcat运行。
当我尝试执行这些更新API时,例如EntityManager.persist(..)
,EclipseLink总是抱怨:
javax.persistence.TransactionRequiredException:'当前没有事务处于活动状态'
示例代码如下:
//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 -------------------------------------------
我的使用模式并不遵循大多数典型用例(例如,使用已知数量的DB - Spring + JPA + multiple persistence units: Injecting EntityManager)。
有人可以就如何解决这个问题给我建议吗?
有没有人曾经遇到这种情况,DB在设计时间内不为人所知?
谢谢。
您自己几乎已经回答了这个问题:“当使用适当的TransactionAttribute(例如TransactionAttributeType.REQUIRED)部署在EJB容器(例如WebLogic)中时,容器将负责事务的开始/结束/回滚”。
WebLogic符合Java Enterprise Edition规范,这可能是它以前工作的原因,但现在您使用的是Tomcat(在嵌入模式下)。所以你根本无法做你想做的事。 persistence.xml文件中的此语句:
<persistence-unit name="PU1" transaction-type="JTA">
需要Enterprise Server(WebLogic,Glassfish,JBoss等)
使用Tomcat,您只能这样做:
<persistence-unit name="PU1" transaction-type="RESOURCE_LOCAL">
而且你需要自己处理交易:
myEntityManager.getTransaction.begin();
... //Do your transaction stuff
myEntityManager.getTransaction().commit();
我终于得到了它:
com.atomikos:transactions-eclipselink:3.9.3
(我的项目使用eclipselink而不是hibernate)
org.springframework.boot:spring-boot-starter-jta-atomikos
org.springframework:spring-tx