带有JTA和Glassfish Application Server的Hibernate JPA似乎没有提交

mw8*_*w88 3 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!");
    }
}
Run Code Online (Sandbox Code Playgroud)

这是小助手级:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的用户对象:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的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>
Run Code Online (Sandbox Code Playgroud)

编辑:我忘了提到,我已经使用了这个帖子中提供的信息:在Glassfish服务器上配置Hibernate JPA 2.0的学习资源

Vin*_*lds 6

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

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

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

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

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

  • 开始新的JTA交易.您可以选择容器管理的事务或应用程序管理的事务.

    • 名称状态的容器管理事务完全由容器管理.您无法调用API来启动和终止此类事务.相反,您必须在EJB中执行所有事务性工作.有问题的EJB应该配置为需要容器管理事务的EJB.演示如何使用EJB在您的场景中执行事务性工作将超出此答案的范围.如果您尚未学习如何编写EJB,我建议您阅读EJB.
    • 应用程序或Bean管理的事务由应用程序本身管理,而不是由容器管理.虽然这可能看起来适合您的情况,但请注意您现在负责交易管理; 通常这种策略会导致错误,并且通常情况下,开发人员并不了解它,结果通常认为它在大多数项目中都是不好的做法.如果您希望使用Bean托管事务,则需要使用UserTransactionAPI类启动事务,如下所示:

      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
          }
      
      }
      
      Run Code Online (Sandbox Code Playgroud)

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

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