Hibernate JPA 与 JTA 和 Glassfish 应用服务器似乎没有提交
我是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您应该使用容器提供的事务支持。这是 Pro JPA 2 Mastering the Java Persistence API 一书中的示例。我希望这有帮助:
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:
本指南用于在 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 文件,如下所示:
在用于创建 EntityManager 的 EJB 类(用 @Stateless 注释的类)中,使用以下语法:
如您所知,当您使用“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 :
In Your EJB class (class that annotated with @Stateless) for creating EntityManager use following syntax :
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.
当您手动提交更改时(即取消注释提交行时),它是否会提交?
设置
还可以尝试检查您的配置是否通过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();
在应用程序服务器中,您可以拥有容器管理的 EntityManager(也称为持久性上下文)或应用程序管理的 EntityManager。在这两种情况下,您都必须将持久性上下文与事务关联起来,该事务可以是 JTA 事务,也可以是普通 JDBC 事务。
对于您当前的问题,应考虑以下几点:
persistence.xml
文件表明您打算使用 JTA 数据源,因此使用 JTA 事务来执行事务工作。根据上述两条语句以及您的应用程序演示的行为,您的 EntityManager 实例似乎未与 JTA 事务关联。因此,在持久性上下文中所做的任何更改都不会被刷新到数据库。这仅仅是因为 JPA 提供者将依赖 JTA 事务和征用的资源来执行事务工作;如果没有找到,则不会完成任何工作(与资源本地事务的情况不同,其中连接池和资源登记由 JPA 提供程序本身执行)。
因此,要点是,在对实体执行任何更改之前,EntityManager 或持久性上下文必须与活动事务关联,以便可以刷新对持久性上下文中的实体所做的所有更改到数据库。要解决您的问题,您必须:
启动新的 JTA 事务。您可以选择容器管理的事务或应用程序管理的事务。
应用程序或 Bean 管理的事务由应用程序本身管理,并且
不是通过容器。虽然这可能适合您的情况,但请注意,您现在负责事务管理;这种策略通常会导致错误,而且开发人员常常无法很好地理解它,因此在大多数项目中它通常被认为是一种不好的做法。如果您希望使用 Bean 管理的事务,则需要使用
UserTransaction
API类如下所示:上面的代码并不完全适合生产。例如,它不执行任何异常处理,也不在应用程序发生故障时显式回滚更改。
如果
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 managedEntityManager
. 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:
persistence.xml
file indicates that you intend to use a JTA datasource and hence, JTA transactions to perform transactional work.JpaUtil
class is responsible for creating application-managedEntityManager
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.
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: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 theEntityManager
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 theEntityManager
first using yourJpaUtil
class, and then start a transaction later, then you must use theEntityManager.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.