mybatis拦截器进行水平分表

(mybatis 版本3.2.*)

 

import java.sql.Connection;  
import java.util.Properties;  
  
import org.apache.commons.logging.Log;  
import org.apache.commons.logging.LogFactory;  
import org.apache.ibatis.executor.statement.StatementHandler;  
import org.apache.ibatis.mapping.BoundSql;  
import org.apache.ibatis.mapping.MappedStatement;  
import org.apache.ibatis.plugin.Interceptor;  
import org.apache.ibatis.plugin.Intercepts;  
import org.apache.ibatis.plugin.Invocation;  
import org.apache.ibatis.plugin.Plugin;  
import org.apache.ibatis.plugin.Signature;  
import org.apache.ibatis.reflection.MetaObject;  
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;  
import org.apache.ibatis.reflection.factory.ObjectFactory;  
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;  
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;

import rml.model.MUser;
import rml.util.ContextHelper;  
  
  
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })  
public class TableSplitInterceptor implements Interceptor {  
    private Log log =LogFactory.getLog(getClass());  
    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();  
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();  
  
    @Override  
    public Object intercept(Invocation invocation) throws Throwable {  
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();  
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);  
          
        doSplitTable(metaStatementHandler);  
        // 传递给下一个拦截器处理  
        return invocation.proceed();  
  
    }  
  
    @Override  
    public Object plugin(Object target) {  
        // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数  
        if (target instanceof StatementHandler) {  
            return Plugin.wrap(target, this);  
        } else {  
            return target;  
        }  
    }  
  
    @Override  
    public void setProperties(Properties properties) {  
  
    }  
  
    private void doSplitTable(MetaObject metaStatementHandler) throws ClassNotFoundException{  
        String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");  
        if (originalSql != null && !originalSql.equals("")) {  
            log.info("分表前的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);  
            MUser muser = (MUser)metaStatementHandler.getValue("delegate.boundSql.parameterObject");
            // 根据配置自动生成分表SQL  
            TableSplit tableSplit = classObj.getAnnotation(TableSplit.class);  
            if (tableSplit != null && tableSplit.split()) {  
                StrategyManager strategyManager = ContextHelper.getStrategyManager();  
                Strategy strategy=strategyManager.getStrategy(tableSplit.strategy());//获取分表策略来处理分表  
                String convertedSql=originalSql.toLowerCase().replaceAll(tableSplit.value(), strategy.convert(tableSplit.value(), muser.getName()));  
                metaStatementHandler.setValue("delegate.boundSql.sql",convertedSql);  
                log.info("分表后的SQL:"+convertedSql);  
            }  
        }  
    }  
    
}

 

public interface Strategy {
     /** 
     * 传入一个需要分表的表名,返回一个处理后的表名  
     * Strategy必须包含一个无参构造器 
     * @param tableName 
     * @return 
     */  
    public String convert(String tableName, String name);  
}

 

import java.util.List;
import rml.model.MUser;
import rml.split.TableSplit;
@TableSplit(value="muser", strategy="%5")
public interface MUserMapper {
    int deleteByPrimaryKey(String id);

    int insert(MUser record);

    int insertSelective(MUser record);

    MUser selectByPrimaryKey(String id);

    int updateByPrimaryKeySelective(MUser record);

    int updateByPrimaryKey(MUser record);
    
    List<MUser> getAll(MUser record);
}

 

 

 

 

 

import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  
  
@Retention(RetentionPolicy.RUNTIME)  
@Target({ ElementType.TYPE })  
public @interface TableSplit {  
    //是否分表  
     public boolean split() default true;  
     //表名  
     public String value();  
       
     //获取分表策略  
     public String strategy(); 
}

 

 

 

public class NameStrategy implements Strategy{

    @Override
    public String convert(String tableName,String name) {
        StringBuilder sb=new StringBuilder(tableName);  
        sb.append("_");
        sb.append(Integer.parseInt(name)%5);
        return sb.toString();
    }

}

 

 

 

 

import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class StrategyManager{
    private  Log log= LogFactory.getLog(StrategyManager.class);
    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(Entry<String, String> entry : strategies.entrySet()){
            try {
                this.strategies.put(entry.getKey(),(Strategy)Class.forName(entry.getValue()).newInstance());
            } catch (Exception e) {
                log.error("实例化策略出错", e);
            }
        }
        printDebugInfo();
    }
    private void printDebugInfo(){
        StringBuffer msg= new StringBuffer("初始化了"+strategies.size()+"策略");
        for(String key: strategies.keySet()){
            msg.append("\n");
            msg.append(key);
            msg.append("  --->  ");
            msg.append(strategies.get(key));
        }
        log.debug(msg.toString());
    }
}
 

 

 

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import rml.split.StrategyManager;

@Component
public class ContextHelper implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        ContextHelper.context = context;
    }

    public static ApplicationContext getApplicationContext() {
        return ContextHelper.context;
    }

    public static <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }

    public static Object getBean(String name) {
        return context.getBean(name);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return context.getBean(name, clazz);
    }

    public static StrategyManager getStrategyManager() {
        return context.getBean(StrategyManager.class);
    }
}
 

 

 

<!-- 配置分表策略 -->  
    <bean id="strategyManager" class="rml.split.StrategyManager">  
        <property name="strategies">  
            <map>  
                <entry key="%5" value="rml.split.NameStrategy" />  
            </map>  
        </property>  
    </bean>

 

 

 

<?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="rml.split.TableSplitInterceptor" />
    </plugins>
     
</configuration>

 

 

/** 
 * 测试分库分表规则 
 */  
@RunWith(SpringJUnit4ClassRunner.class)    
@ContextConfiguration(locations = { "classpath*:spring.xml, classpath*:spring-mvc.xml, classpath*:spring-mybatis.xml, classpath*:mybatis-config.xml" })    
public class ShardingJdbcMybatisTest {
    @Resource
    public MUserMapper mUserMapper;
    
    @Test    
    public void testuserinsert() {    
        MUser mUser = new MUser();
        mUser.setName("5");
        mUser.setAge(10);
        mUser.setAddress("阿什顿发顺丰");
        Assert.assertEquals(mUserMapper.insert(mUser)>0, true);    
    }    
}

 

 

打印结果

[rml.split.TableSplitInterceptor]分表前的SQL:insert into MUSER (NAME, AGE, ADDRESS)
    values (?, ?, ?)
[org.springframework.beans.factory.support.DefaultListableBeanFactory]Returning cached instance of singleton bean 'strategyManager'
[rml.split.TableSplitInterceptor]分表后的SQL:insert into muser_0 (name, age, address)
    values (?, ?, ?)

 

 

 

 

 

 

转载于:https://my.oschina.net/u/2349117/blog/1821447

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值