java 带有 JTA 和 Glassfish Application Server 的 Hibernate JPA 似乎没有提交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6895868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate JPA with JTA and Glassfish Application Server doesn't seem to commit
提问by mw88
I'm new to hibernate and I want it to use the database connection from the application server via JNDI.
我是 Hibernate 的新手,我希望它通过 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:
这是一个小测试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:
我的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
编辑:我忘了提及,我已经使用了此线程中提供的信息:在 Glassfish 服务器上配置 Hibernate JPA 2.0 的学习资源
回答by Vineet Reynolds
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.
在应用程序服务器中,您可以管理容器EntityManager
(也称为持久性上下文)或管理应用程序EntityManager
。在这两种情况下,您都必须将持久性上下文与 JTA 事务或普通 JDBC 事务的事务相关联。
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-managedEntityManager
instances.
- 您的
persistence.xml
文件表明您打算使用 JTA 数据源,因此使用 JTA 事务来执行事务性工作。 - 此外,您的
JpaUtil
类负责创建应用程序管理的EntityManager
实例。
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).
根据以上两条语句和您的应用程序所展示的行为,您的EntityManager
实例似乎与 JTA 事务无关。因此,在持久性上下文中所做的任何更改都不会被刷新到数据库中。这仅仅是因为 JPA 提供者将依赖 JTA 事务和征募的资源来执行事务工作;如果未找到,则不会执行任何工作(与资源本地事务的情况不同,其中连接池和资源登记由 JPA 提供程序本身执行)。
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:
因此,关键是EntityManager
持久上下文必须与活动事务相关联,然后才能对实体执行任何更改,以便对持久上下文中的实体所做的所有更改都可以刷新到数据库中。要解决您的问题,您必须:
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", "[email protected]"); 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 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.
开始一个新的 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", "[email protected]"); 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 Managed 事务),但如果你EntityManager
使用你的JpaUtil
类创建第一个,然后稍后启动一个事务,那么你必须使用EntityManager.joinTransaction()
方法加入JTA 事务的持久性上下文。很明显,从与事务无关的持久性上下文刷新的任何更改都将被忽略。
回答by Edwin Dalorzo
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:
您应该使用容器提供的事务支持。这是 Pro JPA 2 Mastering the 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();
// ...
}
}
回答by Omid Ashouri
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 :
本指南用于在 NetBeans.8.0 IDE 中集成 hibernate.4.3.5 和 EJB 以及 JTA 和 GlassFish.4.0。在net bean中创建一个web项目(注意:不要用maven做web项目,因为Netbeans.8.0 IDE有一个bug)并在项目中添加hibernate jar文件,其他配置MySql和glassfish的相关设置很简单(只要在Resources>JDBC:JDBC Connection Pools & JDBC Resources中定义Connection Pool and JDBC,如果你搜索它在网上有相关指导)(注意:要定义正确的JNDI,首先创建一个依赖JNDI的临时项目,如JPA在 glassfish 中的项目,
<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>
In Your EJB class (class that annotated with @Stateless) for creating EntityManager use following syntax :
在用于创建 EntityManager 的 EJB 类(用 @Stateless 注释的类)中,使用以下语法:
@PersistenceContext(unitName = " omidashouriPU ")
EntityManager em;
em.persist(YourEntityObject);
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.
如您所知,当您使用“transaction-type="JTA”时,事务的管理与您无关,也就是说,管理打开和关闭事务是应用程序服务器(此处为 GlassFish)的职责。事实上,如果你在模式设计中检查你的persistence.xml,在持久化提供者下拉框的前面你可以看到现在添加了hibernate。
回答by Chris
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();
toggleAutoCommit = session.connection().getAutoCommit();