Spring Boot与应用程序管理的持久性上下文

问题描述 投票:3回答:2

我正在尝试从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
    -------------------------------------------

    &ltpersistence-unit name="PU1" transaction-type="JTA">

        &ltproperties>

            &lt!-- comment for spring to handle transaction??? -->
            &lt!--property name="eclipselink.target-server" value="WebLogic_10"/ -->
        &lt/properties>

    &lt/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在设计时间内不为人所知?

谢谢。

jpa spring-boot transactions eclipselink
2个回答
0
投票

您自己几乎已经回答了这个问题:“当使用适当的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();

0
投票

我终于得到了它:

  1. 启用tomcat JNDI并以编程方式为每个DS创建数据源JNDI
  2. 添加交易内容 com.atomikos:transactions-eclipselink:3.9.3(我的项目使用eclipselink而不是hibernate) org.springframework.boot:spring-boot-starter-jta-atomikos org.springframework:spring-tx
© www.soinside.com 2019 - 2024. All rights reserved.