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

时间:2017-07-11 12:23:52

标签: jpa spring-boot transactions eclipselink

我正在尝试从EJB3 + JTA + JPA(EclipseLink)迁移应用程序。目前,该应用程序利用应用程序管理的持久上下文,因为设计时间数据库数量未知。

应用程序管理的持久化上下文允许我们控制如何创建EntityManager(例如提供不同的数据源JNDI以在运行时为特定的DB创建正确的EntityManager )。

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();

当使用适当的TransactionAttribute(例如TransactionAttributeType.REQUIRED)部署在EJB容器(例如WebLogic)中时,容器将负责事务的开始/结束/回滚。

现在,我正在尝试将此应用程序迁移到Spring Boot。 我遇到的问题是,即使我使用@Transactional(propagation = Propagation.REQUIRED)注释方法,也没有启动任何事务。

Spring应用程序打包为可执行JAR文件,并使用embadded 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
    -------------------------------------------

我的使用模式并未遵循大多数典型用例(例如,使用已知数量的数据库 - Spring + JPA + multiple persistence units: Injecting EntityManager)。

有人可以就如何解决这个问题给我建议吗?

有没有人遇到这种情况,设计时间内不了解DB?

谢谢。

2 个答案:

答案 0 :(得分:0)

您自己已经回答了很多问题:“ 当部署在具有适当TransactionAttribute(例如TransactionAttributeType.REQUIRED)的EJB容器(例如WebLogic)中时,该容器将负责事务的开始/结束/回滚”。

WebLogic符合Java Enterprise Edition规范,这也许是它以前能工作的原因,但是现在您正在使用Tomcat(以嵌入式模式),而现在还没有。 因此,您根本无法做您想做的事情。 您的persistence.xml文件中的以下语句:

<persistence-unit name="PU1" transaction-type="JTA">

需要企业服务器(WebLogic,Glassfish,JBoss等)

使用Tomcat,您只能这样做:

<persistence-unit name="PU1" transaction-type="RESOURCE_LOCAL">

您需要自己处理交易:

myEntityManager.getTransaction.begin();
... //Do your transaction stuff
myEntityManager.getTransaction().commit();

答案 1 :(得分:0)

我终于可以使用它了:

  1. 启用tomcat JNDI并以编程方式为每个DS创建数据源JNDI
  2. 添加交易内容

    • com.atomikos:transactions-eclipselink:3.9.3(我的项目使用eclipselink而不是休眠)

    • org.springframework.boot:spring-boot-starter-jta-atomikos

    • org.springframework:spring-tx