其他
我们已经不用AOP做操作日志了! | 原力计划
The following article is from JAVA葵花宝典 Author 努力减肥的胖子
来源 | JAVA葵花宝典
责编 | 王晓曼、Carol
头图 | CSDN下载自东方IC
用户在操作我们系统的过程中,针对一些重要的业务数据进行增删改查的时候,我们希望记录一下用户的操作行为,以便发生问题时能及时的找到依据,这种日志就是业务系统的操作日志。
用户登录日志 重要数据查询日志 (但电商可能不重要的数据也做埋点,比如在淘宝上你搜索什么商品,即使不买,一段时间内首页也会给你推荐类似的东西) 重要数据变更日志 (如密码变更,权限变更,数据修改等) 数据删除日志 ......
1、基于AOP(切面)传统的实现方案
优点:实现思路简单;
缺点:增加数据库的负担,强依赖前端的传参,不方便拓展,不支持批量操作,不支持多表关联;
优点:解除了数据新旧变化的耦合,支持批量操作,方便多表关联拓展,不依赖开发语言;
缺点:数据库表设计需要统一的约定;
1、基于AOP切面+注解的传统方案
@NotNull(message = "新值不能为空")
@UpdateNewDataOperationLog
private T newData;
@Valid
@NotNull(message = "旧值不能为空")
@UpdateOldDataOperationLog
private T oldData;
旧值如果不多查询一次数据库则需要依赖前端把旧值封装到oldData对象中,很有可能已经不是修改前的值;
无法处理批量的List数据;
不支持多表操作;
@ApiOperation(value = "删除用户信息", notes = "删除用户信息")
@DeleteOperationLog(system = SystemNameNewEnum.SYS_JMS_LMDM, module = ModuleNameNewEnum.LMDM_AUTH, table = LogBaseTableNameEnum.TABLE_USER, methodName = "detail")
业务应用:生成每次操作的traceid,并更新到操作的业务表中,发送1条业务消息,包含当前操作的操作人相关的信息; 日志收集应用:对业务日志和转换后的binlog日志做整合,提供对外的日志查询搜索API; 日志处理应用:利用canal采集和解析业务库的binlog日志并投递到kafka中(实现方案可以参考《如何基于Canal和 Kafka,实现 MySQL 的Binlog 近实时同步?》),解析后的记录中记录了当前操作的操作类型,如属于删除、修改、新增,和新旧值的记录,格式如下:
"database":"yl_spmibill_8",
"es":1587879945200,
"id":17161259,
"isDdl":false,
"mysqlType":{"id":"bigint(20)",
"bill_type":"tinyint(2)",
"create_time":"timestamp",
"update_time":"timestamp",
"version":"int(11)",
"trace_id":"varchar(50)"},
"old":[{"update_time":"2020-04-2613:45:45",
"version":"1",
"trace_id":"exclude-36aef98585db4e7a98f9694c8ef28b8c"}],
"pkNames":["id"],"sql":"",
"sqlType":{"id":-5,"bill_type":-6,"create_time":93,"update_time":93,"version":4,"trace_id":12},
"table":"xxx_transfer_bill_117",
"ts":1587879945698,"type":"UPDATE"}
"id":"120716921250250776",
"relevanceInfo":"XX0000097413282,",
"remark":"签收财务网点编码由【】改为【380000】,
签收网点名称由【】改为【泉州南安网点】,签收网点code由【】改为【2534104】,运单状态code由【204】改为【205】,签收财务网点名称由【】改为【福建代理区】,签收网点id由【0】改为【461】,签收标识,1是,0否由【0】改为【1】,签收时间由【null】改为【2020-04-24 21:09:47】,签收财务网点id由【0】改为【400】,",
"traceId":"120716921250250775"
}
所有业务系统表需要添加trace_id字段,每次操作生成一个随机字符串并保存到业务表中; 日志收集应用库表设计。
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`database_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '数据库名',
`table_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ' 数据库表名',
PRIMARY KEY (`id`),
UNIQUE KEY `unq_data_name_table_name` (`database_name`,`table_name`) USING BTREE COMMENT '数据库名表名联合索引'
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据库配置表';
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`table_config_id` bigint(20) DEFAULT NULL,
`field` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字段 数据库',
`field_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字段 中文名称',
`enum_flag` tinyint(2) DEFAULT NULL COMMENT '是否枚举字段(1:是,0:否)',
`relevance_flag` tinyint(2) DEFAULT NULL COMMENT '是否是关联字段(1:是,0否)',
`sort` int(11) DEFAULT NULL COMMENT '排序',
PRIMARY KEY (`id`),
KEY `idx_table_config_id` (`table_config_id`) USING BTREE COMMENT '表ID索引'
) ENGINE=InnoDB AUTO_INCREMENT=2431 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据库字段配置表';
`id` bigint(20) NOT NULL,
`field_config_id` bigint(20) DEFAULT NULL,
`field_key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ' 枚举',
`filed_value` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '枚举名称',
PRIMARY KEY (`id`),
KEY `ids_field_config_id` (`field_config_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据字典配置表';
优化发送业务消息的实现,使用切面拦截减少对业务代码的侵入; 目前暂时不支持对多表关联操作日志记录,需要拓展。
本文以操作日志为题材讨论了操作日志的实现方案和可行性,并且都已经在功能上进行实现,其中使用AOP方案也是大部分中小企业的首选实现方案,但是在一些金融领域以及ERP相关系统,对操作日志记录明细要求极高,常见技术方案很难满足。