MyBatis: ReuseBatchExecutor
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 10 Apr 2016 01:17:45 +0000 (03:17 +0200)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 10 Apr 2016 01:17:45 +0000 (03:17 +0200)
19 files changed:
MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/pom.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/executor/ReuseBatchExecutor.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ReuseBatchExecutorInterceptor.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/mapper/filter/MyBatisScanFilter.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/model/Ad.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/repository/mapper/AdMapper.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/SpringContextLocator.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/TestMain.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/ExampleService.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/de/example/mybatis/repository/mapper/AdMapper.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/generator/generatorConfig.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/ddlChangelog.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/dmlChangelog.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/liquibaseChangeLogs.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/log4j2.xml [new file with mode: 0644]
MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/spring-config.xml [new file with mode: 0644]

diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt
new file mode 100644 (file)
index 0000000..2272363
--- /dev/null
@@ -0,0 +1,34 @@
+
+export M2_HOME=/opt/maven/apache-maven-2.2.1
+PATH=$M2_HOME/bin:$PATH
+
+mvn clean install -Dmaven.test.skip=true
+mvn dependency:sources
+mvn dependency:resolve -Dclassifier=javadoc
+
+
+# I am using the mybatis-generator maven plugin. So, I need always a database (it would be better to use the Eclipse plugin)
+mysql -uroot -proot -e "CREATE DATABASE mybatis_example DEFAULT CHARACTER SET utf8"
+
+mysql -uroot -proot -e "USE mybatis_example; CREATE TABLE ad (id SERIAL, company_id BIGINT, company_categ_id BIGINT, ad_gps BLOB, ad_mobile_image varchar(255), created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB, DEFAULT CHARSET=utf8, COLLATE=utf8_unicode_ci"
+
+mysql -uroot -proot -e "USE mybatis_example; CREATE TABLE ad_description (id SERIAL, laguage_id BIGINT NOT NULL, ad_id BIGINT(20) UNSIGNED NOT NULL, ad_name VARCHAR(255) NOT NULL, ad_description LONGTEXT, ad_mobile_text VARCHAR(500) NOT NULL, ad_link VARCHAR(3000) NOT NULL, PRIMARY KEY (id), INDEX(ad_id), FOREIGN KEY (ad_id) REFERENCES ad (id) ON DELETE CASCADE) ENGINE=InnoDB, DEFAULT CHARSET=utf8, COLLATE=utf8_unicode_ci"
+
+# Run mvn clean install (mybatis-generator plugin creates autogenerated code from tables)
+mvn clean install
+
+# Drop database (we want to check liquibase is working with Spring)
+mysql -uroot -proot -A -e "drop database mybatis_example"
+
+# Liquibase requires (AFAIK) of an existing schema
+mysql -uroot -proot -e "CREATE DATABASE mybatis_example DEFAULT CHARACTER SET utf8"
+
+# Run TestMain.java :)
+
+
+# Useful commands for liquibase that I used in order to create the changelog files from an existing schema.
+# Changelog from DDL. Creates DDL changelog from current database (if schema was previously created without liquibase as above)
+/opt/liquibase/liquibase --driver=com.mysql.jdbc.Driver --classpath=$HOME/.m2/repository/mysql/mysql-connector-java/5.1.9/mysql-connector-java-5.1.9.jar --logLevel=debug --changeLogFile=src/main/resources/liquibase/ddlChangelog.xml --url="jdbc:mysql://localhost/mybatis_example" --username=root --password=root generateChangeLog 
+
+# Changelog for DML. Creates DML changelog from current database (if there are data)
+/opt/liquibase/liquibase --driver=com.mysql.jdbc.Driver --classpath=$HOME/.m2/repository/mysql/mysql-connector-java/5.1.9/mysql-connector-java-5.1.9.jar --logLevel=debug --changeLogFile=src/main/resources/liquibase/dmlChangelog.xml --url="jdbc:mysql://localhost/mybatis_example" --username=root --password=root --diffTypes="data" generateChangeLog
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/pom.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/pom.xml
new file mode 100644 (file)
index 0000000..f398c19
--- /dev/null
@@ -0,0 +1,179 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>de.example.mybatis</groupId>
+  <artifactId>mybatis-spring-reusebatchexecutor</artifactId>
+  <packaging>jar</packaging>
+  <version>1.0-SNAPSHOT</version>
+  <name>mybatis-spring-reusebatchexecutor</name>
+  <url>http://gumartinm.name</url>
+  <properties>
+    <mybatis.generator.outputdirectory>${project.build.directory}/generated-sources/mybatis-generator/</mybatis.generator.outputdirectory>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <liquibase.version>3.4.2</liquibase.version>
+  </properties>
+  <dependencies>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-context</artifactId>
+        <version>4.2.5.RELEASE</version>
+        <!-- 
+            Required dependency for getting rid of commons logging and use my own logging library
+            (in my case I decided to use log4j 2 under slf4j)
+        -->
+        <exclusions>
+            <exclusion>
+                <groupId>commons-logging</groupId>
+                <artifactId>commons-logging</artifactId>
+            </exclusion>
+        </exclusions>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-jdbc</artifactId>
+        <version>4.2.5.RELEASE</version>
+        <!-- 
+            Required dependency for getting rid of commons logging and use my own logging library
+            (in my case I decided to use log4j 2 under slf4j)
+        -->
+        <exclusions>
+            <exclusion>
+                <groupId>commons-logging</groupId>
+                <artifactId>commons-logging</artifactId>
+            </exclusion>
+        </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>cglib</groupId>
+      <artifactId>cglib</artifactId>
+      <version>3.2.1</version>
+    </dependency>
+
+
+    <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis-spring</artifactId>
+        <version>1.2.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis</artifactId>
+      <version>3.3.1</version>
+    </dependency>
+
+    <dependency>
+        <groupId>com.mchange</groupId>
+        <artifactId>c3p0</artifactId>
+        <version>0.9.5.2</version>
+    </dependency>
+    <dependency>
+        <groupId>mysql</groupId>
+        <artifactId>mysql-connector-java</artifactId>
+        <version>5.1.38</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.liquibase</groupId>
+      <artifactId>liquibase-core</artifactId>
+      <version>${liquibase.version}</version>
+    </dependency>
+
+    <!--
+        1/3 Required dependency for log4j 2 with slf4j: binding between log4j 2 and slf4j
+    -->
+    <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-slf4j-impl</artifactId>
+        <version>2.3</version>
+    </dependency>
+    <!--
+        2/3 Required dependency for log4j 2 with slf4j: log4j 2 maven plugin (it is the log4j 2 implementation)
+    -->
+    <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-core</artifactId>
+        <version>2.3</version>
+    </dependency>
+    <!-- 
+        3/3 Required dependency for getting rid of commons logging.
+        This is the BRIDGE (no binding) between Jakarta Commons Logging (used by Spring) and whatever
+        I am using for logging (in this case I am using log4j 2)
+        See: http://www.slf4j.org/legacy.html
+        
+        We need exclusions in every dependency using Jakarta Commons Logging (see Spring dependencies below)
+     -->
+    <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>jcl-over-slf4j</artifactId>
+        <version>1.7.12</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+        <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <version>3.3</version>
+            <configuration>
+                <source>1.8</source>
+                <target>1.8</target>
+                <encoding>${project.build.sourceEncoding}</encoding>
+            </configuration>
+        </plugin>
+        <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-resources-plugin</artifactId>
+            <version>2.7</version>
+            <configuration>
+                <encoding>${project.build.sourceEncoding}</encoding>
+            </configuration>
+        </plugin>
+        <!--
+        <plugin>
+            <groupId>org.mybatis.generator</groupId>
+            <artifactId>mybatis-generator-maven-plugin</artifactId>
+            <version>1.3.2</version>
+            <executions>
+                <execution>
+                    <id>Generate MyBatis Artifacts</id>
+                    <goals>
+                        <goal>generate</goal>
+                    </goals>
+                </execution>
+            </executions>
+            <configuration>
+                <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
+                <jdbcDriver>com.mysql.jdbc.Driver</jdbcDriver>
+                <jdbcPassword>root</jdbcPassword>
+                <jdbcURL>jdbc:mysql://localhost:3306/mybatis_example</jdbcURL>
+                <jdbcUserId>root</jdbcUserId>
+                <outputDirectory>${mybatis.generator.outputdirectory}</outputDirectory>
+                <overwrite>true</overwrite>
+                <verbose>true</verbose>
+            </configuration>
+        </plugin>
+        -->
+        <!-- Required to work with m2e plugin for Eclipse (there is an available connector for this plugin but no for mybatis-generator-maven-plugin) -->
+        <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>build-helper-maven-plugin</artifactId>
+            <version>1.10</version>
+            <executions>
+                <execution>
+                    <id>add-source</id>
+                    <phase>generate-sources</phase>
+                    <goals>
+                        <goal>add-source</goal>
+                    </goals>
+                    <configuration>
+                        <sources>
+                            <source>${mybatis.generator.outputdirectory}</source>
+                        </sources>
+                    </configuration>
+                </execution>
+            </executions>
+        </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/executor/ReuseBatchExecutor.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/executor/ReuseBatchExecutor.java
new file mode 100644 (file)
index 0000000..2d6702a
--- /dev/null
@@ -0,0 +1,181 @@
+package de.example.mybatis.executor;
+
+import java.sql.BatchUpdateException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.executor.BaseExecutor;
+import org.apache.ibatis.executor.BatchExecutorException;
+import org.apache.ibatis.executor.BatchResult;
+import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
+import org.apache.ibatis.executor.keygen.KeyGenerator;
+import org.apache.ibatis.executor.keygen.NoKeyGenerator;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.transaction.Transaction;
+
+public class ReuseBatchExecutor extends BaseExecutor {
+       public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
+
+       private final Map<String, Statement> statementMap = new HashMap<>();
+       private final Map<String, BatchResult> batchResultMap = new HashMap<>();
+
+       public ReuseBatchExecutor(Configuration configuration, Transaction transaction) {
+               super(configuration, transaction);
+       }
+
+       public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
+               final Configuration configuration = ms.getConfiguration();
+               final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT,
+                               null, null);
+               final Statement stmt = reuseUpdateStatement(handler, ms, parameterObject);
+               handler.batch(stmt);
+               return BATCH_UPDATE_RETURN_VALUE;
+       }
+
+       public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
+                       ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+               Statement stmt = null;
+               try {
+                       flushStatements();
+                       final Configuration configuration = ms.getConfiguration();
+                       final StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds,
+                                       resultHandler, boundSql);
+                       stmt = reuseQueryStatement(handler, ms.getStatementLog());
+                       return handler.<E> query(stmt, resultHandler);
+               } finally {
+                       closeStatement(stmt);
+               }
+       }
+
+       public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
+
+               try {
+                       final List<BatchResult> results = new ArrayList<>();
+                       if (isRollback) {
+                               return Collections.emptyList();
+                       } else {
+
+                               long count = 0;
+                               for (Map.Entry<String, Statement> entry : statementMap.entrySet()) {
+                                       final Statement stmt = entry.getValue();
+                                       final String sql = entry.getKey();
+                                       final BatchResult batchResult = batchResultMap.get(sql);
+                                       if (batchResult != null) {
+
+                                               try {
+                                                       batchResult.setUpdateCounts(stmt.executeBatch());
+                                                       MappedStatement ms = batchResult.getMappedStatement();
+                                                       List<Object> parameterObjects = batchResult.getParameterObjects();
+                                                       KeyGenerator keyGenerator = ms.getKeyGenerator();
+                                                       if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
+                                                               Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
+                                                               jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
+                                                       } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { // issue #141
+                                                               for (Object parameter : parameterObjects) {
+                                                                       keyGenerator.processAfter(this, ms, stmt, parameter);
+                                                               }
+                                                       }
+                                       } catch (BatchUpdateException e) {
+                                           StringBuilder message = new StringBuilder();
+                                           message.append(batchResult.getMappedStatement().getId())
+                                               .append(" (batch index #")
+                                               .append(count + 1)
+                                               .append(")")
+                                               .append(" failed.");
+                                           if (count > 0) {
+                                               message.append(" ")
+                                                       .append(count)
+                                                       .append(" prior sub executor(s) completed successfully, but will be rolled back.");
+                                           }
+                                           
+                                           throw new BatchExecutorException(message.toString(), e, results, batchResult); 
+                                       }
+                                               
+                                               results.add(batchResult);
+                                       }
+
+                                       count = count + 1;
+                               }
+
+                               return results;
+                       }
+               } finally {
+                       for (Statement stmt : statementMap.values()) {
+                               closeStatement(stmt);
+                       }
+                       statementMap.clear();
+                       batchResultMap.clear();
+               }
+       }
+
+       private Statement reuseQueryStatement(StatementHandler handler, Log statementLog) throws SQLException {
+               final BoundSql boundSql = handler.getBoundSql();
+               final String sql = boundSql.getSql();
+               final Statement stmt;
+               
+               if (hasStatementFor(sql)) {
+                       stmt = getStatement(sql);
+               } else {
+                       final Connection connection = getConnection(statementLog);
+                       stmt = handler.prepare(connection);
+                       putStatement(sql, stmt);
+               }
+               
+               handler.parameterize(stmt);
+               
+               return stmt;
+       }
+       
+       private Statement reuseUpdateStatement(StatementHandler handler, MappedStatement ms, Object parameterObject) throws SQLException {
+               final BoundSql boundSql = handler.getBoundSql();
+               final String sql = boundSql.getSql();
+               final Statement stmt;
+
+               if (hasStatementFor(sql)) {
+                       stmt = getStatement(sql);
+
+                       final BatchResult batchResult = batchResultMap.get(sql);
+                       batchResult.addParameterObject(parameterObject);
+
+               } else {
+                       final Connection connection = getConnection(ms.getStatementLog());
+                       stmt = handler.prepare(connection);
+
+                       batchResultMap.put(sql, new BatchResult(ms, sql, parameterObject));
+                       putStatement(sql, stmt);
+               }
+
+               handler.parameterize(stmt);
+               
+               return stmt;
+       }
+
+       private boolean hasStatementFor(String sql) {
+               try {
+                       return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();
+               } catch (SQLException e) {
+                       return false;
+               }
+       }
+
+       private Statement getStatement(String s) {
+               return statementMap.get(s);
+       }
+
+       private void putStatement(String sql, Statement stmt) {
+               statementMap.put(sql, stmt);
+       }
+
+}
\ No newline at end of file
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ReuseBatchExecutorInterceptor.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ReuseBatchExecutorInterceptor.java
new file mode 100644 (file)
index 0000000..19124f8
--- /dev/null
@@ -0,0 +1,91 @@
+package de.example.mybatis.interceptor;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.ibatis.executor.CachingExecutor;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.transaction.Transaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import de.example.mybatis.executor.ReuseBatchExecutor;
+
+/**
+ * Too much hacking for doing this stuff. No other way of using my own Executor when using Spring Mybatis.
+ *
+ */
+public class ReuseBatchExecutorInterceptor implements Interceptor {
+       private static final Logger LOGGER = LoggerFactory.getLogger(ReuseBatchExecutorInterceptor.class);
+
+       @Override
+       public Object intercept(Invocation invocation) throws Throwable {
+               Method method = invocation.getMethod();
+               Object[] args = invocation.getArgs();
+               Object target = invocation.getTarget();
+               
+               return invocation.proceed();
+       }
+
+       @Override
+       public Object plugin(Object target) {
+               Object result = target;
+               
+               if (target instanceof CachingExecutor) {
+                       CachingExecutor cachingExecutor = (CachingExecutor) target;
+                       try {
+                               Field delegateField = getField(cachingExecutor.getClass(), "delegate");
+                               delegateField.setAccessible(true);
+                               Object delegatedExecutor = delegateField.get(cachingExecutor);
+                               Executor executor = doReuseBatchExecutor((Executor) delegatedExecutor);
+                               result = new CachingExecutor(executor);
+                       } catch (IllegalAccessException e) {
+                               LOGGER.error("Error: ", e);
+                       } catch (NoSuchFieldException e) {
+                               LOGGER.error("Error: ", e);
+                       }
+               } else if (target instanceof Executor){
+                       result = doReuseBatchExecutor((Executor) target);
+               }
+
+               return result;
+       }
+
+       @Override
+       public void setProperties(Properties properties) {
+               // Nothing to do.
+       }
+
+       private static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
+               try {
+                       return clazz.getDeclaredField(fieldName);
+               } catch (NoSuchFieldException e) {
+                       Class superClass = clazz.getSuperclass();
+                       if (superClass == null) {
+                               throw e;
+                       } else {
+                               return getField(superClass, fieldName);
+                       }
+               }
+       }
+       
+       private ReuseBatchExecutor doReuseBatchExecutor(Executor executor) {
+               Configuration configuration = null;
+               try {
+                       final Field configurationField = getField(executor.getClass(), "configuration");
+                       configurationField.setAccessible(true);
+                       configuration = (Configuration) configurationField.get(executor);
+               } catch (IllegalAccessException e) {
+                       LOGGER.error("Error: ", e);
+               } catch (NoSuchFieldException e) {
+                       LOGGER.error("Error: ", e);
+               }
+
+               final Transaction trx = executor.getTransaction();
+               return new ReuseBatchExecutor(configuration, trx);
+       }
+} 
\ No newline at end of file
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/mapper/filter/MyBatisScanFilter.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/mapper/filter/MyBatisScanFilter.java
new file mode 100644 (file)
index 0000000..104a322
--- /dev/null
@@ -0,0 +1,11 @@
+package de.example.mybatis.mapper.filter;
+
+
+/**
+ * 
+ * MyBatis will search for this interface.
+ * 
+ */
+public interface MyBatisScanFilter {
+
+}
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/model/Ad.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/model/Ad.java
new file mode 100644 (file)
index 0000000..74a945a
--- /dev/null
@@ -0,0 +1,229 @@
+package de.example.mybatis.model;
+
+import java.util.Date;
+
+public class Ad {
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private Long id;
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.company_id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private Long companyId;
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.company_categ_id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private Long companyCategId;
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.ad_mobile_image
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private String adMobileImage;
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.created_at
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private Date createdAt;
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.updated_at
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private Date updatedAt;
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column ad.ad_gps
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    private byte[] adGps;
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.id
+     *
+     * @return the value of ad.id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public Long getId() {
+        return id;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.id
+     *
+     * @param id the value for ad.id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.company_id
+     *
+     * @return the value of ad.company_id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.company_id
+     *
+     * @param companyId the value for ad.company_id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.company_categ_id
+     *
+     * @return the value of ad.company_categ_id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public Long getCompanyCategId() {
+        return companyCategId;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.company_categ_id
+     *
+     * @param companyCategId the value for ad.company_categ_id
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setCompanyCategId(Long companyCategId) {
+        this.companyCategId = companyCategId;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.ad_mobile_image
+     *
+     * @return the value of ad.ad_mobile_image
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public String getAdMobileImage() {
+        return adMobileImage;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.ad_mobile_image
+     *
+     * @param adMobileImage the value for ad.ad_mobile_image
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setAdMobileImage(String adMobileImage) {
+        this.adMobileImage = adMobileImage;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.created_at
+     *
+     * @return the value of ad.created_at
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public Date getCreatedAt() {
+        return createdAt;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.created_at
+     *
+     * @param createdAt the value for ad.created_at
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setCreatedAt(Date createdAt) {
+        this.createdAt = createdAt;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.updated_at
+     *
+     * @return the value of ad.updated_at
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public Date getUpdatedAt() {
+        return updatedAt;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.updated_at
+     *
+     * @param updatedAt the value for ad.updated_at
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setUpdatedAt(Date updatedAt) {
+        this.updatedAt = updatedAt;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method returns the value of the database column ad.ad_gps
+     *
+     * @return the value of ad.ad_gps
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public byte[] getAdGps() {
+        return adGps;
+    }
+
+    /**
+     * This method was generated by MyBatis Generator.
+     * This method sets the value of the database column ad.ad_gps
+     *
+     * @param adGps the value for ad.ad_gps
+     *
+     * @mbggenerated Thu Mar 19 18:05:44 CET 2015
+     */
+    public void setAdGps(byte[] adGps) {
+        this.adGps = adGps;
+    }
+}
\ No newline at end of file
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/repository/mapper/AdMapper.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/repository/mapper/AdMapper.java
new file mode 100644 (file)
index 0000000..ed17f46
--- /dev/null
@@ -0,0 +1,18 @@
+package de.example.mybatis.repository.mapper;
+
+import java.util.List;
+import java.util.Set;
+
+import de.example.mybatis.mapper.filter.MyBatisScanFilter;
+import de.example.mybatis.model.Ad;
+
+public interface AdMapper extends MyBatisScanFilter {
+
+       Set<Ad> selectAsSet();
+       
+       List<Ad> selectAsList();
+       
+       long insert(Ad record);
+       
+       long updateByPrimaryKey(Ad record);
+}
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/SpringContextLocator.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/SpringContextLocator.java
new file mode 100644 (file)
index 0000000..b390f27
--- /dev/null
@@ -0,0 +1,63 @@
+package de.example.mybatis.spring;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+
+/**
+ * Spring context locator.
+ * 
+ */
+public final class SpringContextLocator {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SpringContextLocator.class);
+
+    /** Spring ApplicationContext **/
+    private final ApplicationContext context;
+
+    /** Spring Context **/
+    private static final String SPRING_CONFIG_CONTEXT="spring-config.xml";
+
+
+    /**
+     * Private constructor. Singleton pattern.
+     */
+    private SpringContextLocator() {
+        final String[] factoryFiles = new String[] { SPRING_CONFIG_CONTEXT };
+
+        LOGGER.info("Loading context files " + SpringContextLocator.SPRING_CONFIG_CONTEXT);
+
+        this.context = new ClassPathXmlApplicationContext(factoryFiles);
+
+        LOGGER.info("The context has been loaded successfully!! ");
+    }
+
+    /**
+     * SingletonHolder Thread-safety. To use an Enum class (see Effective Java
+     * Second Edition) if we need serialization and thread-safety.
+     */
+    private static class SingletonHolder {
+        public static final SpringContextLocator INSTANCE = new SpringContextLocator();
+    }
+
+    /**
+     * Return singleton instance. Thread-safety.
+     * 
+     * @return Singleton instance.
+     */
+    public static SpringContextLocator getInstance() {
+        return SingletonHolder.INSTANCE;
+    }
+
+    /**
+     * Return bean from application context.
+     * 
+     * @param beanId
+     *            Bean's id.
+     * @return The bean instance.
+     */
+    public Object getBean(final String beanId) {
+        return this.context.getBean(beanId);
+    }
+}
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/TestMain.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/TestMain.java
new file mode 100644 (file)
index 0000000..0652171
--- /dev/null
@@ -0,0 +1,16 @@
+package de.example.mybatis.spring;
+
+import de.example.mybatis.spring.service.ExampleService;
+
+public class TestMain {
+    public static void main(final String[] args) {
+        
+        final ExampleService example = (ExampleService) SpringContextLocator
+                .getInstance().getBean("exampleService");
+        
+        
+        example.insertAndUpdateAds();
+        
+    }
+
+}
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/ExampleService.java b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/ExampleService.java
new file mode 100644 (file)
index 0000000..e656113
--- /dev/null
@@ -0,0 +1,8 @@
+package de.example.mybatis.spring.service;
+
+public interface ExampleService {
+
+       public void listAds();
+       
+       public void insertAndUpdateAds();
+}
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
new file mode 100644 (file)
index 0000000..aea867b
--- /dev/null
@@ -0,0 +1,108 @@
+package de.example.mybatis.spring.service.impl;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import de.example.mybatis.model.Ad;
+import de.example.mybatis.repository.mapper.AdMapper;
+import de.example.mybatis.spring.service.ExampleService;
+
+@Service("exampleService")
+public class ExampleServiceImpl implements ExampleService {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExampleServiceImpl.class);
+
+    private final AdMapper adMapper;
+
+    @Autowired
+    public ExampleServiceImpl(AdMapper adMapper) {
+       this.adMapper = adMapper;
+    }
+
+    @Override
+    @Transactional
+       public void listAds() {
+               LOGGER.info("listAds");
+
+               final Set<Ad> ads = adMapper.selectAsSet();
+               for (final Ad ad : ads) {
+                       LOGGER.info("Ad id: " + ad.getId());
+                       if (ad.getAdGps() != null) {
+                               try {
+                                       LOGGER.info("Ad GPS: " + new String(ad.getAdGps(), "UTF-8"));
+                               } catch (final UnsupportedEncodingException e) {
+                                       LOGGER.error("Encoding error", e);
+                               }
+                       }
+                       LOGGER.info("Ad mobileImage: " + ad.getAdMobileImage());
+                       LOGGER.info("Ad companyCategId: " + ad.getCompanyCategId());
+                       LOGGER.info("Ad companyId: " + ad.getCompanyId());
+                       LOGGER.info("Ad createdAt: " + ad.getCreatedAt());
+                       LOGGER.info("Ad updatedAt: " + ad.getUpdatedAt());
+                       LOGGER.info("\n");
+               }
+       }
+
+    @Override
+       @Transactional
+       public void insertAndUpdateAds() {
+               LOGGER.info("Insert two new Ads");
+
+               final Ad adTestOne = new Ad();
+               adTestOne.setAdMobileImage("bildOne.jpg");
+               adTestOne.setCompanyCategId(200L);
+               adTestOne.setCreatedAt(new Date());
+               adTestOne.setCompanyId(2L);
+               adTestOne.setUpdatedAt(new Date());
+               adMapper.insert(adTestOne);
+
+               final Ad adTestTwo = new Ad();
+               adTestTwo.setAdMobileImage("bildTwo.jpg");
+               adTestTwo.setCompanyCategId(200L);
+               adTestTwo.setCreatedAt(new Date());
+               adTestTwo.setCompanyId(3L);
+               adTestTwo.setUpdatedAt(new Date());
+               adMapper.insert(adTestTwo);
+
+               
+               
+               LOGGER.info("Update two Ads");
+
+               adTestOne.setAdMobileImage("updatedBildOne.jpg");
+               adMapper.updateByPrimaryKey(adTestOne);
+               
+               adTestTwo.setAdMobileImage("updatedBildTwo.jpg");
+               adMapper.updateByPrimaryKey(adTestTwo);
+               
+               
+               
+               
+               LOGGER.info("Insert two new Ads");
+               
+               final Ad adTestThree = new Ad();
+               adTestThree.setAdMobileImage("bildThree.jpg");
+               adTestThree.setCompanyCategId(200L);
+               adTestThree.setCreatedAt(new Date());
+               adTestThree.setCompanyId(2L);
+               adTestThree.setUpdatedAt(new Date());
+               adMapper.insert(adTestThree);
+               
+               
+               final Ad adTestFour = new Ad();
+               adTestFour.setAdMobileImage("bildFour.jpg");
+               adTestFour.setCompanyCategId(200L);
+               adTestFour.setCreatedAt(new Date());
+               adTestFour.setCompanyId(2L);
+               adTestFour.setUpdatedAt(new Date());
+               adMapper.insert(adTestFour);
+               
+               
+               listAds();
+       }
+}
\ No newline at end of file
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
new file mode 100644 (file)
index 0000000..e34b106
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration
+  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
+  "http://mybatis.org/dtd/mybatis-3-config.dtd">
+
+<configuration>
+  <settings>
+    <!--
+    MyBatis uses two caches: a local cache and a second level cache.
+
+    Each time a new session is created MyBatis creates a local cache and attaches
+    it to the session. Any query executed within the session will be stored in
+    the local cache so further executions of the same query with the same input
+    parameters will not hit the database. The local cache is cleared upon update,
+    commit, rollback and close.
+
+    By default local cache data is used for the whole session duration. This cache
+    is needed to resolve circular references and to speed up repeated nested queries,
+    so it can never be completely disabled but you can configure the local cache to
+    be used just for the duration of an statement execution by setting localCacheScope=STATEMENT.
+
+    Note that when the localCacheScope is set to SESSION, MyBatis returns references
+    to the same objects which are stored in the local cache. Any modification of
+    returned object (lists etc.) influences the local cache contents and subsequently
+    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.
+       
+       VER CachingExecutor.
+       -->
+    <setting name="cacheEnabled" value="false"/>
+    <setting name="localCacheScope" value="STATEMENT"/>
+    <setting name="lazyLoadingEnabled" value="false"/>
+    <setting name="aggressiveLazyLoading" value="false"/>
+    <setting name="multipleResultSetsEnabled" value="true"/>
+    <setting name="useColumnLabel" value="false"/>
+    <setting name="useGeneratedKeys" value="false"/>
+    <setting name="autoMappingBehavior" value="PARTIAL"/>
+    <setting name="defaultExecutorType" value="SIMPLE"/>
+    <setting name="defaultStatementTimeout" value="5"/>
+    <setting name="safeRowBoundsEnabled" value="false"/>
+    <setting name="mapUnderscoreToCamelCase" value="false"/>
+    <setting name="jdbcTypeForNull" value="OTHER"/>
+    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
+    <setting name="logPrefix" value="mybatislogger"/>
+    <setting name="logImpl" value="SLF4J"/>
+    <setting name="proxyFactory" value="CGLIB"/>
+  </settings>
+  
+  
+  <plugins>
+    <plugin interceptor="de.example.mybatis.interceptor.ReuseBatchExecutorInterceptor">
+    </plugin>
+  </plugins>
+  
+</configuration>
\ No newline at end of file
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/de/example/mybatis/repository/mapper/AdMapper.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/de/example/mybatis/repository/mapper/AdMapper.xml
new file mode 100644 (file)
index 0000000..14ded5d
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="de.example.mybatis.repository.mapper.AdMapper" >
+
+       <insert id="insert" parameterType="de.example.mybatis.model.Ad">
+               <selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER">
+                       SELECT LAST_INSERT_ID()
+               </selectKey>
+                       INSERT into ad (
+                               company_id,
+                               company_categ_id,
+                               ad_mobile_image,
+                               created_at,
+                               updated_at,
+                               ad_gps
+                       )
+                       VALUES (
+                               #{companyId,jdbcType=BIGINT},
+                               #{companyCategId,jdbcType=BIGINT},
+                               #{adMobileImage,jdbcType=VARCHAR},
+                               #{createdAt,jdbcType=TIMESTAMP},
+                               #{updatedAt,jdbcType=TIMESTAMP},
+                               #{adGps,jdbcType=LONGVARBINARY}
+                       )
+       </insert>
+
+
+       <update id="updateByPrimaryKey" parameterType="de.example.mybatis.model.Ad">
+           UPDATE
+               ad
+           SET
+               company_id = #{companyId,jdbcType=BIGINT},
+               company_categ_id = #{companyCategId,jdbcType=BIGINT},
+               ad_mobile_image = #{adMobileImage,jdbcType=VARCHAR},
+               created_at = #{createdAt,jdbcType=TIMESTAMP},
+               updated_at = #{updatedAt,jdbcType=TIMESTAMP}
+           WHERE
+               id = #{id,jdbcType=BIGINT}
+       </update>
+
+
+       <select id="selectAsList" resultType="de.example.mybatis.model.Ad"
+               flushCache="false" useCache="true" timeout="10000" statementType="PREPARED">
+               select * FROM ad
+       </select>
+  
+
+       <select id="selectAsSet" resultType="de.example.mybatis.model.Ad"
+        flushCache="false" useCache="true" timeout="10000" statementType="PREPARED">
+               select * FROM ad
+       </select>
+</mapper>
\ No newline at end of file
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/generator/generatorConfig.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/generator/generatorConfig.xml
new file mode 100644 (file)
index 0000000..70ab2bc
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE generatorConfiguration
+  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
+  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
+
+<generatorConfiguration>
+    <!--
+    user.home property is not working with maven 2.2.1
+    <classPathEntry location="${user.home}/.m2/repository/mysql/mysql-connector-java/5.1.9/mysql-connector-java-5.1.9.jar" />
+    -->
+    <classPathEntry location="/home/gustavo/.m2/repository/mysql/mysql-connector-java/5.1.9/mysql-connector-java-5.1.9.jar" />
+
+    <context id="MySQLTables" targetRuntime="MyBatis3">
+
+        <plugin type="org.mybatis.generator.plugins.RenameExampleClassPlugin">
+            <property name="searchString" value="Example$"/>
+            <property name="replaceString" value="Criteria"/>
+        </plugin>
+
+        <!-- This can be useful in paging applications -->
+        <plugin type="org.mybatis.generator.plugins.RowBoundsPlugin">
+        </plugin>
+
+        <!-- Not very useful because you can not rely on its results (equals/hashcode depend on bussines rules)
+        <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin">
+        </plugin>
+
+        <plugin type="org.mybatis.generator.plugins.SerializablePlugin">
+            <property name="suppressJavaInterface" value="true"/>
+        </plugin>
+        -->
+
+
+        <commentGenerator>
+            <property name="suppressAllComments" value="false" />
+            <property name="suppressDate" value="false" />
+        </commentGenerator>
+        
+        <!--
+        If you are dropping like me (by means of some firewall) IPV6 connections and you feel
+        during the first MySLQ connection as if there is a huge lag and you are using
+        *NIX, you could use this system property -Djava.net.preferIPv4Stack=true
+        in order to stop using IPV6 from JVM.
+         -->
+        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
+            connectionURL="jdbc:mysql://localhost:3306/mybatis_example?characterEncoding=UTF-8" userId="root" password="root">
+        </jdbcConnection>
+
+        <javaTypeResolver>
+            <property name="forceBigDecimals" value="true" />
+        </javaTypeResolver>
+
+        <javaModelGenerator targetPackage="de.example.mybatis.model"  targetProject="MAVEN">
+            <!--property name="constructorBased" value="true" />
+            <property name="immutable" value="true" /-->
+            <property name="enableSubPackages" value="true" />
+            <property name="trimStrings" value="false" />
+        </javaModelGenerator>
+
+        <sqlMapGenerator targetPackage="de.example.mybatis.repository.mapper" targetProject="MAVEN">
+            <property name="enableSubPackages" value="true" />
+        </sqlMapGenerator>
+        
+        <javaClientGenerator type="XMLMAPPER" targetPackage="de.example.mybatis.repository.mapper" 
+            targetProject="MAVEN">
+            <property name="enableSubPackages" value="true" />
+        </javaClientGenerator>
+
+        <!--
+            There is no need of declaring every table in data base.
+
+        <table schema="mybatis_example" tableName="ad" domainObjectName="Ad">
+            <property name="useActualColumnNames" value="false" />
+            <property name="ignoreQualifiersAtRuntime" value="true" />
+            <mybatis:scan/> supports filtering the mappers created by either specifying a marker interface or an annotation
+            <property name="rootInterface" value="de.example.mybatis.mapper.filter.MyBatisScanFilter" />
+            <generatedKey column="id" sqlStatement="MySql" identity="true" type="post" />
+        </table>
+        <table schema="mybatis_example" tableName="ad_description" domainObjectName="AdDescription">
+            <property name="useActualColumnNames" value="false" />
+            <property name="ignoreQualifiersAtRuntime" value="true" />
+            <mybatis:scan/> supports filtering the mappers created by either specifying a marker interface or an annotation
+            <property name="rootInterface" value="de.example.mybatis.mapper.filter.MyBatisScanFilter" />
+            <generatedKey column="id" sqlStatement="MySql" identity="true" type="post" />
+        </table>
+        -->
+
+        <table tableName="%"
+            enableSelectByExample="true"
+            enableDeleteByExample="true"
+            enableCountByExample="true"
+            enableUpdateByExample="true"
+            selectByExampleQueryId="true">
+           <property name="useActualColumnNames" value="false" />
+           <property name="ignoreQualifiersAtRuntime" value="true" />
+           <property name="rootInterface" value="de.example.mybatis.mapper.filter.MyBatisScanFilter" />
+           <!--
+            <mybatis:scan/> supports filtering the mappers created by either specifying a marker interface or an annotation
+           -->
+           <property name="rootInterface" value="de.example.mybatis.mapper.filter.MyBatisScanFilter" />
+            <generatedKey column="id" sqlStatement="MySql" identity="true" type="post" />
+        </table>
+    </context>
+</generatorConfiguration>
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/ddlChangelog.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/ddlChangelog.xml
new file mode 100644 (file)
index 0000000..8aef71d
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd">
+    <changeSet author="gustavo (generated)" id="1424631556445-1">
+        <createTable tableName="ad">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints primaryKey="true"/>
+            </column>
+            <column name="company_id" type="BIGINT"/>
+            <column name="company_categ_id" type="BIGINT"/>
+            <column name="ad_gps" type="BLOB"/>
+            <column name="ad_mobile_image" type="VARCHAR(255)"/>
+            <column defaultValueComputed="CURRENT_TIMESTAMP" name="created_at" type="TIMESTAMP">
+                <constraints nullable="false"/>
+            </column>
+            <column defaultValue="0000-00-00 00:00:00" name="updated_at" type="TIMESTAMP">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+        <!-- 
+                You do not need this if you created your schema with the right charset and collation (because
+             it is inherited from schema to tables and rows) anyhow this is just an example of what you can do.
+               -->
+        <modifySql dbms="mysql">
+            <append value="ENGINE=InnoDB, DEFAULT CHARSET=utf8, COLLATE=utf8_unicode_ci"/>
+        </modifySql>
+    </changeSet>
+    <changeSet author="gustavo (generated)" id="1424631556445-2">
+        <createTable tableName="ad_description">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints primaryKey="true"/>
+            </column>
+            <column name="laguage_id" type="BIGINT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ad_id" type="BIGINT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ad_name" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ad_description" type="LONGTEXT"/>
+            <column name="ad_mobile_text" type="VARCHAR(500)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ad_link" type="VARCHAR(3000)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+        <!-- 
+                You do not need this if you created your schema with the right charset and collation (because
+             it is inherited from schema to tables and rows) anyhow this is just an example of what you can do.
+               -->
+        <modifySql dbms="mysql">
+            <append value="ENGINE=InnoDB, DEFAULT CHARSET=utf8, COLLATE=utf8_unicode_ci"/>
+        </modifySql>
+    </changeSet>
+    <changeSet author="gustavo (generated)" id="1424631556445-3">
+        <addUniqueConstraint columnNames="id" constraintName="id" deferrable="false" disabled="false" initiallyDeferred="false" tableName="ad"/>
+    </changeSet>
+    <changeSet author="gustavo (generated)" id="1424631556445-4">
+        <addForeignKeyConstraint baseColumnNames="ad_id" baseTableName="ad_description" constraintName="ad_description_ibfk_1" deferrable="false" initiallyDeferred="false" onDelete="CASCADE" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="ad"/>
+    </changeSet>
+</databaseChangeLog>
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/dmlChangelog.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/dmlChangelog.xml
new file mode 100644 (file)
index 0000000..13a4e12
--- /dev/null
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
+    <changeSet author="gustavo (generated)" id="1424628789069-1">
+        <insert tableName="ad">
+            <column name="id" valueNumeric="1"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="bild.jpg"/>
+            <column name="created_at" valueDate="2014-12-17 23:27:36.0"/>
+            <column name="updated_at" valueDate="2014-12-17 23:27:36.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="2"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="bild.jpg"/>
+            <column name="created_at" valueDate="2014-12-17 23:29:10.0"/>
+            <column name="updated_at" valueDate="2014-12-17 23:29:10.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="3"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 17:13:46.0"/>
+            <column name="updated_at" valueDate="2014-12-27 17:13:47.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="4"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 17:14:39.0"/>
+            <column name="updated_at" valueDate="2014-12-27 17:15:27.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="5"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:38:47.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:38:47.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="6"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:39:53.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:39:53.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="7"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:39:54.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:39:54.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="8"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:40:21.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:40:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="9"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:40:21.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:40:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="10"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:42:34.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:42:34.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="11"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-27 23:42:34.0"/>
+            <column name="updated_at" valueDate="2014-12-27 23:42:34.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="12"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:07:34.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:07:34.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="13"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:07:35.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:07:35.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="14"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:20.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:20.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="15"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:21.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="16"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:21.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="17"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:21.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="18"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:21.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="19"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:21.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="20"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:10:21.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:10:21.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="21"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:19:06.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:19:06.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="23"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:20:08.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:20:08.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="25"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:31:11.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:31:11.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="26"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:31:12.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:31:12.0"/>
+        </insert>
+        <insert tableName="ad">
+            <column name="id" valueNumeric="27"/>
+            <column name="company_id" valueNumeric="2"/>
+            <column name="company_categ_id" valueNumeric="200"/>
+            <column name="ad_gps"/>
+            <column name="ad_mobile_image" value="mobileImage.jpg"/>
+            <column name="created_at" valueDate="2014-12-28 00:31:12.0"/>
+            <column name="updated_at" valueDate="2014-12-28 00:31:12.0"/>
+        </insert>
+    </changeSet>
+</databaseChangeLog>
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/liquibaseChangeLogs.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/liquibaseChangeLogs.xml
new file mode 100644 (file)
index 0000000..740f261
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog
+        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+
+    <!-- DDL -->
+    <include file="liquibase/ddlChangelog.xml" />
+
+    <!-- DML -->
+    <include file="liquibase/dmlChangelog.xml" />
+    <!--
+    <changeSet author="gustavo" id="1">
+        <sqlFile path="liquibase/dmlChangelog.xml" stripComments="true"/>
+    </changeSet>
+    -->
+
+</databaseChangeLog>
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/log4j2.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/log4j2.xml
new file mode 100644 (file)
index 0000000..8b3fc3f
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- 
+       status: The level of internal Log4j events that should be logged to the console.
+       Valid values for this attribute are "trace", "debug", "info", "warn", "error" and "fatal".
+       
+       monitorInterval: The minimum amount of time, in seconds, that must elapse before the file configuration is checked for changes.
+       
+       
+       see https://logging.apache.org/log4j/2.x/manual/configuration.html
+ -->
+<Configuration status="error" strict="true" monitorInterval="30"
+                name="XMLConfigTest" packages="org.apache.logging.log4j.test">
+                
+       <!--
+               ALL > TRACE > DEBUG > INFO > WARN > ERROR > OFF
+               
+               ERROR by default.
+       -->
+                
+    <Appenders>
+        <Appender type="Console" name="STDOUT">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
+        </Appender>
+    </Appenders>
+    <Loggers>
+    
+               <!-- 
+               General logging Spring.
+        -->
+        <Logger name="org.springframework" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
+    
+
+               <!-- 
+                       Anything else will be using TRACE logging level.
+                -->        
+        <Root level="DEBUG">
+            <AppenderRef ref="STDOUT"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/spring-config.xml b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/spring-config.xml
new file mode 100644 (file)
index 0000000..db47ee8
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:tx="http://www.springframework.org/schema/tx"
+       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/context 
+                                                  http://www.springframework.org/schema/context/spring-context-3.2.xsd
+                                                  http://www.springframework.org/schema/tx 
+                           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
+                           http://www.springframework.org/schema/aop 
+                           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
+                           http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
+
+
+    <!--
+    There is no need to register all your mappers one by one. Instead, you can let MyBatis-Spring scan your classpath for them.
+    <mybatis:scan/> supports filtering the mappers created by either specifying a marker interface or an annotation.
+    The annotation property specifies an annotation to search for. The marker-interface attribute specifies a parent interface
+    to search for. If both properties are specified, mappers are added for interfaces that match either criteria. By default,
+    these two properties are null, so all interfaces in the given base package(s) will be loaded as mappers.
+    See http://mybatis.org/schema/mybatis-spring.xsd for further information.
+    -->
+    <mybatis:scan base-package="de.example.mybatis.repository.mapper"
+                  marker-interface="de.example.mybatis.mapper.filter.MyBatisScanFilter"
+                  template-ref="sqlSimpleSession" /> <!-- Required because I am using SIMPLE and BATCH MyBatis Executors -->
+
+    <!-- enable the configuration of transactional behavior based on annotations -->
+    <tx:annotation-driven transaction-manager="transactionManager"/>
+
+       <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
+        <property name="user" value="root"/>
+        <property name="password" value="root"/>
+        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
+        <!--
+        If you are dropping like me (by means of some firewall) IPV6 connections and you feel
+        during the first MySLQ connection as if there is a huge lag and you are using
+        *NIX, you could use this system property -Djava.net.preferIPv4Stack=true
+        in order to stop using IPV6 from JVM.
+        The JVM tries to find out if IPV6 is available by means of opening a random
+        AF_INET6 POSIX socket.
+         -->
+        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis_example?allowMultiQueries=true&amp;autoReconnect=true&amp;characterEncoding=UTF-8"/>
+        <property name="initialPoolSize" value="5"/>
+        <property name="maxPoolSize" value="20"/>
+        <property name="minPoolSize" value="10"/>
+        <property name="acquireIncrement" value="1"/>
+        <property name="acquireRetryAttempts" value="5"/>
+        <property name="acquireRetryDelay" value="1000"/>
+        <property name="automaticTestTable" value="con_test"/>
+        <property name="checkoutTimeout" value="5000"/>
+    </bean>
+    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+        <property name="dataSource" ref="dataSource"/>
+    </bean>
+       <!-- It will be shared by SIMPLE and BATCH operations. -->
+    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
+        <property name="dataSource" ref="dataSource" />
+        <property name="configLocation" value="classpath:config/mybatis-config.xml" />
+    </bean>
+    
+    <!-- We need to declare in this way the SqlSessionTemplate bean because otherwise 
+         mybatis:scan will retrieve the first instantiated Spring bean of this type.
+         Because we want to create a BATCH SqlSessionTemplate we also have to create
+         a SIMPLE SqlSessionTemplate (it is SIMPLE because if we do not declare the Executor type
+         SqlSessionFactoryBean will retrieve its value from mybatis-config.xml and in that file
+         I am using defaultExecutorType=SIMPLE)-->
+    <bean id="sqlSimpleSession" class="org.mybatis.spring.SqlSessionTemplate">
+       <constructor-arg index="0" ref="sqlSessionFactory" />
+       </bean>
+    
+    <!-- 
+    The <mybatis:scan/> XML element will search for mappers in a very similar way than the
+    Spring built-in element <context:component-scan/>  searches for beans.
+    
+    The base-package attribute lets you set the base package for your mapper interface files.
+    You can set more than one package by using a semicolon or comma as a separator. Mappers
+    will be searched for recursively starting in the specified package(s).
+
+    Notice that there is no need to specify a SqlSessionFactory or SqlSessionTemplate as an
+    attribute in the <mybatis:scan/> element because it will create MapperFactoryBeans that can
+    be autowired. But if you are using more than one DataSource autowire may not work for you
+    (in my case I am using SIMPLE and BATCH operations, and autowire did not work for me because
+    once you declare SqlSessionTemplate bean for BATCH operations you have also to declare
+    the SqlSessionTemplate for SIMPLE operations)
+    In this case you can use the factory-ref or template-ref attributes to set the right bean
+    name to use.
+
+    <mybatis:scan/> supports filtering the mappers created by either specifying a marker
+    interface or an annotation. The annotation property specifies an annotation to
+    search for. The marker-interface attribute specifies a parent interface to search for.
+    If both properties are specified, mappers are added for interfaces that match either
+    criteria. By default, these two properties are null, so all interfaces in the given
+    base package(s) will be loaded as mappers.
+
+    Discovered mappers will be named using Spring default naming strategy for autodetected
+    components (see section 3.14.4 of the Spring manual). That is, if no annotation is
+    found, it will use the uncapitalized non-qualified class name of the mapper. But if
+    either a @Component or a JSR-330 @Named annotation is found it will get the name from
+    the annotation. Notice that you can set the annotation attribute
+    to org.springframework.stereotype.Component, javax.inject.Named (if you have JSE 6)
+    or to your own annotation (that must be itself annotated) so the annotation will work
+    both as a marker and as a name provider.
+
+    NOTE <context:component-scan/> won't be able to scan and register mappers. Mappers
+    are interfaces and, in order to register them to Spring, the scanner must know how
+    to create a MapperFactoryBean for each interface it finds. 
+    
+    <bean id="adMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
+        <property name="mapperInterface" value="de.example.mybatis.repository.mapper.AdMapper" />
+        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
+    </bean>
+    
+      -->
+    
+    <!--
+       Using Spring @Service annotation instead of XML
+    <bean id="exampleService" class="de.example.mybatis.spring.service.ExampleService">
+        <property name="adMapper" ref="adMapper" />
+    </bean>
+    -->
+
+
+    <bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
+        <property name="dataSource" ref="dataSource" />
+        <property name="changeLog" value="classpath:/liquibase/liquibaseChangeLogs.xml" />
+    </bean>
+    
+        
+</beans>