mybatis拦截器Interceptor-按月分表操作

mybatis拦截器Interceptor按月分表操作的项目已放在github上,可以下载查看:链接

--------------------------------------------------------------------------------------------------------------------------------

简单介绍:

      拦截器按月分表操作,采用策略模式,对操作得表标明实现得策略(如按日分表,按月分表等这些都是策略),

      操作表得时候,根据采用得哪种策略进行对数据库表名得修改,从而实现按月分表。

下面内容都是,查看其他博主汇总内容:

一:定义策略注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface TableSplit {

    // 默认使用策略
    boolean split() default true;

    // 表名
    String value();

    // 策略
    String strategy();
}

  假如我们对会员表(users)进行按月分表,需要再会员表得Mapper添加注解(如图):

@TableSplit(value = "users", strategy = "MM")
public interface UsersMapper {
    int deleteByPrimaryKey(Integer uid);

    int insert(Users record);

    int insertSelective(Users record);

    Users selectByPrimaryKey(Integer uid);

    int updateByPrimaryKeySelective(Users record);

    int updateByPrimaryKey(Users record);
}

二:实现策略

在第一步我们提到了策略,并且值是“MM”,现在就是要实现他。

1.首先定义接口,传入表名,返回一个表名:

/**
 * 策略接口(由策略类实现,根据各自的策略返回表名)
 */
public interface Strategy {
    /**
     * 传入一个需要分表的表名,返回一个处理后的表名
     * @param tableName
     * @return
     */
    String returnTableName(String tableName);
}

2.然后实现接口(可以是多个,这个实例是按月分表):

/**
 * 策略
 */
public class MMStrategy implements Strategy {
    @Override
    public String returnTableName(String tableName) {
        SimpleDateFormat sdf = new SimpleDateFormat("MM");
        StringBuilder sb=new StringBuilder(tableName);
        sb.append("_");
        sb.append(sdf.format(new Date()));
        return sb.toString();
    }
}

3.实例化策略类:

/**
 * 实例化策略 通过key找到对应的策略类(xxxStrategy)
 */
public class StrategyManager {
    private Map<String,Strategy> strategies = new ConcurrentHashMap<String,Strategy>(10);

    public  Strategy getStrategy(String key){
        return strategies.get(key);
    }

    public Map<String, Strategy> getStrategies() {
        return strategies;
    }

    public void setStrategies(Map<String, String> strategies) {
        for(Map.Entry<String, String> entry : strategies.entrySet()){
            try {
                this.strategies.put(entry.getKey(),(Strategy)Class.forName(entry.getValue()).newInstance());
            } catch (Exception e) {
                System.out.println("实例化策略出错"+e);
            }
        }
    }
}

4.对Map设值(配置拦截器策略),再配置中加入:

    <!-- 配置拦截器策略 -->
    <bean id="strategyManager" class="com.luck.interceptor.strategy.StrategyManager">
        <property name="strategies">
            <map>
                <entry key="MM" value="com.luck.interceptor.strategy.MMStrategy" />
            </map>
        </property>
    </bean>

 entry中得MM和第一步中得MM是对应的,可以说明MM对应得策略类是MMStrategy。

三:实现 Interceptor接口:

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class TableSegInterceptor implements Interceptor {
    @Autowired
    StrategyManager strategyManager;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("进入拦截器:====================");
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);

        Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
        doSplitTable(metaStatementHandler,parameterObject);
        // 传递给下一个拦截器处理
        return invocation.proceed();

    }

    @Override
    public Object plugin(Object o) {
        // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数
        if (o instanceof StatementHandler) {
            return Plugin.wrap(o, this);
        } else {
            return o;
        }

    }

    @Override
    public void setProperties(Properties properties) {

    }

    private void doSplitTable(MetaObject metaStatementHandler,Object param) throws ClassNotFoundException{

        String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
        if (originalSql != null && !originalSql.equals("")) {
            System.out.println("分表前的SQL:"+originalSql);
            MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
            String id = mappedStatement.getId();
            String className = id.substring(0, id.lastIndexOf("."));
            Class<?> classObj = Class.forName(className);
            // 根据配置自动生成分表SQL
            TableSplit tableSplit = classObj.getAnnotation(TableSplit.class);
            if (tableSplit != null && tableSplit.split()) {
                // StrategyManager可以使用ContextHelper策略帮助类获取,本次使用注入
                String key = tableSplit.strategy();
                // 根据key获取策略类
                Strategy strategy = strategyManager.getStrategy(key);
                String convertedSql= null;
                try {
                    convertedSql = originalSql.replaceAll(tableSplit.value(), strategy.returnTableName(tableSplit.value()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                metaStatementHandler.setValue("delegate.boundSql.sql",convertedSql);
                System.out.println("分表后的SQL:"+convertedSql);
            }
        }
    }

前面所做得一切都是为了这一步,目的就是找到根据策略返回得新表名。

到这里基本上已经完成了-----------------

猜你喜欢

转载自blog.csdn.net/qq_37751454/article/details/81630100