|
@@ -0,0 +1,111 @@
|
|
|
|
|
+package org.jeecg.ctop.material.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+import org.apache.ibatis.executor.Executor;
|
|
|
|
|
+import org.apache.ibatis.mapping.MappedStatement;
|
|
|
|
|
+import org.apache.ibatis.mapping.SqlCommandType;
|
|
|
|
|
+import org.apache.ibatis.plugin.*;
|
|
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
|
|
+import java.sql.Connection;
|
|
|
|
|
+import java.sql.Statement;
|
|
|
|
|
+import java.util.Properties;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * MyBatis拦截器,在执行SQL前设置TiFlash引擎
|
|
|
|
|
+ * 最简单的TiFlash配置方案
|
|
|
|
|
+ */
|
|
|
|
|
+@Intercepts({
|
|
|
|
|
+ @Signature(type = Executor.class, method = "query",
|
|
|
|
|
+ args = {MappedStatement.class, Object.class,
|
|
|
|
|
+ org.apache.ibatis.session.RowBounds.class,
|
|
|
|
|
+ org.apache.ibatis.session.ResultHandler.class}),
|
|
|
|
|
+ @Signature(type = Executor.class, method = "update",
|
|
|
|
|
+ args = {MappedStatement.class, Object.class})
|
|
|
|
|
+})
|
|
|
|
|
+@Component // 关键:添加@Component注解让Spring管理
|
|
|
|
|
+public class TiFlashInterceptor implements Interceptor {
|
|
|
|
|
+
|
|
|
|
|
+ private static final String SET_SQL =
|
|
|
|
|
+ "SET session tidb_isolation_read_engines = 'tiflash,tidb'";
|
|
|
|
|
+
|
|
|
|
|
+ // ThreadLocal记录每个连接是否已设置,避免重复设置
|
|
|
|
|
+ private ThreadLocal<Boolean> tiFlashSet = ThreadLocal.withInitial(() -> false);
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Object intercept(Invocation invocation) throws Throwable {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 获取MappedStatement
|
|
|
|
|
+ MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
|
|
|
|
|
+
|
|
|
|
|
+ // 只对SELECT查询设置TiFlash(可选,根据需求调整)
|
|
|
|
|
+ if (ms.getSqlCommandType() == SqlCommandType.SELECT) {
|
|
|
|
|
+ setTiFlashIfNeeded(invocation);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 如果要对所有SQL都设置,可以去掉上面的if判断
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ // 捕获异常但不中断SQL执行
|
|
|
|
|
+ System.err.println("TiFlash拦截器异常: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 继续执行原始SQL
|
|
|
|
|
+ return invocation.proceed();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 设置TiFlash引擎(如果需要)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void setTiFlashIfNeeded(Invocation invocation) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 检查是否已设置
|
|
|
|
|
+ if (tiFlashSet.get()) {
|
|
|
|
|
+ return; // 已设置,跳过
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取数据库连接
|
|
|
|
|
+ Connection connection = getConnection(invocation);
|
|
|
|
|
+ if (connection != null) {
|
|
|
|
|
+ try (Statement stmt = connection.createStatement()) {
|
|
|
|
|
+ stmt.execute(SET_SQL);
|
|
|
|
|
+ tiFlashSet.set(true); // 标记已设置
|
|
|
|
|
+ System.out.println("✅ TiFlash引擎已设置");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ System.err.println("设置TiFlash失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 通过反射获取当前数据库连接
|
|
|
|
|
+ */
|
|
|
|
|
+ private Connection getConnection(Invocation invocation) throws Exception {
|
|
|
|
|
+ // 获取Executor对象
|
|
|
|
|
+ Executor executor = (Executor) invocation.getTarget();
|
|
|
|
|
+
|
|
|
|
|
+ // 反射获取transaction字段
|
|
|
|
|
+ java.lang.reflect.Field transactionField =
|
|
|
|
|
+ Executor.class.getDeclaredField("transaction");
|
|
|
|
|
+ transactionField.setAccessible(true);
|
|
|
|
|
+ Object transaction = transactionField.get(executor);
|
|
|
|
|
+
|
|
|
|
|
+ // 反射获取connection字段
|
|
|
|
|
+ java.lang.reflect.Field connectionField =
|
|
|
|
|
+ transaction.getClass().getDeclaredField("connection");
|
|
|
|
|
+ connectionField.setAccessible(true);
|
|
|
|
|
+
|
|
|
|
|
+ return (Connection) connectionField.get(transaction);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Object plugin(Object target) {
|
|
|
|
|
+ // 包装目标对象
|
|
|
|
|
+ return Plugin.wrap(target, this);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void setProperties(Properties properties) {
|
|
|
|
|
+ // 可以读取配置文件中的属性
|
|
|
|
|
+ System.out.println("TiFlash拦截器初始化...");
|
|
|
|
|
+ }
|
|
|
|
|
+}
|