3.参考文档
Spring Data Envers 是什么?
Spring Data Envers 使得典型的 Envers 查询可以在 Spring Data JPA 的仓库中使用。 它与其他 Spring Data 模块的不同之处在于,它始终与另一个 Spring Data 模块(即 Spring Data JPA)结合使用。
Envers 的作用是什么?
Envers 是一个Hibernate 模块,它为 JPA 实体添加了审计功能。 本文档假定您已熟悉 Envers,因为 Spring Data Envers 依赖于 Envers 的正确配置。
3.3. 配置项
作为使用 Spring Data Envers 的起点,你需要一个类路径中包含 Spring Data JPA 的项目,并额外添加 spring-data-envers 依赖:
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>2.7.18</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;
}
使用方法
您现在可以使用 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 示例,并动手尝试,以了解该库的工作原理。
您还应该查看RevisionRepository的 Javadoc及相关类。
Spring Data Envers 的源代码和问题跟踪器托管在 GitHub 上 [点击这里]