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

时间:2011-08-01 08:28:29

标签: 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

4 个答案:

答案 0 :(得分: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托管交易,则需要使用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管理事务的示例中完成),但是如果首先使用EntityManager类创建JpaUtil,然后启动事务,则不需要这样做之后,您必须使用EntityManager.joinTransaction()方法将持久性上下文与JTA事务连接起来。很明显,从与事务无关的持久化上下文中刷新的任何更改都将被忽略。

答案 1 :(得分:3)

您应该使用容器提供的事务支持。这是Pro JPA 2掌握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();
        // ...
    }
}

答案 2 :(得分:1)

本指南适用于在NetBeans.8.0 IDE中集成hibernate.4.3.5和EJB以及JTA和GlassFish.4.0。在net bean中创建一个web项目(注意:不要使用maven制作web项目因为Netbeans.8.0 IDE中存在错误)并将hibernate jar文件添加到项目中,其他与配置MySql和glassfish相关的设置非常简单(Just在参考资料中定义连接池和JDBC&gt; JDBC:JDBC连接池和JDBC资源,如果你搜索它,可以在网上找到指导)(注意:为了定义一个正确的JNDI,首先创建一个依赖于JNDI的临时项目在glassfish中的JPA项目,然后复制Glassfish中为此项目创建的设置,因为如果您在创建第一个连接池时,如果您在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>

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

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

如您所知,当您使用“transaction-type =&#34; JTA&#34 ;,交易管理不在您手中时,意味着,管理开启和关闭交易是应用服务器(Here GlassFish)的责任。实际上,如果你在模式设计中检查你的persistence.xml,在持久性提供程序下拉框前面你可以看到现在添加了hibernate。

答案 3 :(得分:0)

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

同时尝试通过

检查您的配置

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