3. 参考文档
3.1. 什么是 Spring Data Envers?
Spring Data Envers 在 Spring Data JPA 的存储库中提供了典型的 Envers 查询。 它与其他 Spring Data 模块的不同之处在于,它始终与另一个 Spring Data 模块结合使用:Spring Data JPA。
3.2. 什么是 Envers?
Envers 是一个 Hibernate 模块,它为 JPA 实体添加了审计功能。 本文档假设您熟悉Envers,就像Spring Data Envers依赖于正确配置Envers一样。
3.3. 配置
作为使用 Spring Data Vers的起点,您需要一个在类路径上带有 Spring Data JPA 的项目,并且需要一个额外的spring-data-envers
Dependency:
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>2.6.10</version>
</dependency>
</dependencies>
这也带来了hibernate-envers
作为瞬态依赖项添加到项目中。
要启用 Spring Data Envers 和 Spring Data JPA,我们需要配置两个 bean 和一个特殊的repositoryFactoryBeanClass
:
@Configuration
@EnableEnversRepositories
@EnableTransactionManagement
public class EnversDemoConfiguration {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("example.springdata.jpa.envers");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
要实际使用 Spring Data Envers,请将一个或多个存储库制作成RevisionRepository
通过将其添加为扩展接口:
interface PersonRepository
extends CrudRepository<Person, Long>,
RevisionRepository<Person, Long, Long> (1)
{}
1 | 第一个类型参数 (Person ) 表示实体类型,第二个 (Long ) 表示 id 属性的类型,最后一个 (Long ) 是修订号的类型。
对于默认配置中的 Envers,修订号参数应为Integer 或Long . |
该存储库的实体必须是启用了 Envers 审计的实体(即,它必须具有@Audited
注释):
@Entity
@Audited
class Person {
@Id @GeneratedValue
Long id;
String name;
@Version Long version;
}
3.4. 用法
您现在可以使用RevisionRepository
查询实体的修订版,如以下测试用例所示:
@ExtendWith(SpringExtension.class)
@Import(EnversDemoConfiguration.class) (1)
class EnversIntegrationTests {
final PersonRepository repository;
final TransactionTemplate tx;
EnversIntegrationTests(@Autowired PersonRepository repository, @Autowired PlatformTransactionManager tm) {
this.repository = repository;
this.tx = new TransactionTemplate(tm);
}
@Test
void testRepository() {
Person updated = preparePersonHistory();
Revisions<Long, Person> revisions = repository.findRevisions(updated.id);
Iterator<Revision<Long, Person>> revisionIterator = revisions.iterator();
checkNextRevision(revisionIterator, "John", RevisionType.INSERT);
checkNextRevision(revisionIterator, "Jonny", RevisionType.UPDATE);
checkNextRevision(revisionIterator, null, RevisionType.DELETE);
assertThat(revisionIterator.hasNext()).isFalse();
}
/**
* Checks that the next element in the iterator is a Revision entry referencing a Person
* with the given name after whatever change brought that Revision into existence.
* <p>
* As a side effect the Iterator gets advanced by one element.
*
* @param revisionIterator the iterator to be tested.
* @param name the expected name of the Person referenced by the Revision.
* @param revisionType the type of the revision denoting if it represents an insert, update or delete.
*/
private void checkNextRevision(Iterator<Revision<Long, Person>> revisionIterator, String name,
RevisionType revisionType) {
assertThat(revisionIterator.hasNext()).isTrue();
Revision<Long, Person> revision = revisionIterator.next();
assertThat(revision.getEntity().name).isEqualTo(name);
assertThat(revision.getMetadata().getRevisionType()).isEqualTo(revisionType);
}
/**
* Creates a Person with a couple of changes so it has a non-trivial revision history.
* @return the created Person.
*/
private Person preparePersonHistory() {
Person john = new Person();
john.setName("John");
// create
Person saved = tx.execute(__ -> repository.save(john));
assertThat(saved).isNotNull();
saved.setName("Jonny");
// update
Person updated = tx.execute(__ -> repository.save(saved));
assertThat(updated).isNotNull();
// delete
tx.executeWithoutResult(__ -> repository.delete(updated));
return updated;
}
}
1 | 这引用了前面介绍的应用程序上下文配置(在配置部分中)。 |
3.5. 更多资源
您可以在 Spring Data Examples 存储库中下载 Spring Data Envers 示例并尝试一下以了解该库的工作原理。
您还应该查看Javadoc 的RevisionRepository
和相关类。
您可以在以下位置提问:Stackoverflow 使用spring-data-envers
标记.