我正在开发一个项目,其中我第一次使用JPA,Hibernate和所有这些东西,并且我遇到了未提交的事务的问题。我使用类似User的类:
package org.tomasherman.JBTBackup.Resource.Entity;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "users")
public class User implements Serializable {
@Id
@GeneratedValue
private int id;
private String login;
private String email;
private String password;
private int credit;
public User() {
}
public User(String login, String email, String password, int credit) {
setLogin(login);
setEmail(email);
setPassword(password);
setCredit(credit);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getCredit() {
return credit;
}
public void setCredit(int credit) {
this.credit = credit;
}
}
并使用HSQL数据库将其保存在MEMORY表中。 persistence.xml文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<persistence-unit name="JBTBackupPersistance">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.tomasherman.JBTBackup.Resource.Entity.User</class>
<properties>
<property name="hibernate.connection.url" value="jdbc:hsqldb:file:./database/database.hsql"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="SA"/> <!--default hsql login-->
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="connection.shutdown" value="true"/>
</properties>
</persistence-unit>
并在JUnit测试中测试它,如下所示:
package org.tomasherman.JBTBackup.Resource.Entity;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* Created by IntelliJ IDEA.
* User: arg
* Date: Jun 29, 2010
* Time: 11:24:35 PM
* To change this template use File | Settings | File Templates.
*/
public class UserTest {
private EntityManagerFactory emf;
private EntityManager em;
private final User u1 = new User("and","now","for",1234);
private final User u2 = new User("something","completely","different",123123123);
private final User u3 = new User("a","man","with",123123123);
@Before
public void initEmfAndEm() {
emf = Persistence.createEntityManagerFactory("JBTBackupPersistance");
em = emf.createEntityManager();
}
@After
public void cleanup() {
em.close();
}
@Test
public void emptyTest() {
System.out.println(em.createQuery("from User").getResultList().size());
if(em.getTransaction().isActive()){
System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
}else{
em.getTransaction().begin();
em.persist(u1);
em.persist(u2);
em.persist(u3);
em.getTransaction().commit();
}
System.out.println(em.createQuery("from User").getResultList().size());
}
}
现在问题是插入通常不会写入数据库。测试的输出如下所示:
...some hibernate stuff...
Hibernate:
select
user0_.id as id0_,
user0_.credit as credit0_,
user0_.email as email0_,
user0_.login as login0_,
user0_.password as password0_
from
users user0_
20
Hibernate:
insert
into
users
(id, credit, email, login, password)
values
(null, ?, ?, ?, ?)
Hibernate:
insert
into
users
(id, credit, email, login, password)
values
(null, ?, ?, ?, ?)
Hibernate:
insert
into
users
(id, credit, email, login, password)
values
(null, ?, ?, ?, ?)
Hibernate:
select
user0_.id as id0_,
user0_.credit as credit0_,
user0_.email as email0_,
user0_.login as login0_,
user0_.password as password0_
from
users user0_
23
所以entites在数据库的内存中,但是当我在单元测试后检查数据库时,没有数据。但是,它会不时得到承诺。
如果有人能帮助我,那就太棒了。
编辑: 如果它可以帮助任何人,有一个库版本列表(以maven格式):
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>20040616</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
UPDATE2: 另一个有趣的事情,似乎如果我添加Thread.sleep(1000);在测试结束时,所有事务都会被提交。可能是程序完成得更快,然后数据库可以更新吗?
答案 0 :(得分:2)
根据HSQLDB用户指南:
Closing the Database
从版本1.7.2开始,正在进行中 数据库不再关闭时 与数据库的最后一次连接是 通过JDBC [和数据]显式关闭 不写入磁盘],一个明确的 需要
SHUTDOWN
命令[in 为了保持数据持久性]。在 1.8.0,可以指定连接属性shutdown=true
第一次连接到数据库 (打开的连接 数据库)强制关机的时候 最后一次关闭。
因此,要么通过原生查询发送SHUTDOWN
命令,要么将 ;shutdown=true
添加到连接字符串中:
jdbc:hsqldb:file:./database/database.hsql;shutdown=true
关于write_delay
的问题,不,将其设置为0
不会导致单元测试环境出现问题(它“只是”对性能产生影响)。实际上,我希望shutdown=true
足够如文档中所述:
Application Development and Testing
...
如果您不想运行服务器 实例,你需要持久性 在不同过程中的测试之间, 那么你应该使用
有人报道了一些数据 访问框架不会关闭所有 他们之后与数据库的连接 测试。在这种情况下,你 如果你需要使用零WRITE DELAY 希望数据在结尾处持续存在 测试file:
数据库。你可以使用shutdown=true
连接属性 确保数据库完全保留 连接关闭后。一个 替代选择是使用hsqldb.write_delay=false
连接 属性,但这稍微慢一点 比其他选择。
但我猜您正面临第二段所述的情况。我想知道数据访问层是否真的有罪。
答案 1 :(得分:0)
不是两次调用em.getTransaction()
,而是需要调用一次,并保存对它的引用。每次调用它时,都会获得新事务。所以你开始一个,但然后提交一个单独的。