MyBatis interceptors: trying to change SQL statements in run time.
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 10 Apr 2016 18:58:54 +0000 (20:58 +0200)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 10 Apr 2016 18:58:54 +0000 (20:58 +0200)
No way with MyBatis :(

MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryBoundStatementsInRunTimeInterceptor.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryStatementsInRunTimeInterceptor.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeUpdateStatementsInRunTimeInterceptor.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml

diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryBoundStatementsInRunTimeInterceptor.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryBoundStatementsInRunTimeInterceptor.java
new file mode 100644 (file)
index 0000000..4c3e1a0
--- /dev/null
@@ -0,0 +1,50 @@
+package de.example.mybatis.interceptor;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.Executor;
+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.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+
+@Intercepts({@Signature(
+                 type= Executor.class,
+                 method = "query",
+                 args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})})
+public class ChangeQueryBoundStatementsInRunTimeInterceptor implements Interceptor {
+
+       @Override
+       public Object intercept(Invocation invocation) throws Throwable {
+               Method method = invocation.getMethod();
+               Object[] args = invocation.getArgs();
+               Object target = invocation.getTarget();
+               
+               final MappedStatement stmt = (MappedStatement) args[0];
+               final Object parameter = args[1];
+               final BoundSql boundSql = stmt.getBoundSql(parameter);
+               final String sql = boundSql.getSql();
+               
+               // THIS CODE IS USELESS. I WANTED TO CHANGE IN RUN TIME THE sql CODE BUT IT IS IMPOSSIBLE
+               // TO SET THE NEW sql STATEMENT TO THE CURRENT MappedStatement. Why MyBatis, whyyyyyyyyy???!!! :(
+               
+               return invocation.proceed();
+       }
+
+       @Override
+       public Object plugin(Object target) {
+               return Plugin.wrap(target, this);
+       }
+
+       @Override
+       public void setProperties(Properties properties) {
+       }
+
+}
\ No newline at end of file
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryStatementsInRunTimeInterceptor.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryStatementsInRunTimeInterceptor.java
new file mode 100644 (file)
index 0000000..6d6988b
--- /dev/null
@@ -0,0 +1,49 @@
+package de.example.mybatis.interceptor;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.ibatis.executor.Executor;
+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.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+
+@Intercepts({@Signature(
+                 type= Executor.class,
+                 method = "query",
+                 args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
+public class ChangeQueryStatementsInRunTimeInterceptor implements Interceptor {
+
+       @Override
+       public Object intercept(Invocation invocation) throws Throwable {
+               Method method = invocation.getMethod();
+               Object[] args = invocation.getArgs();
+               Object target = invocation.getTarget();
+               
+               final MappedStatement stmt = (MappedStatement) args[0];
+               final Object parameter = args[1];
+               final BoundSql boundSql = stmt.getBoundSql(parameter);
+               final String sql = boundSql.getSql();
+               
+               // THIS CODE IS USELESS. I WANTED TO CHANGE IN RUN TIME THE sql CODE BUT IT IS IMPOSSIBLE
+               // TO SET THE NEW sql STATEMENT TO THE CURRENT MappedStatement. Why MyBatis, whyyyyyyyyy???!!! :(
+               
+               return invocation.proceed();
+       }
+
+       @Override
+       public Object plugin(Object target) {
+               return Plugin.wrap(target, this);
+       }
+
+       @Override
+       public void setProperties(Properties properties) {
+       }
+
+}
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeUpdateStatementsInRunTimeInterceptor.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeUpdateStatementsInRunTimeInterceptor.java
new file mode 100644 (file)
index 0000000..0e5e5e9
--- /dev/null
@@ -0,0 +1,47 @@
+package de.example.mybatis.interceptor;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.ibatis.executor.Executor;
+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;
+
+@Intercepts({@Signature(
+                 type= Executor.class,
+                 method = "update",
+                 args = {MappedStatement.class, Object.class})})
+public class ChangeUpdateStatementsInRunTimeInterceptor implements Interceptor {
+
+       @Override
+       public Object intercept(Invocation invocation) throws Throwable {
+               Method method = invocation.getMethod();
+               Object[] args = invocation.getArgs();
+               Object target = invocation.getTarget();
+               
+               final MappedStatement stmt = (MappedStatement) args[0];
+               final Object parameter = args[1];
+               final BoundSql boundSql = stmt.getBoundSql(parameter);
+               final String sql = boundSql.getSql();
+               
+               // THIS CODE IS USELESS. I WANTED TO CHANGE IN RUN TIME THE sql CODE BUT IT IS IMPOSSIBLE
+               // TO SET THE NEW sql STATEMENT TO THE CURRENT MappedStatement. Why MyBatis, whyyyyyyyyy???!!! :(
+               
+               return invocation.proceed();
+       }
+
+       @Override
+       public Object plugin(Object target) {
+               return Plugin.wrap(target, this);
+       }
+
+       @Override
+       public void setProperties(Properties properties) {
+       }
+
+}
index 0c9f2ef..04a55fb 100644 (file)
@@ -83,6 +83,9 @@ public class ExampleServiceImpl implements ExampleService {
                // If there is no transaction the cache is useless because after every DML will be cleaned up. Without transaction
                // REUSE and SIMPLE are the same. With transaction REUSE skips the code calling getConnection. With transaction
                // getConnection returns always the same connection. So, with transaction we can avoid some CPU cycles using REUSE.
+               
+               // With Spring-MyBatis operations are ONLY batched when running this code in some transaction. Otherwise BATCH mode is useless
+               // because statements will be flushed once they are executed.
 
                final Ad adTestTwo = new Ad();
                adTestTwo.setAdMobileImage("bildTwo.jpg");
@@ -100,19 +103,38 @@ public class ExampleServiceImpl implements ExampleService {
                // WARNING!!! adTestOne.id keeps being NULL when using BATCH Executor of MyBatis!!!!
                //            So, this code will do ANYTHING AT ALL!!!!
                // BE CAREFUL WHEN USING BATCH MODE FOR ACCESSING DATA BASES!!!!
-               adMapper.updateByPrimaryKey(adTestOne);
+               long countOne = adMapper.updateByPrimaryKey(adTestOne);
                
                // WARNING!!! adTestTwo.id keeps being NULL when using BATCH Executor of MyBatis!!!!
                //            So, this code will do ANYTHING AT ALL!!!!
                // BE CAREFUL WHEN USING BATCH MODE FOR ACCESSING DATA BASES!!!!
                adTestTwo.setAdMobileImage("updatedBildTwo.jpg");
-               adMapper.updateByPrimaryKey(adTestTwo);
+               long countTwo = adMapper.updateByPrimaryKey(adTestTwo);
                
                // IF YOU WANT BATCH MODE FOR ACCESSING DATA BASES YOUR CODE MUST BE IMPLEMENTED FOR BATCH MODE.
                // I MEAN, IN THIS EXAMPLE SIMPLE MODE WILL WORK BUT BATCH MODE WILL NOT WORK IN ANY WAY!!!!
                // BATCH has some implications that must not be forgotten. You can not abstract your code
                // from the access mode to your data base!!!!!
                
+               // BATCH MODE: no transaction
+               // countOne.id = BatchExecutor.BATCH_UPDATE_RETURN_VALUE  <-------------- IF YOU WANT TO USE BATCH MODE, YOUR CODE MUST BE IMPLEMENTED KNOWING THIS KIND OF STUFF!!!!
+               // But because there is no transaction statement is always flushed once it is executed.
+               // So, in BATCH mode and without transaction we do not return the number of updated rows but the statement was
+               // immediately flushed. :/
+               // BATCH MODE: transaction
+               // countOne.id = BatchExecutor.BATCH_UPDATE_RETURN_VALUE  <-------------- IF YOU WANT TO USE BATCH MODE, YOUR CODE MUST BE IMPLEMENTED KNOWING THIS KIND OF STUFF!!!!
+               // SIMPLE MODE: no transaction
+               // countOne.id = 1
+               // SIMPLE MODE: transaction
+               // countOne.id = 1
+               // REUSE MODE: no transaction
+               // countOne.id = 1
+               // REUSE MODE: transaction
+               // countOne.id = 1
+               
+               // With Spring-MyBatis operations are ONLY batched when running this code in some transaction. Otherwise BATCH mode is useless.
+               // because statements will be flushed once they are executed.
+               
                
                
                LOGGER.info("Insert two new Ads");
index 9b9e9fd..a4cd5c0 100644 (file)
   <plugins>
     <plugin interceptor="de.example.mybatis.interceptor.ReuseBatchExecutorInterceptor">
     </plugin>
+    <plugin interceptor="de.example.mybatis.interceptor.ChangeUpdateStatementsInRunTimeInterceptor">
+    </plugin>
+    <plugin interceptor="de.example.mybatis.interceptor.ChangeQueryStatementsInRunTimeInterceptor">
+    </plugin>
+    <plugin interceptor="de.example.mybatis.interceptor.ChangeQueryBoundStatementsInRunTimeInterceptor">
+    </plugin>
   </plugins>
   
 </configuration>
\ No newline at end of file