fastmybatis支持原生的插件,将写好的插件配置到mybatis配置文件中即可
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<plugins>
<plugin interceptor="xxxxx.MyInterceptor" />
</plugins>
</configuration>
这里演示编写一个分表插件
假设有4张分表,user_log0~3,记录用户的日志情况
user_log0
user_log1
user_log2
user_log3
现在需要动态查询指定到某一张表
首先生成对应的实体类,指定一张表生成,不用全部生成
/**
* 表名:user_logX
* %index% 占位符
*/
@Table(name = "user_log%index%")
public class UserLog {
...
}
注意%index%
占位符
Mapper不变
public interface UserLogMapper extends CrudMapper<UserLog, Long> {
}
编写插件,新建一个类实现org.apache.ibatis.plugin.Interceptor
接口
@Intercepts({@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class, Integer.class})})
public class UserLogInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
StatementHandler delegate = getFieldValue(handler, "delegate");
MappedStatement mappedStatement = getFieldValue(delegate, "mappedStatement");
BoundSql boundsql = handler.getBoundSql();
String sqlId = mappedStatement.getId();
if (StringUtils.startsWith(sqlId, "com.myapp.dao.UserLogMapper.")) {
String sql = boundsql.getSql();
// 获取index
String index = String.valueOf(RequestContext.getCurrentContext().getIndex());
// 替换sql
sql = StringUtils.replace(sql, "%index%", index);
setFieldValue(boundsql, "sql", sql);
}
return invocation.proceed();
}
private <T> T getFieldValue(Object handler, String name) {
Field delegateField = ReflectionUtils.findField(handler.getClass(), name);
delegateField.setAccessible(true);
return (T) ReflectionUtils.getField(delegateField, handler);
}
private void setFieldValue(Object obj, String fieldName, Object fieldValue) {
Field field = ReflectionUtils.findField(obj.getClass(), fieldName);
if (field != null) {
try {
field.setAccessible(true);
field.set(obj, fieldValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
这个插件的功能很简单,在执行sql之前替换%index%
占位符,变成正式的index,然后执行sql
配置插件
<plugins>
<plugin interceptor="com.myapp.interceptor.UserLogInterceptor" />
</plugins>
测试用例
public class PluginTest extends BaseTests {
@Autowired
private UserLogMapper userLogMapper;
@Test
public void testInsert() {
// 指定某一张表
RequestContext.getCurrentContext().setIndex(1);
UserLog userLog = new UserLog();
userLog.setLog("insert 111");
userLogMapper.saveIgnoreNull(userLog);
}
@Test
public void testUpdate() {
RequestContext.getCurrentContext().setIndex(1);
UserLog userLog = userLogMapper.getById(1L);
userLog.setLog("update 111");
userLogMapper.updateIgnoreNull(userLog);
}
@Test
public void testGet() {
RequestContext.getCurrentContext().setIndex(1);
UserLog userLog = userLogMapper.getById(1L);
System.out.println(userLog);
}
@Test
public void testQuery() {
RequestContext.getCurrentContext().setIndex(2);
Query query = new Query();
query.eq("user_id", 3);
List<UserLog> list = userLogMapper.list(query);
System.out.println(list);
}
}
这里使用RequestContext.getCurrentContext().setIndex(1);
指定某一张表,还可以根据userId
取模动态计算哪一张表
比如有16张分表,那么index=userId%16
完整代码见:fastmybatis-demo-plugin
fastmybatis是一个mybatis开发框架,其宗旨为:简单、快速、有效。
- 零配置快速上手
- 无需编写xml文件即可完成CRUD操作
- 支持mysql、sqlserver、oracle、postgresql、sqlite
- 支持自定义sql,sql语句可写在注解中或xml中
- 支持与spring-boot集成,依赖starter即可
- 支持插件编写
- 轻量级,无侵入性,是官方mybatis的一种扩展