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的一种扩展
05-29 12:10