--- /dev/null
+
+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
--- /dev/null
+<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>
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+package de.example.mybatis.mapper.filter;
+
+
+/**
+ *
+ * MyBatis will search for this interface.
+ *
+ */
+public interface MyBatisScanFilter {
+
+}
--- /dev/null
+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
--- /dev/null
+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);
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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();
+
+ }
+
+}
--- /dev/null
+package de.example.mybatis.spring.service;
+
+public interface ExampleService {
+
+ public void listAds();
+
+ public void insertAndUpdateAds();
+}
--- /dev/null
+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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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&autoReconnect=true&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>