2

Я хотел бы узнать, использовал ли кто-либо другой режим hibernate-envers с mysql в приложении Spring-boot с помощью интерфейса CrudRepository и не удалось удалить объекты с коллекциями. Я собрал пример приложения с тестом, который демонстрирует генерируемое исключение.Исключение исключения в Hibernate-envers при удалении объекта с помощью коллекции CrudRepository

Пример может быть клонирован из https://github.com/LindesRoets/test-delete.git

Вам понадобится MySQL работает с базой данных под названием test_delete

CREATE DATABASE IF NOT EXISTS `test_delete` DEFAULT CHARACTER SET utf8; 

Выполнить тест

mvn test 

Вы должны увидеть следующее исключение:

2015-08-11 21:36:28.725 ERROR 3855 --- [   main] org.hibernate.AssertionFailure   : HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): java.lang.NullPointerException 
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.926 sec <<< FAILURE! - in com.dcp.test.AuthorRepositoryTest 
testAuthorCRUD(com.dcp.test.AuthorRepositoryTest) Time elapsed: 0.163 sec <<< ERROR! 
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction 
    at org.hibernate.engine.internal.StatefulPersistenceContext.getLoadedCollectionOwnerOrNull(StatefulPersistenceContext.java:756) 
    at org.hibernate.event.spi.AbstractCollectionEvent.getLoadedOwnerOrNull(AbstractCollectionEvent.java:75) 
    at org.hibernate.event.spi.InitializeCollectionEvent.<init>(InitializeCollectionEvent.java:36) 
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1931) 
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:558) 
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:260) 
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554) 
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142) 
    at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294) 
    at java.util.AbstractCollection.addAll(AbstractCollection.java:343) 
    at org.hibernate.envers.internal.entities.mapper.relation.AbstractCollectionMapper.mapCollectionChanges(AbstractCollectionMapper.java:162) 
    at org.hibernate.envers.internal.entities.mapper.relation.AbstractCollectionMapper.mapModifiedFlagsToMapFromEntity(AbstractCollectionMapper.java:212) 
    at org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper.map(MultiPropertyMapper.java:105) 
    at org.hibernate.envers.internal.synchronization.work.DelWorkUnit.generateData(DelWorkUnit.java:66) 
    at org.hibernate.envers.internal.synchronization.work.AbstractAuditWorkUnit.perform(AbstractAuditWorkUnit.java:76) 
    at org.hibernate.envers.internal.synchronization.AuditProcess.executeInSession(AuditProcess.java:119) 

Ниже приведен весь исходный код, как показано в примере приложения.

pom.xml

<?xml version="1.0" encoding="UTF-8"?> 
<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.test</groupId> 
    <artifactId>test</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 
    <name>test-delete</name> 
    <description></description> 


    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.2.5.RELEASE</version> 
    </parent> 


    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <start-class>com.test.Application</start-class> 
     <java.version>1.8</java.version> 
     <spring-boot-version>1.2.5.RELEASE</spring-boot-version> 
    </properties> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>3.3</version> 
       <configuration> 
        <source>1.8</source> 
        <target>1.8</target> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-surefire-plugin</artifactId> 
       <version>2.18.1</version> 
       <configuration> 
        <includes> 
         <include>**/*Test*.java</include> 
        </includes> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-maven-plugin</artifactId>    
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-javadoc-plugin</artifactId> 
       <version>2.10.3</version> 
      </plugin>     
     </plugins> 
    </build> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter</artifactId> 
      <version>${spring-boot-version}</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <version>${spring-boot-version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-jpa</artifactId> 
      <version>${spring-boot-version}</version> 
     </dependency> 


     <dependency> 
      <groupId>mysql</groupId> 
      <artifactId>mysql-connector-java</artifactId> 
      <version>5.1.35</version> 
     </dependency>    


     <dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-envers</artifactId> 
     </dependency>  
    </dependencies> 

</project> 

application.properties

spring.datasource.url = jdbc:mysql://localhost:3306/test_delete 
spring.datasource.username = 
spring.datasource.password = 
# Specify the DBMS 
spring.jpa.database = MYSQL 
spring.datasource.driverClassName = com.mysql.jdbc.Driver 

# Show or not log for each sql query 
spring.jpa.show-sql = true 
spring.jpa.hibernate.ddl-auto = create 

# Naming strategy 
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy 
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect 

#envers 
spring.jpa.properties.org.hibernate.envers.global_with_modified_flag=true 
spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true 

Application.java

@SpringBootApplication 
public class Application { 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 

} 

BaseEntity.java

@MappedSuperclass 
@Audited 
public abstract class BaseEntity implements Serializable { 

    @GeneratedValue(generator = "guid") 
    @GenericGenerator(name = "guid", strategy = "guid") 
    @Column(columnDefinition = "CHAR(36)") 
    @Id 
    protected String id; 

    @Temporal(TemporalType.TIMESTAMP) 
    protected Date dateCreated = new Date(); 

    public String getId() { 
     return id; 
    } 

    public void setId(String id) { 
     this.id = id; 
    } 

    public Date getDateCreated() { 
     return dateCreated; 
    } 

    public void setDateCreated(Date dateCreated) { 
     this.dateCreated = dateCreated; 
    } 

    private static final long serialVersionUID = -8371628134270930829L; 
} 

Author.java

@Entity 
@Audited 
public class Author extends BaseEntity{ 

    private String email; 

    private String name; 

    @OneToMany(mappedBy = "author") 
    private List<Book> books = new ArrayList<>(); 

    public String getEmail() { 
     return email; 
    } 

    public void setEmail(String email) { 
     this.email = email; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public List<Book> getBooks() { 
     return books; 
    } 

    public void setBooks(List<Book> books) { 
     this.books = books; 
    } 


} 

Book.java

@Entity 
@Audited 
public class Book extends BaseEntity { 

    private String title; 

    private String genre; 

    @ManyToOne 
    private Author author; 

    public String getTitle() { 
     return title; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    public String getGenre() { 
     return genre; 
    } 

    public void setGenre(String genre) { 
     this.genre = genre; 
    } 

    public Author getAuthor() { 
     return author; 
    } 

    public void setAuthor(Author author) { 
     this.author = author; 
    } 

} 

AuthorRepository.java

@Transactional 
public interface AuthorRepository extends CrudRepository<Author, String> { 

} 

AuthorRepositoryTest.java

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = Application.class) 
public class AuthorRepositoryTest { 

    @Autowired 
    private AuthorRepository authorRepo; 

    @Test 
    public void testAuthorCRUD() { 
     Author author = new Author(); 
     author.setName("Test Name"); 
     author.setEmail("[email protected]"); 

     Author savedAuthor = authorRepo.save(author); 

     Assert.assertNotNull(savedAuthor); 

     authorRepo.delete(savedAuthor); 
    } 

} 

Если закомментировать @Audited из классов сущностей книги, автора и BaseEntity тест проходят только штрафом.

Кто-нибудь знает, как сделать работу удаления с помощью envers?

ответ

0

Есть два способа, которые я нашел в ходе пробной версии и ошибки, чтобы сделать операцию удаления, как указано в задаче.

Вы можете либо указать коллекцию для загрузки нетерпеливо

@OneToMany(mappedBy = "author", fetch = FetchType.EAGER) 

Или вы можете каскад операции удаления

@OneToMany(mappedBy = "author", cascade = CascadeType.REMOVE) 

Это минимальная конфигурация, что вам нужно будет сделать тестовый проход, как указано в проблеме.

Смежные вопросы