为什么写这个东西?
我们有个用了mybatis的项目,我想在mybatis新增、修改、删除时监控到修改前和修改后的数据,以便后续写日志,最佳的方案可以通过淘宝的canal监听数据库来实现,但通过mybatis插件方式比较轻量(虽然性能差些,但某些场景很适用)。
原理
通过mybatis的拦截器拦截增、删、改操作的SQL,解析SQL的表名和where 部分,根据这两部分到数据库中查询出要更新的数据,得到要更新的数据并预判生成更新后的数据。(新增操作没这么复杂)
项目基本信息
GitHub : https://github.com/clazz666/mybatis_changemonitor
Maven:
<dependency>
<groupId>com.github.clazz666</groupId>
<artifactId>changemonitor</artifactId>
<version>1.0.2</version>
</dependency>
目前支持数据库 : mysql, db2, oracle
使用
创建监听入口
public class DataChangeMonitor extends AbstractMonitor {
@Override
public void listen(List<ChangeData> changeTable) {
System.out.println("ok");
}
}
spring代码方式初始化mybatis配置示例
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean(@Autowired DataSource dataSource,
@Autowired ChangeMonitorInterceptor changeMonitorInterceptor) {
try {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
// 加载全局的配置文件
sessionFactoryBean.setConfigLocation(
new DefaultResourceLoader().getResource("classpath:mybatis-config.xml"));
// 配置mapper的扫描,找到所有的mapper.xml映射文件
Resource[] resources =
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");
sessionFactoryBean.setMapperLocations(resources);
// 添加插件
sessionFactoryBean.setPlugins(new Interceptor[]{changeMonitorInterceptor});
return sessionFactoryBean.getObject();
} catch (IOException e) {
LOGGER.error("mybatis resolver mapper*xml is error", e);
throw new RuntimeException(e);
} catch (Exception e) {
LOGGER.error("mybatis sqlSessionFactoryBean create error", e);
throw new RuntimeException(e);
}
}
@Bean
public ChangeMonitorInterceptor examplePlugin(@Autowired DataChangeMonitor dataChangeMonitor){
ChangeMonitorInterceptor changeMonitorInterceptor = new ChangeMonitorInterceptor();
changeMonitorInterceptor.setMonitor(dataChangeMonitor);
Properties pros = new Properties();
pros.put("dbname", "mysql"); //目前支持mysql,db2,oracle
pros.put("maxRowMonitor", "3"); //最大监听行数,比如一句update更新了1W行,设置了3后最多只监听3条变更数据
pros.put("whiteList", "prd_a,prd_b"); //监听表白名单,通过逗号分隔表名
changeMonitorInterceptor.setProperties(pros);
return changeMonitorInterceptor;
}
@Bean
public DataChangeMonitor dataChangeMonitor(){
return new DataChangeMonitor();
}
源码后续讲解