Hibernate JPA 与 JTA 和 Glassfish 应用服务器似乎没有提交

发布于 2024-11-27 01:27:54 字数 5293 浏览 3 评论 0原文

我是 hibernate 的新手,我希望它通过 JNDI 使用来自应用程序服务器的数据库连接。

奇怪的是,它在数据库中创建我的表,但不保存实体。看来,它并没有承诺。

有人在使用 hibernate 时遇到过类似的问题吗?

这是一个小测试 servlet:

public class WriteTest extends HttpServlet
{
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    {
        /*try
        { 
            User user = new User("Hans", "Maulwurf", "[email protected]");

            InitialContext ctx = new InitialContext();
            UserFacadeBean bean = (UserFacadeBean) ctx.lookup("ejb/UserFacadeBeanService");
            bean.persist(user);
        }
        catch (NamingException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/

        EntityManager em = JpaUtil.getEntityManagerFactory().createEntityManager();
        //em.getTransaction().begin();

        System.out.println("Begin transfer");

        User user = new User("Hans", "Maulwurf", "[email protected]");
        Adress adress = new Adress("Deppenstraße 3","Deppingen");
        //user.setAddress(adress);

        System.out.println("Save User 'Hans Maulwurf'");

        em.persist(user);
        //em.persist(adress);
        //em.getTransaction().commit();
        em.close();

        System.out.println("Everything went better than expected!");
    }
}

这是一个小助手类:

public class JpaUtil
{
    private static final EntityManagerFactory emf;

    static
    {
        try
        {
            System.out.println("Initialize EntityManagerFactory...");
            emf = Persistence.createEntityManagerFactory("testPU");
        }
        catch (Throwable ex)
        {
            System.err.println("Initial EntityManagerFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static EntityManagerFactory getEntityManagerFactory()
    {
        return emf;
    }
}

我的用户对象:

@Entity
@Table(name = "T_UserJpa")
public class User implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Embedded
    @AttributeOverrides(
    {
        @AttributeOverride(name = "street", column =
        @Column(name = "user_street")),
        @AttributeOverride(name = "city", column =
        @Column(name = "user_city", length = 50))
    })
    private Adress adress;
    private String firstname;
    private String lastname;
    private String email;

    public User()
    {
    }

    public User(String firstname, String lastname, String email)
    {
        this.firstname = firstname;
        this.lastname = lastname;
        this.email = email;
    }

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public Adress getAddress()
    {
        return adress;
    }

    public void setAddress(Adress adress)
    {
        this.adress = adress;
    }

    public String getFirstname()
    {
        return firstname;
    }

    public void setFirstname(String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname()
    {
        return lastname;
    }

    public void setLastname(String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (!(obj instanceof User))
        {
            return false;
        }
        final User user = (User) obj;
        return !(email != null ? !email.equals(user.email) : user.email != null);
    }

    @Override
    public int hashCode()
    {
        return 29 * (email != null ? email.hashCode() : 0);
    }
}

我的 persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
  <persistence-unit name="testPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/testdb</jta-data-source>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.autocommit" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

编辑: 我忘了提及,我已经使用了此线程中提供的信息: 在 Glassfish 上配置 Hibernate JPA 2.0 的学习资源服务器

I'm new to hibernate and I want it to use the database connection from the application server via JNDI.

The Strange thing is, that it creates my tables in the database but it doesn't save the entity. It seems, that it doesn't commit.

Has someone experienced similar problems with hibernate?

This is a little test-servlet:

public class WriteTest extends HttpServlet
{
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    {
        /*try
        { 
            User user = new User("Hans", "Maulwurf", "[email protected]");

            InitialContext ctx = new InitialContext();
            UserFacadeBean bean = (UserFacadeBean) ctx.lookup("ejb/UserFacadeBeanService");
            bean.persist(user);
        }
        catch (NamingException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/

        EntityManager em = JpaUtil.getEntityManagerFactory().createEntityManager();
        //em.getTransaction().begin();

        System.out.println("Begin transfer");

        User user = new User("Hans", "Maulwurf", "[email protected]");
        Adress adress = new Adress("Deppenstraße 3","Deppingen");
        //user.setAddress(adress);

        System.out.println("Save User 'Hans Maulwurf'");

        em.persist(user);
        //em.persist(adress);
        //em.getTransaction().commit();
        em.close();

        System.out.println("Everything went better than expected!");
    }
}

This is the little helper-class:

public class JpaUtil
{
    private static final EntityManagerFactory emf;

    static
    {
        try
        {
            System.out.println("Initialize EntityManagerFactory...");
            emf = Persistence.createEntityManagerFactory("testPU");
        }
        catch (Throwable ex)
        {
            System.err.println("Initial EntityManagerFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static EntityManagerFactory getEntityManagerFactory()
    {
        return emf;
    }
}

My user-object:

@Entity
@Table(name = "T_UserJpa")
public class User implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Embedded
    @AttributeOverrides(
    {
        @AttributeOverride(name = "street", column =
        @Column(name = "user_street")),
        @AttributeOverride(name = "city", column =
        @Column(name = "user_city", length = 50))
    })
    private Adress adress;
    private String firstname;
    private String lastname;
    private String email;

    public User()
    {
    }

    public User(String firstname, String lastname, String email)
    {
        this.firstname = firstname;
        this.lastname = lastname;
        this.email = email;
    }

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public Adress getAddress()
    {
        return adress;
    }

    public void setAddress(Adress adress)
    {
        this.adress = adress;
    }

    public String getFirstname()
    {
        return firstname;
    }

    public void setFirstname(String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname()
    {
        return lastname;
    }

    public void setLastname(String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (!(obj instanceof User))
        {
            return false;
        }
        final User user = (User) obj;
        return !(email != null ? !email.equals(user.email) : user.email != null);
    }

    @Override
    public int hashCode()
    {
        return 29 * (email != null ? email.hashCode() : 0);
    }
}

My persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
  <persistence-unit name="testPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/testdb</jta-data-source>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.autocommit" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

Edit: I forgot to mention, that I already used the information provided in this thread: Learning resource for Configuring Hibernate JPA 2.0 on Glassfish server

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

断爱 2024-12-04 01:27:55

您应该使用容器提供的事务支持。这是 Pro JPA 2 Mastering the Java Persistence API 一书中的示例。我希望这有帮助:

public class EmployeeServlet extends HttpServlet {
    @PersistenceUnit(unitName="EmployeeService")
    EntityManagerFactory emf;
    @Resource UserTransaction tx;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // ...
        int id = Integer.parseInt(request.getParameter("id"));
        String name = request.getParameter("name");
        long salary = Long.parseLong(request.getParameter("salary"));
        tx.begin();
        EntityManager em = emf.createEntityManager();
        try {
            EmployeeService service = new EmployeeService(em);
            service.createEmployee(id, name, salary);
        } finally {
            em.close();
        }
        tx.commit();
        // ...
    }
}

You should use the transaction support provided by the container. This is an examples from the book Pro JPA 2 Mastering the Java Persistence API. I hope this helps:

public class EmployeeServlet extends HttpServlet {
    @PersistenceUnit(unitName="EmployeeService")
    EntityManagerFactory emf;
    @Resource UserTransaction tx;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // ...
        int id = Integer.parseInt(request.getParameter("id"));
        String name = request.getParameter("name");
        long salary = Long.parseLong(request.getParameter("salary"));
        tx.begin();
        EntityManager em = emf.createEntityManager();
        try {
            EmployeeService service = new EmployeeService(em);
            service.createEmployee(id, name, salary);
        } finally {
            em.close();
        }
        tx.commit();
        // ...
    }
}
薯片软お妹 2024-12-04 01:27:55

本指南用于在 NetBeans.8.0 IDE 中集成 hibernate.4.3.5 和 EJB、JTA 以及 GlassFish.4.0。在net beans中创建一个web项目(注意:不要用maven制作web项目,因为Netbeans.8.0 IDE中有一个bug)并将hibernate jar文件添加到项目中,其他与配置MySql和glassfish相关的设置非常简单(只需在资源> JDBC:JDBC 连接池和 JDBC 资源中定义连接池和 JDBC,如果您搜索的话可以在网上找到相关指南)(注意:为了定义正确的 JNDI,首先创建一个临时的 JNDI)。依赖于 JNDI 的项目,例如 glassfish 中的 JPA 项目,然后复制在 Glassfish 中为此项目创建的设置,因为在创建第一个连接池时,当您要在创建第一个连接池时对 MySQl 执行 ping 操作时,glassfish 中存在一个错误你自己在 glassfish 中),所以我不会在本文中描述,然后创建 persistence.xml 文件,如下所示:

<persistence-unit name="omidashouriPU" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/yourJNDI (which you defined in glassfish) </jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.connection.driver_class"  value="com.mysql.jdbc.Driver"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/YourSchemaName"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="yourpassword"/>
            <property name="hibernate.show_sql" value="true"/>
    </properties>
</persistence-unit>

在用于创建 EntityManager 的 EJB 类(用 @Stateless 注释的类)中,使用以下语法:

@PersistenceContext(unitName = " omidashouriPU ")
EntityManager em;
em.persist(YourEntityObject);

如您所知,当您使用“transaction-type =“JTA”,事务的管理不由您负责,这意味着,管理打开和关闭事务是应用程序服务器(此处为GlassFish)的责任。事实上,如果你在模式设计中检查 persistence.xml,在持久化提供者下拉框前面你可以看到现在添加了 hibernate。

This guidance is for integrating hibernate.4.3.5 and EJB and JTA and GlassFish.4.0 in NetBeans.8.0 IDE. Create a web project in net beans (attention: do not make web project with maven because there is a bug in Netbeans.8.0 IDE ) and add hibernate jar files to the project, other setting related to configuring MySql and glassfish is very simple(Just define Connection Pool and JDBC in Resources>JDBC:JDBC Connection Pools & JDBC Resources, guidance for that is in the web if you search for it)(attention: for defining a correct JNDI, first create a temporary project which depends on JNDI like JPA project in glassfish, then copy the settings that is created in Glassfish for this Project because there is a bug in glassfish when you are going to get a ping to MySQl in creating your first Connection Pool if you create it by yourself inside the glassfish) so I do not describe in this article then create persistence.xml file as follow :

<persistence-unit name="omidashouriPU" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/yourJNDI (which you defined in glassfish) </jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.connection.driver_class"  value="com.mysql.jdbc.Driver"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/YourSchemaName"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="yourpassword"/>
            <property name="hibernate.show_sql" value="true"/>
    </properties>
</persistence-unit>

In Your EJB class (class that annotated with @Stateless) for creating EntityManager use following syntax :

@PersistenceContext(unitName = " omidashouriPU ")
EntityManager em;
em.persist(YourEntityObject);

As you Know when you are using “transaction-type="JTA", management of transaction is not with you, mean that, managing of opening and closing the transaction is application server (Here GlassFish) responsibility. Indeed if you check your persistence.xml in mode design, in front of persistence provider drop down box you can see hibernate is now added.

在你怀里撒娇 2024-12-04 01:27:55

当您手动提交更改时(即取消注释提交行时),它是否会提交?

设置

还可以尝试检查您的配置是否通过toggleAutoCommit = session.connection().getAutoCommit();

Does it commit when you maunally commit your changed ie when you uncomment the commit line?

Also try checking you configuration is being set by

toggleAutoCommit = session.connection().getAutoCommit();

忘羡 2024-12-04 01:27:54

在应用程序服务器中,您可以拥有容器管理的 EntityManager(也称为持久性上下文)或应用程序管理的 EntityManager。在这两种情况下,您都必须将持久性上下文与事务关联起来,该事务可以是 JTA 事务,也可以是普通 JDBC 事务。

对于您当前的问题,应考虑以下几点:

  • 您的 persistence.xml 文件表明您打算使用 JTA 数据源,因此使用 JTA 事务来执行事务工作。
  • 此外,您的 JpaUtil 类负责创建应用程序管理的 EntityManager 实例。

根据上述两条语句以及您的应用程序演示的行为,您的 EntityManager 实例似乎未与 JTA 事务关联。因此,在持久性上下文中所做的任何更改都不会被刷新到数据库。这仅仅是因为 JPA 提供者将依赖 JTA 事务和征用的资源来执行事务工作;如果没有找到,则不会完成任何工作(与资源本地事务的情况不同,其中连接池和资源登记由 JPA 提供程序本身执行)。

因此,要点是,在对实体执行任何更改之前,EntityManager 或持久性上下文必须与活动事务关联,以便可以刷新对持久性上下文中的实体所做的所有更改到数据库。要解决您的问题,您必须:

  • 启动新的 JTA 事务。您可以选择容器管理的事务或应用程序管理的事务。

  • 如果 EntityManager 尚未与 JTA 事务关联,则将 EntityManager 实例加入到 JTA 事务中。如果您首先启动 JTA 事务(在上面涉及 Bean 管理事务的示例中完成),则没有必要,但如果您首先使用 JpaUtil 类创建 EntityManager ,然后稍后启动事务,那么您必须使用 EntityManager.joinTransaction() 方法将持久化上下文与 JTA 事务连接起来。很明显,从与事务无关的持久性上下文中刷新的任何更改都将被忽略。

In an application server, you can either have a container managed EntityManager (aka, a persistence context) or an application managed EntityManager. In both cases, you would have to associate the persistence context with a Transaction that is either a JTA Transaction, or plain JDBC transaction.

With respect to your problem at hand, the following points ought to be considered:

  • Your persistence.xml file indicates that you intend to use a JTA datasource and hence, JTA transactions to perform transactional work.
  • Also, your JpaUtil class is responsible for creating application-managed EntityManager instances.

In light of the above two statements and the behavior demonstrated by your application, it would appear that your EntityManager instance is not associated with a JTA transaction. Hence, any changes made in the persistence context, will simply not be flushed to the database. This is simply due to the fact that the JPA provider will rely on the JTA transaction and enlisted resources to perform the transactional work; if none are found, then no work will be done (unlike the case with Resource-Local transactions where the connection pool and resource enlistment is performed by the JPA provider itself).

The point therefore, is that the EntityManager or the persistence context must be associated with an active transaction, before you perform any changes to entities, so that all changes made to the entities in the persistence context can be flushed to the database. To resolve your problem, you must:

  • start a new JTA transaction. You could opt for either container managed transactions or application managed transactions.

    • Container managed transactions as the name states, are managed entirely by the container. You cannot invoke APIs to start and terminate such transactions. Instead, you must perform all transactional work within EJBs. The EJBs in question should be configured as ones requiring container managed transactions. Demonstrating the use of EJBs to perform transactional work in your scenario would be out of bounds of this answer. I would suggest reading up on EJBs if you haven't learn how to write one yet.
    • Application or Bean managed transactions are managed by the application itself and
      not by the container. While this might appear suitable in your case, do note that you are now responsible for transaction management; often this strategy results in mistakes, and quite often, it is not well-understood by developers with the result that it is often considered a bad practice in most projects. If you wish to use Bean managed transactions, then you will need to start a Transaction using the UserTransaction API class as shown below:

      public class WriteTest extends HttpServlet
      {
          @Resource
          UserTransaction tx; // a UserTransaction reference is injected like a any other resource. It can also be looked up from JNDI.
      
          public void doGet(HttpServletRequest request, HttpServletResponse response)
          {
              ...
              tx.begin(); // Start a new JTA BMT
              EntityManager em = JpaUtil.getEntityManagerFactory().createEntityManager();
              ...
              User user = new User("Hans", "Maulwurf", "[email protected]");
              Adress adress = new Adress("Deppenstraße 3","Deppingen");
              //user.setAddress(adress);
      
              em.persist(user);
              em.close();
              ...
              tx.commit(); // Commit the JTA BMT
          }
      
      }
      

      The above code isn't exactly production-ready. For example, it does not perform any exception handling, and nor does it explicitly rollback the changes in the event of an application failure.

  • join the EntityManager instance with the JTA transaction, if the EntityManager is not already associated with the JTA transaction. This is not necessary if you start the JTA transaction first (which is done in the above example involving Bean Managed transactions), but if you create the EntityManager first using your JpaUtil class, and then start a transaction later, then you must use the EntityManager.joinTransaction() method to join the persistence context with the JTA transaction. Quite evidently, any changes flushed from the persistence context not associated with a transaction, will be ignored.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文