操作记录精细到字段级别,有比较干净的方案么?

2021-11-27 02:19:44 +08:00
 taloricag
就是 post 请求,需要知道修改到数据库改了什么字段做操作记录
实际上现在操作记录的实现已经是 AOP ,在路由层丢给一个单独的控制层去解决操作记录的问题
但是在路由层不可能记录到字段级别,毕竟也不可能在这个地方去查数据
所以有没啥干净一点的方案,实在是不想在业务逻辑的 controller 里再去逐个字段做对比...

或许最理想的方案是在 ORM 去做,但是目前对 ORM 的控制力实在有点弱...(go / gorm
2933 次点击
所在节点    程序员
12 条回复
wd
2021-11-27 06:45:02 +08:00
数据库 trigger
totoro52
2021-11-27 08:01:12 +08:00
我的做法是 binlog ,用 canal 解析 binlog 在写入日志数据库,同步到 es , 完全和业务层解偶,缺点是无法记录用户的 ip 等,不过业务日志只要记录业务行为就行了,剩下的交给系统日志
taloricag
2021-11-27 09:35:16 +08:00
@totoro52 谢谢大佬,但是场景不太符合我,因为我的场景不是完全跟业务解耦,还有条件触发,比如修改了 A 字段需要发个邮件,修改了 B 字段发个通知这种,给我整蒙了
rrfeng
2021-11-27 09:54:20 +08:00
gorm 有 hooks 啊
cs419
2021-11-27 09:58:52 +08:00
client 驱动层
修改 github.com/go-sql-driver/mysql 进行 aop
fgwmlhdkkkw
2021-11-27 10:12:30 +08:00
只记请求和 sql ,然后再用 sql 解析器,取出来字段。
totoro52
2021-11-27 11:24:58 +08:00
@taloricag 一样可以 只要你的表设计有更新人这类似的字段,可以取出来在回表去查通知,如果你的表设计没有更新人和创建人那就不行了
totoro52
2021-11-27 11:27:08 +08:00
@taloricag canal 本身只是负责解析记录,剩下的逻辑还是在自己手上
Fule
2021-11-29 09:58:47 +08:00
SQL Server 2016+ 有 Temporal Table ,自动维护整行历史记录,一定程度上有助于这类问题,不知道其它数据库是否有类似特性:
https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2016
shigella
2021-11-29 10:00:03 +08:00
canal
cnit
2021-11-29 16:28:51 +08:00
``` java


@Component
@CanalTable("table_name")
public class OrderHeaderHandler implements EntryHandler {

@Autowired
private XxxService xxxService;

@Override
public void update(Map<String, String> before, Map<String, String> after, Set<String> updateColumns) {
//获取需要记录日志的列
Map<String, String> filedMap = FieldUtils.objectToMap(TableName.class, updateColumns);
String tableId= before.get("tableId");
String records = "";
if (filedMap != null && filedMap.keySet().size() > 0) {
for (String update : filedMap.keySet()) {
String comment = filedMap.get(update);
String beforeValue = before.get(update);
String afterValue = after.get(update);
records = records.concat(String.format("%s 由 %s 改为 %s", comment, StringUtils.isEmpty(beforeValue) ? "空" : beforeValue
, StringUtils.isEmpty(afterValue) ? "空" : afterValue) + ";");
}
//记录日志
OperationRecords operationRecords = new OperationRecords();
operationRecords.setLinkedId(Long.parseLong(orderId));
operationRecords.setRecords(records);
operationRecords.setTableName("container_transport_order_header");
operationRecords.setCreateTime(new Date());
operationRecords.setCreateUserId(parseLongUserId(after.get("updateUserId")));
operationRecordsService.save(operationRecords);
}
}



```
onhao
2021-11-29 17:00:00 +08:00
@taloricag 我的方案,可能应用场景有限 用触发器
https://wuhao.pw/archives/268/

免去了在应用端敲代码了,仅供参考。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/818291

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX