|
|
@@ -0,0 +1,227 @@ |
|
|
|
|
|
package com.iformall.plugin.shard.plugin; |
|
|
|
|
|
|
|
|
|
|
|
import net.sf.jsqlparser.JSQLParserException; |
|
|
|
|
|
import net.sf.jsqlparser.expression.Expression; |
|
|
|
|
|
import net.sf.jsqlparser.expression.Parenthesis; |
|
|
|
|
|
import net.sf.jsqlparser.expression.StringValue; |
|
|
|
|
|
import net.sf.jsqlparser.expression.operators.conditional.AndExpression; |
|
|
|
|
|
import net.sf.jsqlparser.expression.operators.conditional.OrExpression; |
|
|
|
|
|
import net.sf.jsqlparser.expression.operators.relational.EqualsTo; |
|
|
|
|
|
import net.sf.jsqlparser.expression.operators.relational.ExpressionList; |
|
|
|
|
|
import net.sf.jsqlparser.expression.operators.relational.ItemsList; |
|
|
|
|
|
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList; |
|
|
|
|
|
import net.sf.jsqlparser.parser.CCJSqlParserUtil; |
|
|
|
|
|
import net.sf.jsqlparser.schema.Column; |
|
|
|
|
|
import net.sf.jsqlparser.schema.Table; |
|
|
|
|
|
import net.sf.jsqlparser.statement.Statement; |
|
|
|
|
|
import net.sf.jsqlparser.statement.create.table.ColDataType; |
|
|
|
|
|
import net.sf.jsqlparser.statement.create.table.ColumnDefinition; |
|
|
|
|
|
import net.sf.jsqlparser.statement.create.table.CreateTable; |
|
|
|
|
|
import net.sf.jsqlparser.statement.delete.Delete; |
|
|
|
|
|
import net.sf.jsqlparser.statement.insert.Insert; |
|
|
|
|
|
import net.sf.jsqlparser.statement.select.*; |
|
|
|
|
|
import net.sf.jsqlparser.statement.update.Update; |
|
|
|
|
|
import net.sf.jsqlparser.util.TablesNamesFinder; |
|
|
|
|
|
import org.apache.ibatis.executor.statement.StatementHandler; |
|
|
|
|
|
import org.apache.ibatis.mapping.BoundSql; |
|
|
|
|
|
import org.apache.ibatis.mapping.MappedStatement; |
|
|
|
|
|
import org.apache.ibatis.mapping.ParameterMapping; |
|
|
|
|
|
import org.apache.ibatis.mapping.SqlCommandType; |
|
|
|
|
|
import org.apache.ibatis.plugin.*; |
|
|
|
|
|
import org.apache.ibatis.reflection.MetaObject; |
|
|
|
|
|
import org.apache.ibatis.reflection.SystemMetaObject; |
|
|
|
|
|
import org.apache.ibatis.session.Configuration; |
|
|
|
|
|
import org.apache.ibatis.session.ResultHandler; |
|
|
|
|
|
|
|
|
|
|
|
import com.iformall.plugin.shard.annotation.IgnoreSharding; |
|
|
|
|
|
import com.iformall.plugin.shard.impl.ShardingRuleExcuter; |
|
|
|
|
|
import com.iformall.plugin.shard.impl.ShardingSphere; |
|
|
|
|
|
import com.iformall.plugin.shard.impl.ShardingTableExcuter; |
|
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
|
import java.sql.Connection; |
|
|
|
|
|
import java.util.Arrays; |
|
|
|
|
|
import java.util.HashMap; |
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
import java.util.Map; |
|
|
|
|
|
import java.util.Properties; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
*分表 |
|
|
|
|
|
*/ |
|
|
|
|
|
@Intercepts({ |
|
|
|
|
|
//@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), |
|
|
|
|
|
//@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) |
|
|
|
|
|
@Signature( method = "prepare", type = StatementHandler.class,args = {Connection.class, Integer.class}), |
|
|
|
|
|
@Signature(method = "query", type = StatementHandler.class, args = {java.sql.Statement.class, ResultHandler.class}) |
|
|
|
|
|
}) |
|
|
|
|
|
public class ShardingSpherePlugin implements Interceptor { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ShardingSpherePlugin(){ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//属性参数信息 |
|
|
|
|
|
private Properties properties; |
|
|
|
|
|
private String dialect = "mysql"; |
|
|
|
|
|
private List<ShardingSphere> ShardingSpheres; |
|
|
|
|
|
public String getDialect() { |
|
|
|
|
|
return dialect; |
|
|
|
|
|
} |
|
|
|
|
|
public void setDialect(String dialect) { |
|
|
|
|
|
this.dialect = dialect; |
|
|
|
|
|
} |
|
|
|
|
|
public List<ShardingSphere> getShardingSpheres() { |
|
|
|
|
|
return ShardingSpheres; |
|
|
|
|
|
} |
|
|
|
|
|
public void setShardingSpheres(List<ShardingSphere> shardingSpheres) { |
|
|
|
|
|
ShardingSpheres = shardingSpheres; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 生成代理对象 |
|
|
|
|
|
* |
|
|
|
|
|
* @param target |
|
|
|
|
|
* @return |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
public Object plugin(Object target) { |
|
|
|
|
|
if (target instanceof StatementHandler) { |
|
|
|
|
|
return Plugin.wrap(target, this); |
|
|
|
|
|
} else { |
|
|
|
|
|
return target; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 获取配置信息 |
|
|
|
|
|
* {dialect=mysql, tenantInfo=org.xue.test.TenantInfoImpl, tenantIdColumn=tenant_id, parentTenantIdColumn=parent_tenant_id} |
|
|
|
|
|
* @param properties |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
public void setProperties(Properties properties) { |
|
|
|
|
|
this.properties=properties; |
|
|
|
|
|
this.dialect = this.properties.getProperty("dialect"); |
|
|
|
|
|
if (null != this.ShardingSpheres) { |
|
|
|
|
|
for (ShardingSphere ss : this.ShardingSpheres) { |
|
|
|
|
|
ShardingTableExcuter.setTableSharding(ss.getTableName(), ss); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Method findMethod(Method[] methods, String methodName) { |
|
|
|
|
|
for (Method method : methods) { |
|
|
|
|
|
if (method.getName().equals(methodName)) { |
|
|
|
|
|
return method; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
public Object intercept(Invocation invocation) throws Throwable { |
|
|
|
|
|
if (!ShardingTableExcuter.hasShardingConfig()) { |
|
|
|
|
|
return invocation.proceed(); |
|
|
|
|
|
} |
|
|
|
|
|
StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); |
|
|
|
|
|
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); |
|
|
|
|
|
MappedStatement ms = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); |
|
|
|
|
|
String id = ms.getId(); |
|
|
|
|
|
String className = id.substring(0, id.lastIndexOf(".")); |
|
|
|
|
|
String methodName = id.substring(id.lastIndexOf(".") + 1); |
|
|
|
|
|
Class<?> clazz = Class.forName(className); |
|
|
|
|
|
Method method = findMethod(clazz.getDeclaredMethods(), methodName); |
|
|
|
|
|
if (method != null) { |
|
|
|
|
|
IgnoreSharding ignore = method.getAnnotation(IgnoreSharding.class); |
|
|
|
|
|
if (null == ignore) { |
|
|
|
|
|
//Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration"); |
|
|
|
|
|
Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject"); |
|
|
|
|
|
BoundSql boundSql = statementHandler.getBoundSql(); |
|
|
|
|
|
String newSQL = buildTable(boundSql,parameterObject); |
|
|
|
|
|
metaStatementHandler.setValue("delegate.boundSql.sql", newSQL); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return invocation.proceed(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildTable(BoundSql boundSql,Object parameterObject) throws JSQLParserException { |
|
|
|
|
|
String oldSql = boundSql.getSql(); |
|
|
|
|
|
Statement stmt = CCJSqlParserUtil.parse(oldSql); |
|
|
|
|
|
if (stmt instanceof Insert) { |
|
|
|
|
|
return buildInsert((Insert) stmt,oldSql,parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (stmt instanceof Delete) { |
|
|
|
|
|
return buildDelete((Delete) stmt,oldSql,parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (stmt instanceof Update) { |
|
|
|
|
|
return buildUpdate((Update) stmt,oldSql,parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (stmt instanceof Select) { |
|
|
|
|
|
return buildSelect((Select) stmt,oldSql,parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (stmt instanceof CreateTable) { |
|
|
|
|
|
return oldSql; |
|
|
|
|
|
} |
|
|
|
|
|
throw new RuntimeException("非法sql语句,请检查"+oldSql); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildInsert(Insert stmt,String oldSql,Object parameterObject) { |
|
|
|
|
|
return buildTable(stmt.getTable(), oldSql, parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildDelete(Delete stmt,String oldSql,Object parameterObject) { |
|
|
|
|
|
return buildTable(stmt.getTable(), oldSql, parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildUpdate(Update stmt,String oldSql,Object parameterObject) { |
|
|
|
|
|
return buildListTables(stmt.getTables(), oldSql, parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildSelect(Select stmt,String oldSql,Object parameterObject) { |
|
|
|
|
|
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); |
|
|
|
|
|
List<String> tableList = tablesNamesFinder.getTableList(stmt); |
|
|
|
|
|
return buildByListTableNames(tableList, oldSql, parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildByTableName(String table,String oldSql,Object parameterObject) { |
|
|
|
|
|
if (!ShardingTableExcuter.isShardingTable(table)) { |
|
|
|
|
|
return oldSql; |
|
|
|
|
|
} |
|
|
|
|
|
String newtable = getShareTable(table,parameterObject); |
|
|
|
|
|
return oldSql.replaceAll(table, newtable); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildTable(Table table,String oldSql,Object parameterObject) { |
|
|
|
|
|
return buildByTableName(table.getName(), oldSql, parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildListTables(List<Table> tables,String oldSql,Object parameterObject) { |
|
|
|
|
|
for (Table t : tables) { |
|
|
|
|
|
oldSql = buildTable(t,oldSql,parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
return oldSql; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildByListTableNames(List<String> tables,String oldSql,Object parameterObject) { |
|
|
|
|
|
for (String t : tables) { |
|
|
|
|
|
oldSql = buildByTableName(t,oldSql,parameterObject); |
|
|
|
|
|
} |
|
|
|
|
|
return oldSql; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String getShareTable(String table,Object parameterObject) { |
|
|
|
|
|
ShardingSphere ss = ShardingTableExcuter.getShardingSphere(table); |
|
|
|
|
|
return ss.getTableName()+ShardingSphere.TABLE_SUFFIX+ShardingRuleExcuter.getTableIndex(ss.getRule(), getValue(ss.getColumn(),parameterObject), ss.getCount()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Object getValue(String column,Object parameterObject) { |
|
|
|
|
|
if (parameterObject instanceof Map) { |
|
|
|
|
|
return ((Map) parameterObject).get(column); |
|
|
|
|
|
} |
|
|
|
|
|
return parameterObject; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |