- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 Hibernate ( hibernate-entitymanager
)、MySQL 连接器 (mysql-connector-java) 和 JUnit ( junit-jupiter-engine
) 处理 Maven 项目,我想在之后执行回滚数据库操作JUnit 测试
好吧,我已经尝试过:
@Transactional
测试类和测试用例中的注解savePerson(Person p, boolean isRollback)
传递一个额外的参数 isRollback
并放一些 if
条件。PersonServiceImpl
然后放@Transactional
顶级类中的注释。不幸的是,没用。
我有一个 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>entity-manager-07</artifactId>
<version>1.0</version>
<name>entity-manager-07</name>
<description>entity-manager-07</description>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.0-M1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.0-M1</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
安Person
实体
package com.example.entities;
import javax.persistence.*;
@Entity
@Table(name = "Person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "lastname")
private String lastname;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Person [id=");
builder.append(id);
builder.append(", name=");
builder.append(name);
builder.append(", lastname=");
builder.append(lastname);
builder.append("]");
return builder.toString();
}
}
DAO 接口(interface) Dao<T>
package com.example.dao;
public interface Dao<T> {
T save(T t) throws Exception;
T save(T t, boolean isRollback) throws Exception;
}
另外,DAO 类 PersonDAOImpl
package com.example.dao;
import javax.persistence.EntityManager;
import com.example.entities.Person;
public class PersonDAOImpl implements Dao<Person> {
private EntityManager entityManager;
public PersonDAOImpl(EntityManager em) {
this.entityManager = em;
}
@Override
public Person save(Person person) throws Exception {
try {
entityManager.getTransaction().begin();
if (person.getId() == null) {
entityManager.persist(person);
}
entityManager.persist(person);
entityManager.getTransaction().commit();
} catch (Exception e) {
if (entityManager.getTransaction() != null && entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
throw e;
} finally {
entityManager.close();
}
return person;
}
@Override
public Person save(Person person, boolean isRollback) throws Exception {
try {
entityManager.getTransaction().begin();
if (isRollback){
entityManager.getTransaction().setRollbackOnly();
}
if (person.getId() == null) {
entityManager.persist(person);
}
if (entityManager.getTransaction().getRollbackOnly()){
System.out.println("Rollback...");
entityManager.getTransaction().rollback();
} else {
entityManager.getTransaction().commit();
}
} catch (Exception e) {
if (entityManager.getTransaction() != null && entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
throw e;
} finally {
entityManager.close();
}
return person;
}
}
服务接口(interface)PersonService
package com.example.services;
import com.example.entities.Person;
public interface PersonService {
Person savePerson(Person p) throws Exception;
Person savePerson(Person p, boolean isRollback) throws Exception;
}
服务类PersonServiceImpl
package com.example.services;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import com.example.dao.PersonDAOImpl;
import com.example.entities.Person;
@Transactional
public class PersonServiceImpl implements PersonService{
private PersonDAOImpl dao;
public PersonServiceImpl(EntityManager em) {
// DAO
this.dao = new PersonDAOImpl(em);
}
@Override
public Person savePerson(Person p) throws Exception {
return this.dao.save(p);
}
@Override
public Person savePerson(Person p, boolean isRollback) throws Exception {
return this.dao.save(p, isRollback);
}
}
持久性配置
src/test/resources/hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://192.168.1.5:3306/entitymanager-test-001</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- JDBC Connection Pool Property : -->
<property name="hibernate.connection.pool_size">2</property>
<!-- Echo all executed SQL to stdout -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.use_sql_comments">true</property>
<!-- SQL Dialect Property -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Set the current session context -->
<property name="current_session_context_class">thread</property>
<!-- Entities -->
<mapping class="com.example.entities.Person" />
</session-factory>
</hibernate-configuration>
src/test/resources/META-INF/persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="my-persistence-unit"
transaction-type="RESOURCE_LOCAL">
<!-- Persistence provider -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.ejb.cfgfile"
value="./hibernate.cfg.xml" />
<property name="hibernate.session.events.log" value="true" />
</properties>
</persistence-unit>
</persistence>
最后,一个JUnit测试PersonServiceImplTest
package services;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.transaction.Transactional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.example.entities.Person;
import com.example.services.PersonServiceImpl;
@Transactional
class PersonServiceImplTest {
private EntityManagerFactory emf;
private EntityManager em;
@BeforeEach
void setUp() {
this.emf = Persistence.createEntityManagerFactory("my-persistence-unit");
}
@AfterEach
void tearDown() {
emf.close();
}
@Test
@Transactional
void savePersonRollback() {
this.em = emf.createEntityManager();
// Operation
PersonServiceImpl personService = new PersonServiceImpl(this.em);
// New person
Person person = new Person();
person.setName("Michael");
person.setLastname("Fisher");
Person pe = null;
try {
pe = personService.savePerson(person, true);
assertNotNull(pe);
assertTrue(pe.getId() > 0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
新的解决方案尝试(添加:2019 年 5 月 17 日)
person
在PersonDAOImpl
savePersonDoWork
(使用 Savepoint、PreparedStatement、Hibernate 工作)package com.example.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import javax.persistence.EntityManager;
import org.hibernate.Session;
import org.hibernate.jdbc.Work;
import com.example.entities.Person;
public class PersonDAOImpl implements Dao<Person> {
private EntityManager entityManager;
private Person person;
public PersonDAOImpl(EntityManager em) {
this.entityManager = em;
}
// ... more code
@Override
public Person savePersonDoWork(Person personToSave, boolean isRollback) throws Exception {
try {
entityManager.getTransaction().begin();
if (isRollback) {
System.out.println("Rollback if...");
entityManager.getTransaction().setRollbackOnly();
}
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute(Connection con) throws SQLException {
// do something useful
con.setAutoCommit(false);
// Savepoint
Savepoint saveBeforeInsert = con.setSavepoint();
// INSERT SQL
String sql = "INSERT INTO Person (lastname, name) VALUES (?, ?)";
con.prepareStatement(sql);
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, personToSave.getName());
st.setString(2, personToSave.getLastname());
// execute the preparedstatement insert
Long idPerson = new Long(st.executeUpdate());
if (isRollback) {
System.out.println("Rollback execute()...");
con.rollback(saveBeforeInsert);
}
// Close
st.close();
// Set data
person = new Person();
person.setId(idPerson);
person.setName(personToSave.getName());
person.setLastname(personToSave.getLastname());
}
});
} catch (Exception e) {
if (entityManager.getTransaction() != null && entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
throw e;
} finally {
entityManager.close();
}
return this.person;
}
}
不幸的是,回滚数据库操作还没有工作。
预期结果
我希望数据库没有任何变化,没有新行,没有新数据,因为我的数据库充满了测试数据,我不希望这样。
SELECT * FROM Person
(5 行)SELECT * FROM Person
(5 行)你能帮帮我吗?我会感谢你的意见、建议或支持。谢谢。
最佳答案
您正在 DAO 中调用 entityManager.getTransaction().commit();
。所以事务已经提交,不能再回滚。
如果您希望能够回滚事务,您必须将事务处理外部化。
您使用的是 Spring 还是 Java EE,还是只使用普通的 Hibernate 而没有任何其他框架?
关于java - 如何在 Hibernate 中修复 'A rollback database operation after a JUnit test'(没有 Spring)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56141728/
我是一名优秀的程序员,十分优秀!