java - 使用 JTA 和 Glassfish Application Server 的 Hibernate JPA 似乎没有提交

标签 java hibernate jpa jta

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

奇怪的是,它在数据库中创建了我的表,但不保存实体。看起来,它没有提交。

有没有人遇到过与 hibernate 类似的问题?

这是一个小测试 servlet:

public class WriteTest extends HttpServlet
{
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    {
        /*try
        { 
            User user = new User("Hans", "Maulwurf", "hans.maulwurf@test.de");

            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", "hans.maulwurf@test.de");
        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>

编辑:我忘了说,我已经使用了这个线程中提供的信息:Learning resource for Configuring Hibernate JPA 2.0 on Glassfish server

最佳答案

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

关于您手头的问题,应考虑以下几点:

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

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

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

  • 开始一个新的 JTA 事务。您可以选择容器管理的事务或应用程序管理的事务。

    • 顾名思义,容器管理事务完全由容器管理。您不能调用 API 来启动和终止此类交易。相反,您必须在 EJB 中执行所有事务性工作。所讨论的 EJB 应该配置为需要容器管理事务的 EJB。在您的场景中演示如何使用 EJB 执行事务性工作超出了此答案的范围。如果您还没有学会如何编写 EJB,我建议您阅读 EJB。
    • 应用程序或 Bean 管理的事务由应用程序本身管理,并且 不是靠容器。虽然这可能适合您的情况,但请注意您现在负责事务管理;这种策略通常会导致错误,而且开发人员往往没有很好地理解它,因此在大多数项目中它通常被认为是一种不好的做法。如果您希望使用 Bean 管理的事务,那么您将需要使用 UserTransaction 启动一个事务。 API类如下图:

      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", "hans.maulwurf@test.de");
              Adress adress = new Adress("Deppenstraße 3","Deppingen");
              //user.setAddress(adress);
      
              em.persist(user);
              em.close();
              ...
              tx.commit(); // Commit the JTA BMT
          }
      
      }
      

      上面的代码并不完全适合生产。例如,它不执​​行任何异常处理,也不会在应用程序出现故障时显式回滚更改。

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

关于java - 使用 JTA 和 Glassfish Application Server 的 Hibernate JPA 似乎没有提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6895868/

相关文章:

JavaFx:如何更新 GridPane 内动态创建的 TextField 的文本?

java - 无法从连接池获取/创建连接

java - 当我通过我的设备(USB 调试)运行它时,我的 UI 会失真,但在我的 AVD 上运行良好

java - Hibernate Search - 即使 Elasticsearch 集群关闭也启动应用程序

java - 覆盖 hibernate 映射文件中相关实体的延迟加载设置

java - Spring Data JPA JpaRepository.save(entity) 不返回数据库默认值

java - 使用php获取内存使用情况

java - 我如何使用 thymeleaf 以一种形式显示 2 个实体的值

java - 更新实体 (JPA+MySQL) - key '142' 的重复条目 'PRIMARY'

hibernate - EntityManager 刷新问题