gpt4 book ai didi

java - 如何在 Hibernate 中修复 'A rollback database operation after a JUnit test'(没有 Spring)?

转载 作者:行者123 更新时间:2023-11-30 12:05:41 25 4
gpt4 key购买 nike

我正在使用 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 日)

  • 添加新属性 personPersonDAOImpl
  • 创建一个新方法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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com