Hibernate数据变更记录

本文详细介绍了如何通过HibernateEnvers在软件设计中实现数据变更自动记录到审计表的功能,包括配置步骤、关键Annotation的使用、以及在实际应用中可能遇到的问题与解决策略。

在很多行业的软件设计中,数据安全都是非常重要的。很多时对数据的每一次修改操作都需要记录变更以备后期审计或者数据回滚。既然这个是通用功能需求,Hibernate Envers 提供了简单的通用实现,把每次数据表的变更都记录到对应配置的审计表中,实现数据变更的自动记录。

Hibernate Envers是如何做到数据变更自动记录到审计表的呢,这个其实非常简单,就是利用了Hibernate自己的事件监听机制。通过对Hibernate的操作事件监听记录修改数据的内容。

首先,先配置数据对象需要被监听的字段,这个可以通过简单的Annotation来实现。Envers常用的Annotation有:
1. 用于对象的:
@Audited 标记该实体类或属性支持数据修改记录。
@NotAudited 标记该属性不支持数据修改记录,典型如乐观锁version字段。
2. 用于记录全局修订版本,时间戳以及其它可能需要数据时的:
@RevisionEntity 实现为数据修改记录表保存其他自定义内容
@RevisionTimestamp 记录修改时间,必须配合@RevisionEntity使用
@RevisionNumber 修改记录表的版本id 通常是配置成主键。

接着配置hibernate envers监听数据变更(一般增,删,改,极少设计查询)

 <bean id="sessionFactory"      class="org.springframework.orm.hibernate4.LocalSessionFactoryBean ">
          <property name="dataSource">
              <ref local="dataSource" />
          </property>
          *<property name="eventListeners">
              <map>
                  <entry key="post-insert" value-ref="enversEventListener" />
                  <entry key="post-update" value-ref="enversEventListener" />
                 <entry key="post-delete" value-ref="enversEventListener" />
                 <entry key="post-collection-recreate" value-ref="enversEventListener" />
                 <entry key="pre-collection-remove" value-ref="enversEventListener" />
                 <entry key="pre-collection-update" value-ref="enversEventListener" />
             </map>
         </property>*         
      *<bean name="enversEventListener" class="org.hibernate.envers.event.AuditEventListener" />*

最后在hibernate的配置文件中设置审计表的属性相关信息。

<property name="hibernateProperties">  
        <!-- 配置版本数据 -->  
            <props>  
                <!--配置审计表名的后缀,默认为空  -->  
                <prop key="org.hibernate.envers.audit_table_suffix"></prop>  
                <!--配置审计表名的前缀,默认为_AUD  -->  
                <prop key="org.hibernate.envers.audit_table_prefix">_AUDIT</prop>  
                <!--配置审计表中记录版本号的字段名称  -->  
                <prop key="org.hibernate.envers.revision_field_name">REVISION_ID</prop>  
                <!--配置审计表中数据操作类型的字段名称,0:新增   1:修改   2:删除  -->  
                <prop key="org.hibernate.envers.revision_type_field_name">REVTYPE</prop>  
                <!--配置是否支持关联表修改时记录修改记录,默认为true  -->  
                <prop key="org.hibernate.envers.revision_on_collection_change">true</prop>  
                <!--配置是否不对乐观锁字段修改时记录修改记录,即使用Version字段,默认值为true  -->  
                <prop key="org.hibernate.envers.do_not_audit_optimistic_locking_field">true</prop>  
                <!--配置是否在删除操作时,记录所有字段还是只记录id值。默认为false    false:只记录id   true:记录全部字段  -->  
                <prop key="org.hibernate.envers.store_data_at_delete">true</prop>
            </props>  
        </property>  

这里有一个问题要注意就是Aduit table的生成,我个人不太喜欢hibernate的auto hbm2ddl,所以我都是自己手动生成对于的SQL ddl,如果需要auto ddl,那么需要配置hibernate.hbm2ddl.auto为 create, create-drop 或者 update。一般配置为update。

使用Envers存在的问题:
1. 随着业务操作的频繁,审计表数据增长过快
2. 有时候为了修复系统问题,部分数据操作可能会直接使用SQL,绕过Hibernate,需要注意这类数据变更的记录和处理
3. 数据表设计需包含创建用户和更新用户信息,以及创建时间和更新时间,否则变更信息记录不完全。
4. 中途系统升级对象需要添加新的持久属性的时候,需要处理数据表以及对应的审计表。

其它没有涉及的部分:
1. 限制:http://docs.jboss.org/envers/docs/#exceptions-wontbesupported
2. 额外数据信息记录实现:http://docs.jboss.org/envers/docs/#revisionlog
3. 变更数据查询:http://docs.jboss.org/envers/docs/#queries

### Hibernate 自动记录审计字段的实现方式 在 Hibernate 中,可以通过多种方法实现自动记录审计字段的功能。以下是基于 `Hibernate Envers` 和 `JPA 审计注解` 的两种常见实现方式。 #### 方法一:使用 Hibernate Envers 实现审计功能 Hibernate Envers 是一个专门用于实体版本管理和审计的工具。它可以自动追踪实体的变化并存储历史记录。要启用此功能,需完成以下配置: 1. **引入依赖** 需要在项目的构建文件中添加 Hibernate Envers 的依赖项。 ```xml <!-- Maven --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> <version>{hibernate-version}</version> </dependency> ``` 2. **启用 Envers 功能** 在应用的配置文件中开启 Envers 支持: ```properties spring.jpa.properties.org.hibernate.envers.audit_table_suffix=_AUD spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true ``` 3. **定义可审计实体** 使用默认设置时,只需标注实体类即可使其成为可审计对象。 ```java import jakarta.persistence.Entity; import org.hibernate.envers.Audited; @Entity @Audited public class User { private Long id; private String name; private String email; // Getters and Setters } ``` 4. **查询审计数据** 可以通过 `AuditReader` 查询特定时间点的数据状态或变更历史。 ```java AuditReader auditReader = AuditReaderFactory.get(entityManager); List<Number> revisions = auditReader.getRevisions(User.class, userId); for (Number rev : revisions) { User userAtRev = auditReader.find(User.class, userId, rev); System.out.println("Revision " + rev + ": " + userAtRev.getName()); } ``` 上述过程展示了如何利用 Hibernate Envers 记录全字段的历史变化[^3]。 --- #### 方法二:使用 JPA 审计注解实现自动化审计 如果仅需要记录简单的创建时间和更新时间戳,则可以借助 Spring Data JPA 提供的内置支持。 1. **引入依赖** 如果尚未集成 Spring Boot 或 Spring Data JPA,请先确保其已正确配置。 2. **启用审计功能** 添加全局配置以激活审计特性。 ```java import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @Configuration @EnableJpaAuditing public class AuditingConfig {} ``` 3. **定义审计字段** 在实体类中声明所需的审计字段,并使用相应的注解标记它们。 ```java import jakarta.persistence.Entity; import jakarta.persistence.Temporal; import jakarta.persistence.TemporalType; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; import java.util.Date; @Entity public class Product { @CreatedBy private String createdBy; @CreatedDate @Temporal(TemporalType.TIMESTAMP) private Date createdDate; @LastModifiedBy private String lastModifiedBy; @LastModifiedDate @Temporal(TemporalType.TIMESTAMP) private Date lastModifiedDate; // Other fields, getters, setters... } ``` 4. **自定义 AuditorAware 接口** 为了动态获取当前用户的名称或其他上下文信息,需实现 `AuditorAware` 接口。 ```java import org.springframework.data.domain.AuditorAware; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import java.util.Optional; public class SecurityAuditorAware implements AuditorAware<String> { @Override public Optional<String> getCurrentAuditor() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { return Optional.empty(); } return Optional.of(authentication.getName()); } } ``` 以上步骤实现了基本的时间戳和用户信息的自动填充功能[^2]。 --- #### 性能优化建议 当处理大量数据时,应考虑性能影响。例如,启用了二级缓存能够有效降低数据库负载。 ```properties spring.jpa.properties.hibernate.cache.use_second_level_cache=true spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.jcache.JCacheRegionFactory ``` 这有助于提升读取效率,尤其是在频繁访问审计表的情况下[^4]。 --- ### 结论 无论是选择 Hibernate Envers 还是 JPA 注解的方式,都可以满足不同场景下的审计需求。前者适合复杂的版本管理与全面的历史记录,而后者则更适用于轻量级的时间戳和操作者信息记录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值