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);
}
}
}
四.配置mybatis拦截器
在sqlSessionFactory中配置TableSegInterceptor
即: <bean id="tableSegInterceptor" class="com.luck.interceptor.TableSegInterceptor"/>
// 我的sqlSessionFactory配置
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource"/>
<property name="mapperLocations" value="classpath:sqlmap/*Mapper.xml"/>
<!-- 分页插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<value>
dialect=mysql
</value>
</property>
</bean>
<!-- 使用mybatis拦截器-->
<bean id="tableSegInterceptor" class="com.luck.interceptor.TableSegInterceptor"/>
</array>
</property>
</bean>
前面所做得一切都是为了这一步,目的就是找到根据策略返回得新表名。
到这里基本上已经完成了-----------------