带JTA和Glassfish Application Server的Hibernate JPA似乎没有提交 [英] Hibernate JPA with JTA and Glassfish Application Server doesn't seem to commit

查看:108
本文介绍了带JTA和Glassfish Application Server的Hibernate JPA似乎没有提交的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是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自动生成的catch块
e.printStackTrace();
} * /

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

System.out.println(Begin transfer);

用户用户=新用户(Hans,Maulwurf,hans.maulwurf@test.de);
地址= new Adress(Deppenstraße3,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(一切都比预期好!);


这是小帮手类:

  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);
抛出新的ExceptionInInitializerError(ex);



public static EntityManagerFactory getEntityManagerFactory()
{
return emf;


我的用户对象:

  @Entity 
@Table(name =T_UserJpa)
public class User实现Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
私有长ID;
@Embedded
@AttributeOverrides(
{
@AttributeOverride(name =street,column =
@Column(name =user_street)),
@AttributeOverride(name =city,column =
@Column(name =user_city,length = 50))
})
private地址;
私人字符串名字;
私人字符串姓氏;
私人字符串电子邮件;

public User()
{
}

public User(String firstname,String lastname,String email)
{
this.firstname = firstname;
this.lastname = lastname;
this.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;
$
$ b @Override
public boolean equals(Object obj)
{
if(this == obj)
{
返回true;
}
if(!(obj instanceof User))
{
return false;
}
最终用户用户=(用户)obj;
return!(email!= null?!email.equals(user.email):user.email!= null);

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


我的persistence.xml:

 <?xml version =1.0encoding =UTF-8?> 
< persistence version =1.0xmlns =http://java.sun.com/xml/ns/persistence>
< persistence-unit name =testPUtransaction-type =JTA>
< provider> org.hibernate.ejb.HibernatePersistence< / provider>
< jta-data-source> jdbc / testdb< / jta-data-source>
<属性>
< property name =hibernate.dialectvalue =org.hibernate.dialect.PostgreSQLDialect/>
< property name =hibernate.show_sqlvalue =true/>
< property name =hibernate.transaction.factory_classvalue =org.hibernate.transaction.JTATransactionFactory/>
< property name =hibernate.hbm2ddl.autovalue =update/>
< property name =hibernate.connection.autocommitvalue =true/>
< / properties>
< / persistence-unit>
< /余辉>

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

解决方案

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



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


  • 您的 persistence.xml 文件表明您打算使用JTA数据源,因此使用JTA事务来执行事务性工作。

  • 另外,您的 JpaUtil 类负责创建应用程序管理 EntityManager 实例。



鉴于上述两种说法和应用程序演示的行为,看起来您的 EntityManager 实例不与JTA事务相关联。因此,在持久化上下文中进行的任何更改都不会刷新到数据库。这仅仅是由于JPA提供商将依赖JTA事务并且招募资源来执行事务性工作;如果没有找到,那么就不会做任何工作(与JPA提供程序本身执行连接池和资源登记的Resource-Local事务不同)。

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


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


    • 容器管理事务作为名称状态完全由容器管理。您无法调用API来启动和终止此类事务。相反,您必须在EJB中执行所有事务性工作。有问题的EJB应该配置为需要容器管理事务的EJB。演示如何使用EJB在您的场景中执行事务性工作将超出此答案。如果您还没有学习如何编写EJB,我建议您阅读EJB。

    • Application或Bean管理的事务由应用程序本身管理,
      不是由容器。虽然这可能看起来适合您的情况,但请注意您现在负责事务管理;通常这种策略会导致错误,而且很多时候,开发人员并不能很好地理解它,结果在大多数项目中它通常被认为是不好的做法。如果你想使用Bean管理事务,那么你将需要使用 UserTransaction API类如下所示:

        public class WriteTest extends HttpServlet 
      {
      @Resource
      UserTransaction tx; //一个UserTransaction引用像任何其他资源一样注入。它也可以从JNDI中查找。

      public void doGet(HttpServletRequest请求,HttpServletResponse响应)
      {
      ...
      tx.begin(); //开始一个新的JTA BMT
      EntityManager em = JpaUtil.getEntityManagerFactory()。createEntityManager();
      ...
      用户用户=新用户(Hans,Maulwurf,hans.maulwurf@test.de);
      地址= new Adress(Deppenstraße3,Deppingen);
      //user.setAddress(adress);

      em.persist(user);
      em.close();
      ...
      tx.commit(); //提交JTA BMT
      }

      }

      上面的代码不完全是生产准备。例如,它不会执行任何异常处理,也不会在发生应用程序故障时显式回滚这些更改。

    • b
    • 如果 EntityManager 尚未与JTA事务关联,那么将 EntityManager 实例与JTA事务加入JTA交易。如果首先启动JTA事务(这在上述涉及Bean Managed事务的示例中完成),但是如果您首先使用<$ c创建 EntityManager ,则这不是必需的$ c> JpaUtil class,然后再启动一个事务,那么你必须使用 EntityManager.joinTransaction() 方法将持久性上下文与JTA事务加入。很明显,从持久化上下文中刷新的任何与事务无关的更改都将被忽略。



    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", "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!");
        }
    }
    

    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

    解决方案

    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", "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
            }
        
        }
        

        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.

    这篇关于带JTA和Glassfish Application Server的Hibernate JPA似乎没有提交的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆