【问题标题】:How to configure EJB/JPA in JTA transaction mode?JTA事务模式下如何配置EJB/JPA?
【发布时间】:2022-01-05 01:29:50
【问题描述】:

这是配置 JPA 和使用 JTA 事务模式连接到数据库的简单指南。它还包括开发人员最常见的错误,您应该避免它们。 希望对您有所帮助。

【问题讨论】:

    标签: jpa glassfish ejb jta payara


    【解决方案1】:

    1- 在您的应用服务器中设置数据源: 为了使用 JTA 模式在您的 WebApp 中配置 JPA,您首先需要设置一个 DataSource。您可以从应用程序服务器(Glassfish / Payara / ...)设置数据源。但建议通过您的 Web 应用程序设置数据源。按照以下步骤通过 Maven WebApp 为 Glassfish 或 Payara 设置数据源:

    1. 在您的项目文件夹中创建一个名为“setup”的新文件夹(不是包)。
    2. 创建一个新的 xml 文件并将其命名为“glassfish-resources.xml”并将其保存在“setup”文件夹中。并写入以下内容:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
    <resources>
        <jdbc-resource enabled="true" jndi-name="**jdbc/DBDev01**" object-type="user" pool-name="**jdbc/DBDev01-ConnectionPool**">
        <description/>
      </jdbc-resource>
       <jdbc-connection-pool allow-non-component-callers="false" 
                            associate-with-thread="false" connection-creation-retry-attempts="0" 
                            connection-creation-retry-interval-in-seconds="10" 
                            connection-leak-reclaim="false" 
                            connection-leak-timeout-in-seconds="0" 
                            connection-validation-method="auto-commit" 
                            datasource-classname="**org.mariadb.jdbc.MariaDbDataSource**" 
                            fail-all-connections="false" 
                            idle-timeout-in-seconds="300" 
                            is-connection-validation-required="false" 
                            is-isolation-level-guaranteed="true" 
                            lazy-connection-association="false" 
                            lazy-connection-enlistment="false" 
                            match-connections="false" 
                            max-connection-usage-count="0" 
                            max-pool-size="32" 
                            max-wait-time-in-millis="60000" 
                            name="**jdbc/DBDev01-ConnectionPool**" 
                            non-transactional-connections="false" 
                            pool-resize-quantity="2" 
                            res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
    <!-- for MariaDB users, it recomended to add ?useMysqlMetadata=true, this will make MariaDB pretending that it is a MySQL for tools or libraries that not support MariaDB -->    
    <property name="URL" value="**jdbc:mariadb://XXX.XXX.XXX.XXX:XXXX/DB_NAME?useMysqlMetadata=true**"/>
        <property name="User" value="**USERNAME**"/>
        <property name="Password" value="**PASSWORD**"/>
      </jdbc-connection-pool>
    </resources>
    

    注意: ** ** 之间的所有值都应根据您的设置进行修改。 在部署您的 webapp 后,该文件将由您的应用程序服务器 (Glassfish/Payara) 加载。对于 Payara 用户,您还可以将文件命名为“payara-resources.xml”,但只需稍作修改。参考:Payara Deployment Descriptors.

    2- 为 WEB-INF/web.xml 中的数据源添加资源引用: 您需要通过在 WEB-INF/web.xml 文件中添加以下内容来为 Webapp 中的 DataSource 添加资源引用:

    <web-app .....>
      ......
    
    <resource-ref>
      <description>**DBDev01**</description>
      <res-ref-name>**jdbc/DBDev01**</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
      <!-- <res-sharing-scope>Shareable</res-sharing-scope> -->
    </resource-ref>
    </web-app>
    

    注意:res-ref-name 应该与您在 glassfish 资源文件中为数据源选择的名称完全匹配。

    3- 配置 Persistence.xml 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
        <persistence-unit name="**MyDB**" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <!--  List all Entity classes  -->
        <class>**com.MyEntityClassName**</class>
    
        <jta-data-source>**jdbc/DBDev01**</jta-data-source>
    <!--  you can list all entity classes you need and set this value to true. or set this value to false to include other entity clases  -->
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
    
    <properties>
                 <!-- while eclipselink not support MariaDB , set this property to enforce eclipselink to work with it as MySQL -->
                <property name="eclipselink.target-database" value="MySQL"/>
            </properties>
      </persistence-unit>
      </persistence>
    

    注意1:如果你想使用JTA作为交易类型,那么你必须定义jta-data-source。开发人员在未定义 JTA 数据源的情况下尝试连接数据库的属性中添加 DB URL、用户名和密码是一个常见错误。这将不起作用,并且会导致您的应用程序服务器使用已定义的默认数据源,该数据源通常是 H2 数据库。

    注意 2: eclipselink(JPA 库)不支持 MariaDB。但是有一个解决方法。 解决方案 1::在您的连接 URL 上添加“?useMysqlMetadata=true”作为后缀,例如:&lt;property name="URL" value="**jdbc:mariadb://XXX.XXX.XXX.XXX:XXXX/DB_NAME?useMysqlMetadata=true"/&gt; 这将使 MariaDB 假装它是 MySQL。 解决方案2: 强制eclipselink 将数据库作为MySQL 处理。这可以通过在 persistence.xml 中设置eclipselink.target-database 属性来完成,如下所示:

    <properties>
             <!-- while eclipselink not support MariaDB , set this property to enforce eclipselink to work with it as MySQL -->
            <property name="eclipselink.target-database" value="MySQL"/>
        </properties>
    

    4- 在 POM.xml 中添加 JDBC 客户端作为依赖项:

    <dependency>
    <!--  This is for MariaDB. You should change it if you are using other kind of DB like MySQL or Oracle DB  -->
        <groupId>org.mariadb.jdbc</groupId>
        <artifactId>mariadb-java-client</artifactId>
        <version>2.7.2</version>
    </dependency>
    

    5- 享受您的代码: 写一个 sessionBean:

    @Stateless
    public class StudentManager
    {
    /* Notes: 
    1.you should use the same name exactly that defined in Persistence.xml file.
    2.You can not use @PersistenceUnit with JTA. only use @PersistenceContext with JTA.
    */
    
        @PersistenceContext(unitName="MyDB")
        private EntityManager em;
        
        public StudentManager()
        {
            
        }
        
        public void persist(Student student) {
            
            em.persist(student);
        }    
    }
    

    编写TestController:

    @Named
    @SessionScoped
    public class TestController
    {
        @Inject
        private StudentManager studentManager;
        private String message = "";
        
        public void test()
        {
            Student student = new Student();
       
            Student.setCode(11223344);
            Student.setName("John");
            
            studentManager.persist(Student); 
    /*Note:we used studentManager directly without constructing.
    writing studentManager = new StudentManager() is a common mistake and will lead you to get a null EntityManager.*/
            this.setMessage("A new Student already saved successful with Code:" + Student.getCode());
        }
    

    常见问题:应该使用@Inject 还是@EJB? here is the answer

    一个简单的 JSF 测试页面:

    <?xml version='1.0' encoding='UTF-8' ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://xmlns.jcp.org/jsf/html">
        <h:head>
            <title>Facelet Title</title>
        </h:head>
        <h:body>
            <h:form>
                 <h:commandButton value="Test Save a Student over JTA" action="#{testController.test()}" />
                 <br />
                 <h:outputLabel for="message" value="#{test.message}" />
            </h:form>
    
        </h:body>
    </html>
    
    

    【讨论】:

      猜你喜欢
      • 2013-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-23
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      相关资源
      最近更新 更多