fastmybatis編寫分表插件

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的一種擴展
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章