我們已經(jīng)不用AOP做操作日志了!

文章來源于公眾號JAVA葵花寶典 垢揩,作者努力減肥的胖子

前言

用戶在操作我們系統(tǒng)的過程中玖绿,針對一些重要的業(yè)務(wù)數(shù)據(jù)進行增刪改查的時候,我們希望記錄一下用戶的操作行為叁巨,以便發(fā)生問題時能及時的找到依據(jù)斑匪,這種日志就是業(yè)務(wù)系統(tǒng)的操作日志。

本篇我們來探討下常見操作日志的實現(xiàn)方案和可行性

常見的操作日志類型

  • 用戶登錄日志
  • 重要數(shù)據(jù)查詢?nèi)罩?(但電商可能不重要的數(shù)據(jù)也做埋點锋勺,比如在淘寶上你搜索什么商品蚀瘸,即使不買,一段時間內(nèi)首頁也會給你推薦類似的東西)
  • 重要數(shù)據(jù)變更日志 (如密碼變更庶橱,權(quán)限變更贮勃,數(shù)據(jù)修改等)
  • 數(shù)據(jù)刪除日志
  • ......

總結(jié)來說,就是重要的增刪改查根據(jù)業(yè)務(wù)的需要來做操作日志的埋點苏章。

實現(xiàn)方案對比

基于AOP(切面)傳統(tǒng)的實現(xiàn)方案

  • 優(yōu)點:實現(xiàn)思路簡單寂嘉;
  • 缺點:增加數(shù)據(jù)庫的負擔,強依賴前端的傳參枫绅,不方便拓展泉孩,不支持批量操作,不支持多表關(guān)聯(lián)并淋;

基于數(shù)據(jù)庫Binlog

  • 優(yōu)點:解除了數(shù)據(jù)新舊變化的耦合寓搬,支持批量操作,方便多表關(guān)聯(lián)拓展县耽,不依賴開發(fā)語言句喷;
  • 缺點:數(shù)據(jù)庫表設(shè)計需要統(tǒng)一的約定;

方案實現(xiàn)細節(jié)

一兔毙、基于AOP切面+注解的傳統(tǒng)方案

傳統(tǒng)的做法就是切面+注解的方式唾琼,這種對代碼的侵入性不強,通常記錄ip瞒御、業(yè)務(wù)模塊父叙、操作賬號、操作場景肴裙、操作來源等等趾唱,一般在注解+攔截器里這些值都拿得到,如下圖所示:

image

這種常見的我們在通用方法都可以處理蜻懦,但是在數(shù)據(jù)變更方面甜癞,一直沒有較好的實現(xiàn)方式,比如數(shù)據(jù)在變更前是多少宛乃,變更后是多少悠咱。

以我們以前實現(xiàn)的一套方案來說蒸辆,基于數(shù)據(jù)變更的記錄方式不僅要和需求方約定好模板(上百個字段的不可能都做展示和記錄),也要和前端做一些約定析既,比如在修改之前的值是多少躬贡,修改后的值是多少,如下代碼客官請看:

    @Valid
    @NotNull(message = "新值不能為空")
    @UpdateNewDataOperationLog
    private T newData;

    @Valid
    @NotNull(message = "舊值不能為空")
    @UpdateOldDataOperationLog
    private T oldData;

存在的問題:

  • 1.舊值如果不多查詢一次數(shù)據(jù)庫則需要依賴前端把舊值封裝到oldData對象中眼坏,很有可能已經(jīng)不是修改前的值拂玻;
  • 2.無法處理批量的List數(shù)據(jù);
  • 3.不支持多表操作宰译;

再以一個場景為例檐蚜,再刪除之前需要記錄刪除前的值,是不是還得再查一次~

    @PostMapping("/delete")
    @ApiOperation(value = "刪除用戶信息", notes = "刪除用戶信息")
    @DeleteOperationLog(system = SystemNameNewEnum.SYS_JMS_LMDM, module = ModuleNameNewEnum.LMDM_AUTH, table = LogBaseTableNameEnum.TABLE_USER, methodName = "detail")

二沿侈、基于數(shù)據(jù)庫Binlog 方案

系統(tǒng)架構(gòu)圖如下:

image

「主要分為3塊:」

  • 1:業(yè)務(wù)應(yīng)用 生成每次操作的traceid闯第,并更新到操作的業(yè)務(wù)表中,發(fā)送1條業(yè)務(wù)消息缀拭,包含當前操作的操作人相關(guān)的信息咳短;

  • 2:日志收集應(yīng)用 對業(yè)務(wù)日志和轉(zhuǎn)換后的binlog日志做整合,提供對外的日志查詢搜索API智厌;

  • 3:日志處理應(yīng)用

  • 利用canal采集和解析業(yè)務(wù)庫的binlog日志并投遞到kafka中诲泌,解析后的記錄中記錄了當前操作的操作類型盲赊,如屬于刪除铣鹏、修改、新增,和新舊值的記錄哀蘑,格式如下:

{"data":[{"id":"122158992930664499","bill_type":"1","create_time":"2020-04-2609:15:13","update_time":"2020-04-2613:45:46","version":"2","trace_id":"exclude-f04ff706673d4e98a757396efb711173"}],
"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"}

處理完binlon日志轉(zhuǎn)換后的操作日志诚卸,如下:

  {
  "id":"120716921250250776",
  "relevanceInfo":"XX0000097413282,",
  "remark":"簽收財務(wù)網(wǎng)點編碼由【】改為【380000】,
  簽收網(wǎng)點名稱由【】改為【泉州南安網(wǎng)點】绘迁,簽收網(wǎng)點code由【】改為【2534104】合溺,運單狀態(tài)code由【204】改為【205】,簽收財務(wù)網(wǎng)點名稱由【】改為【福建代理區(qū)】缀台,簽收網(wǎng)點id由【0】改為【461】棠赛,簽收標識,1是,0否由【0】改為【1】膛腐,簽收時間由【null】改為【2020-04-24 21:09:47】睛约,簽收財務(wù)網(wǎng)點id由【0】改為【400】,",
  "traceId":"120716921250250775"
  }

庫表設(shè)計

  • 1:所有業(yè)務(wù)系統(tǒng)表需要添加trace_id字段哲身,每次操作生成一個隨機字符串并保存到業(yè)務(wù)表中辩涝;
  • 2:日志收集應(yīng)用庫表設(shè)計
    CREATE TABLE `table_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `database_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '數(shù)據(jù)庫名',
  `table_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ' 數(shù)據(jù)庫表名',
  PRIMARY KEY (`id`),
  UNIQUE KEY `unq_data_name_table_name` (`database_name`,`table_name`) USING BTREE COMMENT '數(shù)據(jù)庫名表名聯(lián)合索引'
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='數(shù)據(jù)庫配置表';
CREATE TABLE `table_field_config` (
  `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 '字段 數(shù)據(jù)庫',
  `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 '是否是關(guān)聯(lián)字段(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='數(shù)據(jù)庫字段配置表';
CREATE TABLE `table_field_value` (
  `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='數(shù)據(jù)字典配置表';
image

效果
image

基于binlog實現(xiàn)方案未來規(guī)劃

  1. 優(yōu)化發(fā)送業(yè)務(wù)消息的實現(xiàn),使用切面攔截減少對業(yè)務(wù)代碼的侵入勘天;
  2. 目前暫時不支持對多表關(guān)聯(lián)操作日志記錄怔揩,需要拓展捉邢;

總結(jié)

本文以操作日志為題材討論了操作日志的實現(xiàn)方案和可行性,并且都已經(jīng)在功能上進行實現(xiàn)商膊,其中使用aop方案也是大部分中小企業(yè)的首選實現(xiàn)方案伏伐,但是在一些金融領(lǐng)域以及erp相關(guān)系統(tǒng),對操作日志記錄明細要求極高晕拆,常見技術(shù)方案很難滿足秘案,即使能夠滿足也會帶來一些代碼強侵入以及性能問題,所以我們又討論了基于binlog實現(xiàn)的方案潦匈,該方案雖然比對aop來說增強了技術(shù)的復雜性阱高,但是對于有一定技術(shù)積累的團隊來說不算什么難事,并且該方案我們都實現(xiàn)了上線茬缩,并且解決了代碼層面上的侵入赤惊,屬于跨語言級別的,相信對讀者還是有一定的啟發(fā)凰锡。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末未舟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掂为,更是在濱河造成了極大的恐慌裕膀,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勇哗,死亡現(xiàn)場離奇詭異昼扛,居然都是意外死亡,警方通過查閱死者的電腦和手機欲诺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門抄谐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扰法,你說我怎么就攤上這事蛹含。” “怎么了塞颁?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵浦箱,是天一觀的道長。 經(jīng)常有香客問我祠锣,道長酷窥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任锤岸,我火速辦了婚禮竖幔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘是偷。我一直安慰自己拳氢,他們只是感情好募逞,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馋评,像睡著了一般放接。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上留特,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天纠脾,我揣著相機與錄音,去河邊找鬼蜕青。 笑死苟蹈,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的右核。 我是一名探鬼主播慧脱,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贺喝!你這毒婦竟也來了菱鸥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤躏鱼,失蹤者是張志新(化名)和其女友劉穎氮采,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體染苛,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡鹊漠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了殖侵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贸呢。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拢军,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怔鳖,我是刑警寧澤茉唉,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站结执,受9級特大地震影響度陆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜献幔,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一懂傀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜡感,春花似錦蹬蚁、人聲如沸恃泪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贝乎。三九已至,卻和暖如春叽粹,著一層夾襖步出監(jiān)牢的瞬間览效,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工虫几, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锤灿,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓辆脸,卻偏偏與公主長得像衡招,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子每强,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355