1、保持redis和mysql连接的一致性:通常使用延迟双删功能(具有弊端)
解决方案:可以使用canal监听数据库的变化(删改),一旦出现此类操作,立即删除redis中的对应数据,直至下次使用该数据时,从数据库中查找后(新数据)写入redis中。
2、如何监听表的字段:可以使用mybatis的拦截器进行(见下文)
更优方案:通过canal监听数据库的变化(会返回一个json串,可以解析json串来监听数据表或者数据表中的字段名)
一、MyBatis拦截器-笔试题
1.笔试题
ORM使用的是mybatis,请提供记录字段级变更日志的技术方案。
需求:
1.可以指定表进行监控
2.可以指定表中的某些字段进行监控
2.实现
2.1 引入解析器
什么是JSqlParser?
JSqlParser 是一个 SQL 语句解析器。 它将 SQL转换为可遍历的 Java 类层次结构。
添加依赖
<dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>4.6</version></dependency>
2.2 添加拦截器
@Component
@Intercepts({// 指定要拦截的方法签名,这里是拦截Executor的update方法@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),// 可以添加更多要拦截的方法签名...
})
@Slf4j
public class MonitorInterceptor implements Interceptor {private static List<String> MONITOR_TABLES = CollUtil.newArrayList("205_product");private static List<String> MONITOR_COLUMNS = CollUtil.newArrayList("price");@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler)(invocation.getTarget());BoundSql boundSql = statementHandler.getBoundSql();String sql = boundSql.getSql();net.sf.jsqlparser.statement.Statement statement = CCJSqlParserUtil.parse(sql);if(statement instanceof Update){Update update = (Update)statement;String table = update.getTable().getName();if(MONITOR_TABLES.contains(table)){log.info("表 {} 更改了", table);ArrayList<UpdateSet> updateSets = update.getUpdateSets();updateSets.forEach(item -> item.getColumns().forEach(item2 -> {if(MONITOR_COLUMNS.contains(item2.getColumnName())){sendDingding(table);}}));}}return invocation.proceed();}private void sendDingding(String table){String url = "https://oapi.dingtalk.com/robot/send?access_token=ddaea71f9ed09a0cd0fe1a28e18fadb618a4e0cee829c0534d48b3273dd9e644";JSONObject msg = new JSONObject();msg.set("msgtype", "markdown");msg.set("markdown", new JSONObject().set("title", LocalUserUtil.getLocalUser().getNickName()+ " 更改了表 " + table ).set("text"," 更改了价格请审核 "));msg.set("at", new JSONObject().set("isAtAll", true));String json = JSONUtil.toJsonStr(msg);String result = HttpRequest.post(url).body(json).execute().body();}
}