zoukankan      html  css  js  c++  java
  • 如何用Mybatis分库分表

    分库

    在分库的时候 有时候为了方便 一些表需要存放所有库的信息,称为全局库。如:用户表存放所有的用户。

    此时分库的思路 数据库分为全局库和业务库,其中业务库又分为N多个库,全局库只放个别表方便开发。

    这个时候 就需要一个全局DAO,此时我们的Mybatis就需要支持两个DAO

    两个DAO(bizDao和globalDao)就需要有两个sqlSessionFactory,bizSqlSessionFactory和globalSqlSessionFactory和两个事物管理器transactionManager

        <bean id="bizDao" class="com.xxx.dao.BizDao">
            <property name="sqlSessionFactory" ref="bizSqlSessionFactory"/>
        </bean>
        <bean id="globalDao" class="com.xxx.dao.GlobalDao">
            <property name="sqlSessionFactory" ref="globalSqlSessionFactory"/>
        </bean>
         <bean id="bizSqlSessionFactory" parent="sqlSessionFactoryDefault" class="org.mybatis.spring.SqlSessionFactoryBean">
             <property name="dataSource" ref="routingDataSource"/> 
         </bean>
    
        <bean id="globalSqlSessionFactory" parent="sqlSessionFactoryDefault" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="globalDataSource"/>           
        </bean>

    根据请求动态指定业务库DataSource

    分库就是一个项目有多个数据库,对Myabtis来说就有多个数据源(dataSource)根据你的请求 判断应该查询哪个库 从而指定动态指定哪个数据源

    可以继承Spring的AbstractRoutingDataSource重写接口中determineCurrentLookupKey()根据业务需求返回当前的dbkey(哪个库1、2、3、4。。。)

    全局库和业务库事物管理器

    因为事物是基于Service的,所以Service也建议分为全局Service和业务Service,根据Service类型(建议配个AOP全局处理 放到ThreadLocal中)

    实现PlatformTransactionManager接口,接口中getTransaction()方法可以动态的返回指定的事物管理器(从上面的ThreadLocal中拿到当前的事物管理器)

    思考:为什么AbstractRoutingDataSource中多个DataSource不需要动态配置事物管理器?

    总结:业务库和全局库有两个不同的DataSource,其中业务库的DataSource继承Spring的AbstractRoutingDataSource

    Spring又分为了N个DataSource(对bizSqlSessionFactory而言 只有一个RoutingDataSource,RoutingDataSource里面有一个数据源集合)

    全局的globalSqlSessionFactory也可以当bizSqlSessionFactory中的AbstractRoutingDataSource的一个属性 这么做虽然减少了配置,但是开发不直观。

    分表

    上面的分库的思路就是动态指定DateSource和TransactionManager

    分表:就是在Mybatis中写一个拦截器 动态的更改表名

    1.拦截器

    SqlSessionFactoryBean里面有个private Interceptor[] plugins;属性 可以配置一些拦截器

    我们自己定义的拦截器需要实现Interceptor接口

    接口需要加以下注解

    @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}) })

    2.在拦截器里面 我们需要动态解析SQL和更改SQL

    @Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})
    })
    public class MybatisInterceptor implements Interceptor {
        
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            if (invocation.getTarget() instanceof StatementHandler) {
                RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
                //通过反射拿到statement对象
                StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
                BoundSql boundSql = delegate.getBoundSql();
                String sql = boundSql.getSql();
                String pageSql =sql+" limit 1 ";//操作sql
                //再通过反射把新sql设置进去
                ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
            }
            return invocation.proceed();
        }

    Mybatis四大对象以及插件原理

  • 相关阅读:
    【BZOJ4383】[POI2015]Pustynia 线段树优化建图
    【BZOJ4519】[Cqoi2016]不同的最小割 最小割树
    【BZOJ2229】[Zjoi2011]最小割 最小割树
    【BZOJ2151】种树 双向链表+堆(模拟费用流)
    Python入门之Pycharm开发中最常用快捷键
    Python Web学习笔记之GIL机制下的鸡肋多线程
    SQL学习之Can't connect to MySQL server on localhost (10061)
    win10锁屏界面无法更新
    如何安装Pycharm官方统计代码行插件
    Notepad++ 主题配色配置
  • 原文地址:https://www.cnblogs.com/ssskkk/p/11109597.html
Copyright © 2011-2022 走看看