super(configuration, transaction);
}
+ @Override
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
final Configuration configuration = ms.getConfiguration();
final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT,
return BATCH_UPDATE_RETURN_VALUE;
}
+ @Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
}
}
+ @Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
import java.lang.reflect.Method;
import java.util.Properties;
+import org.apache.ibatis.executor.BatchExecutor;
import org.apache.ibatis.executor.CachingExecutor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.Interceptor;
public Object plugin(Object target) {
Object result = target;
+ // It avoids one branch when target is not Executor instance.
+ if (!(target instanceof Executor)) {
+ return result;
+ }
+
if (target instanceof CachingExecutor) {
CachingExecutor cachingExecutor = (CachingExecutor) target;
try {
} catch (NoSuchFieldException e) {
LOGGER.error("Error: ", e);
}
- } else if (target instanceof Executor){
+ // Do not override SimpleExecutor because it is used by SelectKeyGenerator (retrieves autoincremented value
+ // from database after INSERT) ReuseBatchExecutor should also work but if MyBatis wants to use SimpleExecutor
+ // why do not stick with it?
+ } else if (target instanceof BatchExecutor){
result = doReuseBatchExecutor((Executor) target);
}
LOGGER.info("Update two Ads");
adTestOne.setAdMobileImage("updatedBildOne.jpg");
+ // 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);
+ // 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);
+ // 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!!!!!
the values which are returned from the cache in the lifetime of the session.
Therefore, as best practice, do not to modify the objects returned by MyBatis.
- SI SE MODIFICAN, CUANDO HAGA UNA BÚSQUEDA EN LA CACHE POR ESE OBJETO, YA NO LO ENCONTRARÉ,
- SERÁ COMO SI NUNCA HUBIERA SIDO CACHEADO, Y ENTONCES LA CACHE NO SIRVE PARA NADA.
+ A) Ver CachingExecutor, se habilita o deshabilita con la opción cacheEnabled:
+ 1. Se hace una query tipo SELECT (no DMLs como UPDATE, INSERT, etc)
+ 2. Se crea una clave basada en la query (el statement)
+ 3. Si la clave no está en la cache, se hace la query (se delega al Executor que haya por debajo)
+ 4. Se guarda el resultado en la cache para esa query.
+ 5. MODIFICO LOS OBJETOS RETORNADOS.
+ 6. Una nueva query igual a la anterior será encontrada en la cache porque la clave es la misma.
+ 7. Yo espero que lo que devuelva la query sea lo que está en base de datos pero como modifiqué
+ los objetos ahora la cache me devuelve los objetos modificados!!!!! DESASTRE TOTAL.
+
+ CONCLUSION: o deshabilitas la cache con cacheEnabled=false o tienes mucho cuidado de NUNCA modificar
+ los objetos retornados.
+
+ LA CACHE SOLO SE USA CUANDO NO HAY DMLs. SI LA QUERY ES UN DML TIPO update, insert, etc, etc,
+ LA CACHE NO SE USARÁ. SOLO SE USA CON selects (POR EJEMPLO).
+
+
+ B) Ver BaseExecutor localCache, no puede ser nunca deshabilitada completamente, solo ponerla como
+ STATEMENT o SESSION con la opción localCacheScope:
+ Ver en BaseExecutor la siguiente linea:
+ list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
+ Pasa exactamente lo mismo que pasaba con CachingExecutor :(
+
+ CONCLUSIÓN: o pones localCache a nivel de STATEMENT con localCacheScope=STATEMENT o tienes mucho
+ cuidado de NUNCA modificar los objetos retornados.
+
+
+ ¿Para qué existe CachingExecutor si ya hay una localCache que puedo poner a nivel de SESSION?
- VER CachingExecutor.
-->
<setting name="cacheEnabled" value="false"/>
<setting name="localCacheScope" value="STATEMENT"/>
<setting name="useColumnLabel" value="false"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
- <setting name="defaultExecutorType" value="SIMPLE"/>
+ <setting name="defaultExecutorType" value="BATCH"/>
<setting name="defaultStatementTimeout" value="5"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
+ http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.2.xsd
+ http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
+ http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
+ http://www.springframework.org/schema/aop/spring-aop.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
+ <!-- Searches for beans in packages (instead of XML configuration we can use in this way annotations like @Service, @Endpoint, etc, etc) -->
+ <context:component-scan base-package="de.example.mybatis"/>
<!--
There is no need to register all your mappers one by one. Instead, you can let MyBatis-Spring scan your classpath for them.