基于Slick 3.2如何审计数据库变更?求类似Hibernate Envers的方案
关于Slick 3.2实现数据变更跟踪的实用建议
我有过使用Active Slick和原生Slick实现数据变更跟踪的经验,刚好能给你一些贴合需求的建议——毕竟不想引入完整CQRS是很合理的诉求,咱们可以用更轻量的方式解决问题。
先说说Active Slick的情况
Active Slick主要是给Slick套了一层ActiveRecord风格的API,让实体类可以直接调用save/update这类方法,但它本身并没有内置的审计/变更跟踪功能。如果你已经在项目里用了它,也完全可以扩展出审计逻辑:
- 你可以在实体的自定义
save/update方法里,手动添加写入变更日志的代码; - 或者利用Slick的生命周期钩子(比如
beforeUpdate、afterInsert),在数据操作触发时自动记录日志。
不过本质上,这和直接用原生Slick做扩展差别不大,Active Slick只是简化了实体层的代码,核心的审计逻辑还是需要你自己实现。
更适合的轻量级方案(无需CQRS)
如果不想自己从头写太多审计逻辑,推荐这几种方式:
1. 自定义Slick审计拦截器
利用Slick的DBIOAction组合特性,写一个通用的审计包装函数,把所有需要跟踪的增删改操作都套进去。这样不用每个操作都重复写日志代码,还能保证操作和日志在同一个事务里。
举个简单的实现示例:
// 先定义审计日志的表模型 case class AuditLog( id: Long, entityId: Long, entityType: String, operation: String, // 比如INSERT/UPDATE/DELETE timestamp: java.time.LocalDateTime, performedBy: String // 当前操作的用户ID ) class AuditLogs(tag: Tag) extends Table[AuditLog](tag, "audit_logs") { def id = column[Long]("id", O.PrimaryKey, O.AutoInc) def entityId = column[Long]("entity_id") def entityType = column[String]("entity_type") def operation = column[String]("operation") def timestamp = column[java.time.LocalDateTime]("timestamp") def performedBy = column[String]("performed_by") override def * = (id, entityId, entityType, operation, timestamp, performedBy) <> (AuditLog.tupled, AuditLog.unapply) } val auditLogTable = TableQuery[AuditLogs] // 通用审计包装函数 def audit[T](action: DBIO[T], entityId: Long, entityType: String, operation: String, userId: String): DBIO[T] = { val logEntry = AuditLog( id = 0, // 自增字段留空 entityId = entityId, entityType = entityType, operation = operation, timestamp = java.time.LocalDateTime.now(), performedBy = userId ) // 组合操作:先执行原操作,再写入日志,保证事务一致性 action.flatMap { result => (auditLogTable += logEntry).map(_ => result) }.transactionally } // 使用示例:更新用户时自动记录审计日志 val updateUserAction = userTable.filter(_.id === userId).update(updatedUser) val auditedAction = audit(updateUserAction, userId, "User", "UPDATE", currentUserId) db.run(auditedAction)
2. 用Slick代码生成器自动添加审计字段
如果你的所有实体都需要基础审计字段(比如创建时间、更新时间、创建人、更新人),可以修改Slick的代码生成器,让它自动给每个表生成这些字段,并且在插入/更新时自动填充值。这样能减少大量重复代码,也能保证审计字段的一致性。
3. 轻量级第三方审计库
可以找找专门为Slick设计的审计库,比如slick-audit(注意要选兼容Slick 3.2的版本)。这类库不需要引入CQRS,只需要配置要审计的表,就能自动拦截增删改操作并记录详细的变更日志(包括变更前后的字段值),效果和Hibernate Envers很类似,而且集成成本很低。
总结
- 如果已经在用Active Slick,完全可以基于它扩展审计逻辑,但不要指望它自带开箱即用的变更跟踪功能;
- 优先考虑自定义拦截器或第三方轻量级审计库,这些方案都不需要引入完整的CQRS模式,能快速满足你的数据变更跟踪需求。
内容的提问来源于stack exchange,提问作者Tadej Mali
相关产品推荐
相关产品推荐

