From e0b2cb6b1cd16873ca9076ee99f81d8abb68b614 Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Sun, 10 Apr 2016 20:58:54 +0200 Subject: [PATCH] MyBatis interceptors: trying to change SQL statements in run time. No way with MyBatis :( --- ...geQueryBoundStatementsInRunTimeInterceptor.java | 50 ++++++++++++++++++++++ .../ChangeQueryStatementsInRunTimeInterceptor.java | 49 +++++++++++++++++++++ ...ChangeUpdateStatementsInRunTimeInterceptor.java | 47 ++++++++++++++++++++ .../spring/service/impl/ExampleServiceImpl.java | 26 ++++++++++- .../src/main/resources/config/mybatis-config.xml | 6 +++ 5 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryBoundStatementsInRunTimeInterceptor.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryStatementsInRunTimeInterceptor.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeUpdateStatementsInRunTimeInterceptor.java 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 index 0000000..4c3e1a0 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryBoundStatementsInRunTimeInterceptor.java @@ -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 index 0000000..6d6988b --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeQueryStatementsInRunTimeInterceptor.java @@ -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 index 0000000..0e5e5e9 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ChangeUpdateStatementsInRunTimeInterceptor.java @@ -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) { + } + +} diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java index 0c9f2ef..04a55fb 100644 --- a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java @@ -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"); diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml index 9b9e9fd..a4cd5c0 100644 --- a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml @@ -78,6 +78,12 @@ + + + + + + \ No newline at end of file -- 2.1.4