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");
@Override
public 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();
}
}