基于mybatis 手写分表
时间: 2023-06-28 14:11:24 浏览: 157
Mybatis并不提供分表的功能,但是可以通过自定义插件来实现分表。
以下是一个简单的分表插件示例:
首先,创建一个自定义插件类TableShardPlugin:
```java
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class TableShardPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameter = invocation.getArgs()[1];
// 获取注解
TableShard tableShard = mappedStatement.getMethod().getAnnotation(TableShard.class);
if (tableShard == null) {
return invocation.proceed();
}
// 获取分表字段的值
String shardValue = "";
try {
Field field = parameter.getClass().getDeclaredField(tableShard.shardField());
field.setAccessible(true);
shardValue = String.valueOf(field.get(parameter));
} catch (Exception e) {
throw new RuntimeException("get shardValue error", e);
}
// 获取分表规则
TableShardStrategy strategy = tableShard.shardStrategy().newInstance();
// 获取分表后缀
String suffix = strategy.getSuffix(shardValue);
// 修改sql语句
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
String sql = boundSql.getSql().replace(tableShard.tableName(), tableShard.tableName() + "_" + suffix);
BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
MappedStatement newMappedStatement = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));
invocation.getArgs()[0] = newMappedStatement;
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {}
private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
builder.resource(ms.getResource());
builder.fetchSize(ms.getFetchSize());
builder.statementType(ms.getStatementType());
builder.keyGenerator(ms.getKeyGenerator());
builder.timeout(ms.getTimeout());
builder.parameterMap(ms.getParameterMap());
builder.resultMaps(ms.getResultMaps());
builder.resultSetType(ms.getResultSetType());
builder.cache(ms.getCache());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());
return builder.build();
}
private static class BoundSqlSqlSource implements SqlSource {
private BoundSql boundSql;
public BoundSqlSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}
}
```
然后,创建一个注解TableShard:
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TableShard {
String tableName();
String shardField();
Class<? extends TableShardStrategy> shardStrategy();
}
```
最后,实现分表策略接口TableShardStrategy:
```java
public interface TableShardStrategy {
String getSuffix(String shardValue);
}
```
使用示例:
```java
@Mapper
public interface UserMapper {
@TableShard(tableName = "user", shardField = "id", shardStrategy = UserIdModShardStrategy.class)
int insert(User user);
}
```
其中,UserIdModShardStrategy是一个分表策略实现类,根据用户id取模得到分表后缀。
```java
public class UserIdModShardStrategy implements TableShardStrategy {
@Override
public String getSuffix(String shardValue) {
int mod = Integer.parseInt(shardValue) % 10;
return String.valueOf(mod);
}
}
```
以上就是一个简单的手写Mybatis分表插件实现。
阅读全文