From 6b772ea038209c53ca2331d84c7176dd661c59d2 Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Sun, 10 Apr 2016 03:17:45 +0200 Subject: [PATCH] MyBatis: ReuseBatchExecutor --- .../MyBatis-Spring-ReuseBatchExecutor/README.txt | 34 +++ MyBatis/MyBatis-Spring-ReuseBatchExecutor/pom.xml | 179 ++++++++++++++++ .../mybatis/executor/ReuseBatchExecutor.java | 181 ++++++++++++++++ .../interceptor/ReuseBatchExecutorInterceptor.java | 91 ++++++++ .../mybatis/mapper/filter/MyBatisScanFilter.java | 11 + .../src/main/java/de/example/mybatis/model/Ad.java | 229 ++++++++++++++++++++ .../mybatis/repository/mapper/AdMapper.java | 18 ++ .../mybatis/spring/SpringContextLocator.java | 63 ++++++ .../java/de/example/mybatis/spring/TestMain.java | 16 ++ .../mybatis/spring/service/ExampleService.java | 8 + .../spring/service/impl/ExampleServiceImpl.java | 108 ++++++++++ .../src/main/resources/config/mybatis-config.xml | 58 ++++++ .../example/mybatis/repository/mapper/AdMapper.xml | 52 +++++ .../main/resources/generator/generatorConfig.xml | 104 ++++++++++ .../src/main/resources/liquibase/ddlChangelog.xml | 63 ++++++ .../src/main/resources/liquibase/dmlChangelog.xml | 230 +++++++++++++++++++++ .../resources/liquibase/liquibaseChangeLogs.xml | 18 ++ .../src/main/resources/log4j2.xml | 43 ++++ .../src/main/resources/spring-config.xml | 135 ++++++++++++ 19 files changed, 1641 insertions(+) create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/pom.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/executor/ReuseBatchExecutor.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ReuseBatchExecutorInterceptor.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/mapper/filter/MyBatisScanFilter.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/model/Ad.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/repository/mapper/AdMapper.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/SpringContextLocator.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/TestMain.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/ExampleService.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/de/example/mybatis/repository/mapper/AdMapper.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/generator/generatorConfig.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/ddlChangelog.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/dmlChangelog.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/liquibaseChangeLogs.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/log4j2.xml create mode 100644 MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/spring-config.xml diff --git a/MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt new file mode 100644 index 0000000..2272363 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/README.txt @@ -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 index 0000000..f398c19 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/pom.xml @@ -0,0 +1,179 @@ + + 4.0.0 + de.example.mybatis + mybatis-spring-reusebatchexecutor + jar + 1.0-SNAPSHOT + mybatis-spring-reusebatchexecutor + http://gumartinm.name + + ${project.build.directory}/generated-sources/mybatis-generator/ + UTF-8 + 3.4.2 + + + + org.springframework + spring-context + 4.2.5.RELEASE + + + + commons-logging + commons-logging + + + + + org.springframework + spring-jdbc + 4.2.5.RELEASE + + + + commons-logging + commons-logging + + + + + + cglib + cglib + 3.2.1 + + + + + org.mybatis + mybatis-spring + 1.2.5 + + + org.mybatis + mybatis + 3.3.1 + + + + com.mchange + c3p0 + 0.9.5.2 + + + mysql + mysql-connector-java + 5.1.38 + + + + org.liquibase + liquibase-core + ${liquibase.version} + + + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.3 + + + + org.apache.logging.log4j + log4j-core + 2.3 + + + + org.slf4j + jcl-over-slf4j + 1.7.12 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + ${project.build.sourceEncoding} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + add-source + generate-sources + + add-source + + + + ${mybatis.generator.outputdirectory} + + + + + + + + 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 index 0000000..2d6702a --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/executor/ReuseBatchExecutor.java @@ -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 statementMap = new HashMap<>(); + private final Map 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 List 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. query(stmt, resultHandler); + } finally { + closeStatement(stmt); + } + } + + public List doFlushStatements(boolean isRollback) throws SQLException { + + try { + final List results = new ArrayList<>(); + if (isRollback) { + return Collections.emptyList(); + } else { + + long count = 0; + for (Map.Entry 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 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 index 0000000..19124f8 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/interceptor/ReuseBatchExecutorInterceptor.java @@ -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 index 0000000..104a322 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/mapper/filter/MyBatisScanFilter.java @@ -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 index 0000000..74a945a --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/model/Ad.java @@ -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 index 0000000..ed17f46 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/repository/mapper/AdMapper.java @@ -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 selectAsSet(); + + List 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 index 0000000..b390f27 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/SpringContextLocator.java @@ -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 index 0000000..0652171 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/TestMain.java @@ -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 index 0000000..e656113 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/ExampleService.java @@ -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 index 0000000..aea867b --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/java/de/example/mybatis/spring/service/impl/ExampleServiceImpl.java @@ -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 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 index 0000000..e34b106 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/config/mybatis-config.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 index 0000000..14ded5d --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/de/example/mybatis/repository/mapper/AdMapper.xml @@ -0,0 +1,52 @@ + + + + + + + SELECT LAST_INSERT_ID() + + 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} + ) + + + + + 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} + + + + + + + + \ 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 index 0000000..70ab2bc --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/generator/generatorConfig.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
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 index 0000000..8aef71d --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/ddlChangelog.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 0000000..13a4e12 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/dmlChangelog.xml @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 0000000..740f261 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/liquibase/liquibaseChangeLogs.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + 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 index 0000000..8b3fc3f --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/log4j2.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 0000000..db47ee8 --- /dev/null +++ b/MyBatis/MyBatis-Spring-ReuseBatchExecutor/src/main/resources/spring-config.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.1.4