最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

那我們就會是用到Mybaits的攔截器

Mybatis插件機制:

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

總體概況為:

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

分表注解

首先我們想要的效果是只有指定的表才需要分表,并不是全部表都需要分表,因為攔截器是全局的,所以我們需要做特殊處理,當只有指定的表我們才進行攔截和處理。

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

基于以上兩點,我們會構造一個注解,作用于表上,為我們指定分表策略,以及標記當前表是需要做分表的。

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

    Class<? extends TableShardStrategy> shardStrategy();
}

分表策略接口

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

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

目前只有一個實現(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;
    }
}

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

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

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

最后就是Mybatis的攔截器實現(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 該配置才會生效
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); //獲取表實體類上的注解
        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的實現(xiàn)類
        Class<?> clazz = Class.forName(className);
        if (BaseMapper.class.isAssignableFrom(clazz)) {
            return (Class<?>) ((ParameterizedType) (clazz.getGenericInterfaces()[0])).getActualTypeArguments()[0]; //獲取表實體類
            //public interface XXXMapper extends BaseMapper<XXX> 其實就是獲取到泛型中的具體表實體類
            return null;
    }

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

}

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

參考

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

mybatis @Intercepts的用法

MyBatis攔截器原理探究

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

Mybatis的分表實戰(zhàn)

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

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

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

相關文章

  • Java 編程如何使用 Class.forName() 加載類

    Java 編程如何使用 Class.forName() 加載類

    在一些應用中,無法事先知道使用者將加載什么類,而必須讓使用者指定類名稱以加載類,可以使用 Class的靜態(tài)forName()方法實現(xiàn)動態(tài)加載類,這篇文章主要介紹了Java編程如何使用Class.forName()加載類,需要的朋友可以參考下
    2022-06-06
  • 解讀查看zookeeper事務日志的正確姿勢

    解讀查看zookeeper事務日志的正確姿勢

    這篇文章主要介紹了解讀查看zookeeper事務日志的正確姿勢。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 通過案例了解靜態(tài)修飾符static使用場景

    通過案例了解靜態(tài)修飾符static使用場景

    這篇文章主要介紹了通過案例了解靜態(tài)修飾符static使用場景,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • 詳解Spark?Sql在UDF中如何引用外部數(shù)據(jù)

    詳解Spark?Sql在UDF中如何引用外部數(shù)據(jù)

    這篇文章主要為大家介紹了詳解Spark?Sql在UDF中如何引用外部數(shù)據(jù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • 用java生成html文件實現(xiàn)原理及代碼

    用java生成html文件實現(xiàn)原理及代碼

    用printStream來向html文件里輸出數(shù)據(jù),先創(chuàng)建一個StringBuilder對象,通過append方法來為其添加html語句,具體實現(xiàn)如下,感興趣的朋友可以參考下,希望對大家有所幫助
    2013-08-08
  • SpringBoot框架中Mybatis-plus的簡單使用操作匯總

    SpringBoot框架中Mybatis-plus的簡單使用操作匯總

    這篇文章主要介紹了SpringBoot框架中Mybatis-plus的簡單使用,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • 詳解Java獲取環(huán)境變量及系統(tǒng)屬性的方法

    詳解Java獲取環(huán)境變量及系統(tǒng)屬性的方法

    這篇文章主要介紹了詳解Java獲取環(huán)境變量及系統(tǒng)屬性的方法,講解了System.getEnv()和System.getProperties()這兩個核心方法的使用,需要的朋友可以參考下
    2016-05-05
  • 基于SpringBoot?使用?Flink?收發(fā)Kafka消息的示例詳解

    基于SpringBoot?使用?Flink?收發(fā)Kafka消息的示例詳解

    這篇文章主要介紹了基于SpringBoot?使用?Flink?收發(fā)Kafka消息,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01
  • Socket結合線程池使用實現(xiàn)客戶端和服務端通信demo

    Socket結合線程池使用實現(xiàn)客戶端和服務端通信demo

    這篇文章主要為大家介紹了Socket結合線程池的使用來實現(xiàn)客戶端和服務端通信實戰(zhàn)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • Springboot項目因為kackson版本問題啟動報錯解決方案

    Springboot項目因為kackson版本問題啟動報錯解決方案

    這篇文章主要介紹了Springboot項目因為kackson版本問題啟動報錯解決方案,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07

最新評論

禹城市| 平果县| 钟山县| 宝兴县| 修武县| 宣城市| 石台县| 临汾市| 鄂托克前旗| 保定市| 玉龙| 哈巴河县| 洛南县| 关岭| 绵竹市| 惠来县| 交口县| 三都| 新邵县| 房山区| 临西县| 黔江区| 奈曼旗| 恩平市| 北京市| 沂水县| 乐至县| 西青区| 沂源县| 秀山| 海宁市| 梓潼县| 阿坝| 东宁县| 会同县| 手机| 石狮市| 涟源市| 南部县| 天水市| 修水县|