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 Envers 的起点,您需要一个在 Classpath 上具有 Spring Data JPA 的项目和一个额外的依赖项:spring-data-envers
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>2.6.10</version>
</dependency>
</dependencies>
这也将作为 transent 依赖项引入项目。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 | 第一个类型参数 () 表示实体类型,第二个 () 表示 id 属性的类型,最后一个 () 是修订号的类型。
对于默认配置中的 Envers,修订号参数应为 或 。Person Long Long Integer Long |
该存储库的实体必须是启用了 Envers 审计的实体(即,它必须具有注释):@Audited
@Entity
@Audited
class Person {
@Id @GeneratedValue
Long id;
String name;
@Version Long version;
}
3.4. 使用
您现在可以使用 methods from 来查询实体的修订版,如以下测试用例所示: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 | 这引用了前面介绍的 application context configuration (在 Configuration 部分中)。 |
3.5. 更多资源
您可以在 Spring Data Examples 存储库中下载 Spring Data Envers 示例,并尝试一下该库的工作原理。
您还应该查看 RevisionRepository
和相关类的 Javadoc。