欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mybatis攔截器實(shí)現(xiàn)數(shù)據(jù)分表

 更新時(shí)間:2024年01月26日 15:09:04   作者:c.  
當(dāng)數(shù)據(jù)量比較多時(shí),放在一個(gè)表中的時(shí)候會(huì)影響查詢效率,本文主要介紹了Mybatis攔截器實(shí)現(xiàn)數(shù)據(jù)分表,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在項(xiàng)目中我們是用Mybatis + TKMapper + MYSQL存儲(chǔ)了一些消息日志,但是現(xiàn)在隨著業(yè)務(wù)數(shù)據(jù)暴增, 單表支撐不了這么多數(shù)據(jù). 因此決定把表做水平切分, 按照月份來給表進(jìn)行切分。這樣當(dāng)我們需要housekeep數(shù)據(jù)的時(shí)候,就可以直接drop掉表了,不論是備份還是刪除效率都會(huì)比較高

那我們就會(huì)是用到Mybaits的攔截器

Mybatis插件機(jī)制:

Mybatis支持插件(plugin), 講得通俗一點(diǎn)就是攔截器(interceptor). > 它支持ParameterHandler/StatementHandler/Executor/ResultSetHandler這四個(gè)級(jí)> 別進(jìn)行攔截.

總體概況為:

  • 攔截參數(shù)的處理(ParameterHandler)
  • 攔截Sql語法構(gòu)建的處理(StatementHandler)
  • 攔截執(zhí)行器的方法(Executor)
  • 攔截結(jié)果集的處理(ResultSetHandler)

分表注解

首先我們想要的效果是只有指定的表才需要分表,并不是全部表都需要分表,因?yàn)閿r截器是全局的,所以我們需要做特殊處理,當(dāng)只有指定的表我們才進(jìn)行攔截和處理。

第二點(diǎn),我們的分表策略目前是按照年月份來進(jìn)行分表,以后可能會(huì)按照天來分表,也就是分表策略是可變的,所以我們的代碼是可擴(kuò)展的,能夠自定義分表策略的。

基于以上兩點(diǎn),我們會(huì)構(gòu)造一個(gè)注解,作用于表上,為我們指定分表策略,以及標(biāo)記當(dāng)前表是需要做分表的。

@Target({TYPE})
@Retention(RUNTIME)
public @interface TableShard {

    Class<? extends TableShardStrategy> shardStrategy();
}

分表策略接口

public interface TableShardStrategy {
    String getTableShardName(String tableName);
}

從方法名就可以看出來,返回的是一個(gè)分表后的表名

目前只有一個(gè)實(shí)現(xiàn)類,也就是按照年月份分表

public class DateTableShardStrategy implements TableShardStrategy {

    public static final String PATTERN = "yyyyMM";

    @Override
    public String getTableShardName(String tableName) {
        YearMonth yearMonth = Optional.ofNullable(ProcessContextHolder.get()).orElse(ProcessInfo.builder().yearMonth(TimeUtils.getYearMonth()).build()).getYearMonth();
        String date = DateTimeFormatter.ofPattern(PATTERN).format(yearMonth);
        return tableName + "_" + date;
    }
}

具體的實(shí)現(xiàn)其實(shí)就是根據(jù)當(dāng)前實(shí)現(xiàn)獲取月份,然后在當(dāng)前的表名后面加上年月。 至于為什么中間從ProcessContextHolder.get()獲取時(shí)間呢,其實(shí)是當(dāng)有消息進(jìn)來的時(shí)候,我們會(huì)在ThreadLocal存一個(gè)當(dāng)前時(shí)間作為當(dāng)前消息的全局時(shí)間。為什么需要這么做呢,就是擔(dān)心一條消息在處理的過程中,出現(xiàn)跨月的情況,所以導(dǎo)致同一條消息的數(shù)據(jù),存儲(chǔ)在了兩個(gè)不同的表。所以需要維護(hù)一個(gè)全局的時(shí)間。

之后我們就可以在表的實(shí)體類上加上該注解了@TableShard(shardStrategy = DateTableShardStrategy.class)

Mybaits的攔截器實(shí)現(xiàn)

最后就是Mybatis的攔截器實(shí)現(xiàn)了。

@Intercepts({
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class}
        )
})
@Slf4j
@Component
@ConditionalOnProperty(value = "table.shard.enabled", havingValue = "true") //加上了table.shard.enabled 該配置才會(huì)生效
public class MybatisStatementInterceptor implements Interceptor {

    private static final ReflectorFactory defaultReflectorFactory = new DefaultReflectorFactory();
    public static final String DELEGATE_BOUND_SQL_SQL = "delegate.boundSql.sql";
    public static final String DELEGATE_MAPPED_STATEMENT = "delegate.mappedStatement";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = MetaObject.forObject(statementHandler,
                SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                defaultReflectorFactory
        );

        MappedStatement mappedStatement = (MappedStatement)
                metaObject.getValue(DELEGATE_MAPPED_STATEMENT);

        Class<?> clazz = getTableClass(mappedStatement);
        if (clazz == null) {
            return invocation.proceed();
        }
        TableShard tableShard = clazz.getAnnotation(TableShard.class); //獲取表實(shí)體類上的注解
        Table table = clazz.getAnnotation(Table.class);
        if (tableShard != null && table != null) { //如果注解存在就執(zhí)行分表策略
            String tableName = table.name();
            Class<? extends TableShardStrategy> strategyClazz = tableShard.shardStrategy();
            TableShardStrategy strategy = strategyClazz.getDeclaredConstructor().newInstance();
            String tableShardName = strategy.getTableShardName(tableName);
            String sql = (String) metaObject.getValue(DELEGATE_BOUND_SQL_SQL);
            metaObject.setValue(DELEGATE_BOUND_SQL_SQL, sql.replaceAll(tableName, tableShardName.toUpperCase())); //替換表名
        }
        return invocation.proceed();
    }

    private Class<?> getTableClass(MappedStatement mappedStatement) throws ClassNotFoundException {
        String className = mappedStatement.getId();
        className = className.substring(0, className.lastIndexOf('.')); //獲取到BaseMapper的實(shí)現(xiàn)類
        Class<?> clazz = Class.forName(className);
        if (BaseMapper.class.isAssignableFrom(clazz)) {
            return (Class<?>) ((ParameterizedType) (clazz.getGenericInterfaces()[0])).getActualTypeArguments()[0]; //獲取表實(shí)體類
            //public interface XXXMapper extends BaseMapper<XXX> 其實(shí)就是獲取到泛型中的具體表實(shí)體類
            return null;
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

}

好了,這樣就實(shí)現(xiàn)了使用Mybatis攔截器進(jìn)行數(shù)據(jù)分表

參考

通過MyBatis攔截器實(shí)現(xiàn)增刪改查參數(shù)的加/解密(已上線項(xiàng)目)

mybatis @Intercepts的用法

MyBatis攔截器原理探究

mybatis自定義攔截器攔截sql,處理createTime,updateTime,createBy,updateBy等問題

Mybatis的分表實(shí)戰(zhàn)

基于mybatis攔截器分表實(shí)現(xiàn)

mybatis攔截器實(shí)現(xiàn)數(shù)據(jù)庫表水平切分

到此這篇關(guān)于Mybatis攔截器實(shí)現(xiàn)數(shù)據(jù)分表的文章就介紹到這了,更多相關(guān)Mybatis攔截器分表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)ZooKeeper的zNode監(jiān)控

    Java實(shí)現(xiàn)ZooKeeper的zNode監(jiān)控

    這篇文章主要介紹了Java實(shí)現(xiàn)ZooKeeper的zNode監(jiān)控問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-08-08
  • Java線性結(jié)構(gòu)中棧、隊(duì)列和串的基本概念和特點(diǎn)詳解

    Java線性結(jié)構(gòu)中棧、隊(duì)列和串的基本概念和特點(diǎn)詳解

    前幾天小編給大家介紹了Java線性結(jié)構(gòu)中的鏈表,除了鏈表這種結(jié)構(gòu)之外,實(shí)際上還有棧、隊(duì)列、串等結(jié)構(gòu),那么這些結(jié)構(gòu)又有哪些特點(diǎn)呢,本文就給大家詳細(xì)的介紹一下,感興趣的小伙伴跟著小編一起來看看吧
    2023-07-07
  • 文件路徑正確,報(bào)java.io.FileNotFoundException異常的原因及解決辦法

    文件路徑正確,報(bào)java.io.FileNotFoundException異常的原因及解決辦法

    這篇文章主要介紹了文件路徑正確,報(bào)java.io.FileNotFoundException異常的原因及解決辦法的相關(guān)資料,需要的朋友可以參考下
    2016-04-04
  • 淺談java線程狀態(tài)與線程安全解析

    淺談java線程狀態(tài)與線程安全解析

    本文主要介紹了淺談java線程狀態(tài)與線程安全解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • RSA加密的方式和解密方式實(shí)現(xiàn)方法(推薦)

    RSA加密的方式和解密方式實(shí)現(xiàn)方法(推薦)

    下面小編就為大家?guī)硪黄猂SA加密的方式和解密方式實(shí)現(xiàn)方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java服務(wù)限流算法的6種實(shí)現(xiàn)

    Java服務(wù)限流算法的6種實(shí)現(xiàn)

    服務(wù)限流是指通過控制請求的速率或次數(shù)來達(dá)到保護(hù)服務(wù)的目的,本文主要介紹了Java服務(wù)限流算法的6種實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-05-05
  • java中的4種循環(huán)方法示例詳情

    java中的4種循環(huán)方法示例詳情

    大家好,本篇文章主要講的是java中的4種循環(huán)方法示例詳情,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 詳解Java利用同步塊synchronized()保證并發(fā)安全

    詳解Java利用同步塊synchronized()保證并發(fā)安全

    這篇文章主要介紹了Java利用同步塊synchronized()保證并發(fā)安全,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java 二分法檢索算法代碼實(shí)現(xiàn)詳解

    Java 二分法檢索算法代碼實(shí)現(xiàn)詳解

    這篇文章主要介紹了Java 二分法檢索算法代碼實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Java雙括弧初始化操作技巧

    Java雙括弧初始化操作技巧

    這篇文章主要介紹了Java雙括弧初始化操作技巧,這種方法不僅提高了代碼的可讀性,而且簡化了代碼的數(shù)量,需要的朋友可以參考下
    2015-12-12

最新評(píng)論