--- /dev/null
+package de.example.mybatis.batch.repository.mapper;
+
+import de.example.mybatis.model.Ad;
+
+
+public interface AdSpringBatchMapper /** extends MyBatisScanFilter NO SCAN BY MyBatis!! **/ {
+
+ int insert(Ad record);
+}
package de.example.mybatis.spring;
+import java.sql.SQLException;
+
import org.apache.log4j.Logger;
+import org.springframework.jdbc.CannotGetJdbcConnectionException;
+import de.example.mybatis.spring.service.BatchAndSimpleSameTrx;
+import de.example.mybatis.spring.service.ExampleBatchService;
import de.example.mybatis.spring.service.ExampleCustomService;
import de.example.mybatis.spring.service.ExampleService;
// exampleService.insertNewAd();
//
// exampleService.getAdsByCriteria();
-
-
- final ExampleCustomService exampleCustomService = (ExampleCustomService) SpringContextLocator
- .getInstance().getBean("exampleCustomService");
-
- exampleCustomService.getAds();
+//
+//
+// final ExampleCustomService exampleCustomService = (ExampleCustomService) SpringContextLocator
+// .getInstance().getBean("exampleCustomService");
+//
+// exampleCustomService.getAds();
+//
+// exampleCustomService.updateAds();
+
+
+// final ExampleBatchService exampleBatchService = (ExampleBatchService) SpringContextLocator
+// .getInstance().getBean("exampleBatchService");
+//
+// exampleBatchService.insertNewAd();
+//
+// exampleBatchService.insertBatchNewAd();
+
+
+ final BatchAndSimpleSameTrx batchAndSimpleSameTrx = (BatchAndSimpleSameTrx) SpringContextLocator
+ .getInstance().getBean("batchAndSimpleSameTrx");
- exampleCustomService.updateAds();
+ try {
+ batchAndSimpleSameTrx.insertNewAd();
+ } catch (CannotGetJdbcConnectionException e) {
+ logger.error("Error exception: ", e);
+ } catch (SQLException e) {
+ logger.error("Error exception: ", e);
+ }
+
}
}
--- /dev/null
+package de.example.mybatis.spring.service;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Date;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.jdbc.SQL;
+import org.apache.log4j.Logger;
+import org.springframework.jdbc.CannotGetJdbcConnectionException;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.transaction.annotation.Transactional;
+
+import de.example.mybatis.model.Ad;
+import de.example.mybatis.repository.mapper.AdMapper;
+
+
+public class BatchAndSimpleSameTrx {
+ private static final Logger logger = Logger.getLogger(BatchAndSimpleSameTrx.class);
+
+ private AdMapper adMapper;
+ private DataSource dataSource;
+
+ @Transactional
+ /**
+ * JUST IN THIS VERY MOMENT Spring sends "set autocommit = 0" EVEN IF THERE ARE NO OPERATIONS ON THE DATABASE!!!
+ * So, Spring is picking up some thread from the connections pool and giving it to the current Java thread.
+ */
+ public void insertNewAd() throws CannotGetJdbcConnectionException, SQLException {
+ logger.info("Insert new Ad");
+
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("bild.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+
+ /**
+ * No batched inserts will be sent to data base just in this very moment.
+ */
+ this.adMapper.insert(adTest);
+
+ /**
+ * We want to use SIMPLE and BATCH operations but MyBatis complains with this exception:
+ * "Cannot change the ExecutorType when there is an existing transaction".
+ *
+ * So, we get the connection for the current transaction by means of the Spring DataSourceUtils
+ * and using JDBC we implement the BATCH operation in the current open transaction
+ * (it was open because of the @Transactional annotation)
+ */
+ this.doBatch(DataSourceUtils.getConnection(this.dataSource));
+
+ /**
+ * No batched inserts will be sent to data base just in this very moment.
+ */
+ this.adMapper.insert(adTest);
+
+ /**
+ * WHEN RETURNING FROM THIS METHOD Spring SENDS "set autocommit = 1" AND TRANSACTION ENDS
+ * (OR IF THERE IS ERROR Spring SENDS "rollback" AS EXPECTED)
+ */
+ }
+
+ private void doBatch(final Connection connection) throws SQLException {
+
+ final PreparedStatement preparedStatement = connection.prepareStatement(doStatement());
+ try {
+ for (int i = 0; i < 10; i++) {
+ /**
+ * Batched statements are not yet sent to data base.
+ */
+ preparedStatement.addBatch();
+ }
+
+ /**
+ * RIGHT HERE THE BATCH STATEMENTS WILL BE SENT TO THE DATA BASE.
+ */
+ preparedStatement.executeBatch();
+
+ } finally {
+ preparedStatement.close();
+ }
+ }
+
+ private String doStatement() {
+ return new SQL() {
+ {
+ INSERT_INTO("ad");
+ VALUES("company_categ_id, ad_mobile_image, created_at, updated_at",
+ "'200', 'batch.jpg', '2015-03-20 02:54:50.0', '2015-03-20 02:54:50.0'");
+ }
+ }.toString();
+ }
+
+ public void setAdMapper(final AdMapper adMapper) {
+ this.adMapper = adMapper;
+ }
+
+ public void setDataSource(final DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+}
--- /dev/null
+package de.example.mybatis.spring.service;
+
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+import org.springframework.transaction.annotation.Transactional;
+
+import de.example.mybatis.batch.repository.mapper.AdSpringBatchMapper;
+import de.example.mybatis.model.Ad;
+import de.example.mybatis.repository.mapper.AdMapper;
+
+
+public class ExampleBatchService {
+ private static final Logger logger = Logger.getLogger(ExampleBatchService.class);
+
+ private AdSpringBatchMapper adSpringBatchMapper;
+ private AdMapper adMapper;
+
+ @Transactional
+ /**
+ * JUST IN THIS VERY MOMENT Spring sends "set autocommit = 0" EVEN IF THERE ARE NO OPERATIONS ON THE DATABASE!!!
+ * So, Spring is picking up some thread from the connections pool and giving it to the current Java thread.
+ */
+ public void insertBatchNewAd() {
+ logger.info("Insert new Batch Ad");
+
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("bild.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+
+ /**
+ * BECAUSE THIS IS A BATCH MAPPER, OPERATIONS WILL NOT BE SENT TO THE DATABASE UNTIL COMMAND commit IS SENT TO DATABASE.
+ * BECAUSE THIS METHOD IS ANNOTATED WITH @Transactional, THE COMMAND commit WILL BE SENT WHEN RETURNING FROM THIS METHOD
+ * (WHEN TRANSACTION ENDS UP)
+ *
+ * WORK AROUND: using SqlSession (MyBatis) we have access to the flushStatements method!!!
+ * SO, WE MUST INJECT THE SqlSession BEAN AND USE IT HERE IF WE DON'T WANT TO WAIT UNTIL TRANSACTION IS FINISHED.
+ */
+ this.adSpringBatchMapper.insert(adTest);
+
+ /**
+ * There will not be new "set autocommit = 0" because Spring remembers that this thread already started some transaction
+ * (it must be using ThreadLocals)
+ */
+ this.insertPrivateNewAd();
+ }
+
+ private void insertPrivateNewAd() {
+ logger.info("Insert new private Ad");
+
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("bild.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+
+ // MyBatis complains: "Cannot change the ExecutorType when there is an existing transaction".
+ // Work around in BatchAndSimpleSameTrx.
+ this.adMapper.insert(adTest);
+ }
+
+ @Transactional
+ /**
+ * JUST IN THIS VERY MOMENT Spring sends "set autocommit = 0" EVEN IF THERE ARE NO OPERATIONS ON THE DATABASE!!!
+ * So, Spring is picking up some thread from the connections pool and giving it to the current Java thread.
+ */
+ public void insertNewAd() {
+ logger.info("Insert new Ad");
+
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("bild.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+ this.adMapper.insert(adTest);
+
+ //DataSourceUtils.getConnection();
+
+ this.insertPrivateBatchNewAd();
+ }
+
+ private void insertPrivateBatchNewAd() {
+ logger.info("Insert new private Batch Ad");
+
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("bild.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+
+ /**
+ * BECAUSE THIS IS A BATCH MAPPER, OPERATIONS WILL NOT BE SENT TO THE DATABASE UNTIL COMMAND commit IS SENT TO DATABASE.
+ * BECAUSE THIS METHOD IS ANNOTATED WITH @Transactional, THE COMMAND commit WILL BE SENT WHEN RETURNING FROM THIS METHOD
+ * (WHEN TRANSACTION ENDS UP)
+ *
+ * WORK AROUND: using SqlSession (MyBatis) we have access to the flushStatements method!!!
+ * SO, WE MUST INJECT THE SqlSession BEAN AND USE IT HERE IF WE DON'T WANT TO WAIT UNTIL TRANSACTION IS FINISHED.
+ */
+ // MyBatis complains: "Cannot change the ExecutorType when there is an existing transaction".
+ // Workaround in BatchAndSimpleSameTrx.
+ this.adSpringBatchMapper.insert(adTest);
+ }
+
+ public void setAdSpringBatchMapper(final AdSpringBatchMapper adSpringBatchMapper) {
+ this.adSpringBatchMapper = adSpringBatchMapper;
+ }
+
+ public void setAdMapper(final AdMapper adMapper) {
+ this.adMapper = adMapper;
+ }
+}
adTest.setCompanyId(2L);
adTest.setUpdatedAt(new Date());
this.adMapper.insert(adTest);
+
+ this.adMapper.insert(adTest);
}
}
\ 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.batch.repository.mapper.AdSpringBatchMapper" >
+
+ <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>
+
+</mapper>
\ No newline at end of file
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" />
+ 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"/>
<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.
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.
+ 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.
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:/liquibase/liquibaseChangeLogs.xml" />
</bean>
+
+
+ <!--
+ MyBatis batch implementation
+ IT DOESN'T ALLOW YOU TO USE DIFFERENT TYPE OF EXECUTORS IN THE SAME TRANSACTION!!! Work around to this
+ limitation in BatchAndSimpleSameTrx.java class (using JDBC)
+
+ MyBatis batch mappers will not be scanned because they have different base package and different interface.
+ Session will be shared by batched and simple MyBatis mappers (so they can share the same transaction)
+ -->
+
+ <bean id="sqlBatchSession" class="org.mybatis.spring.SqlSessionTemplate">
+ <constructor-arg index="0" ref="sqlSessionFactory" />
+ <constructor-arg index="1" value="BATCH" />
+ </bean>
+
+ <bean id="adSpringBatchMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
+ <property name="mapperInterface" value="de.example.mybatis.batch.repository.mapper.AdSpringBatchMapper" />
+ <property name="sqlSessionTemplate" ref="sqlBatchSession" />
+ </bean>
+
+ <bean id="exampleBatchService" class="de.example.mybatis.spring.service.ExampleBatchService">
+ <property name="adSpringBatchMapper" ref="adSpringBatchMapper" />
+ <property name="adMapper" ref="adMapper" />
+ </bean>
+
+ <bean id="batchAndSimpleSameTrx" class="de.example.mybatis.spring.service.BatchAndSimpleSameTrx">
+ <property name="adMapper" ref="adMapper" />
+ <property name="dataSource" ref="dataSource" />
+ </bean>
+
</beans>
--- /dev/null
+package de.example.mybatis;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.apache.log4j.Logger;
+
+import de.example.mybatis.model.Ad;
+import de.example.mybatis.model.AdCriteria;
+import de.example.mybatis.repository.mapper.AdMapper;
+
+
+public class TestMainBatch {
+ private static final Logger logger = Logger.getLogger(TestMainBatch.class);
+
+ public static void main(final String[] args) throws IOException {
+
+ // From org.xml.sax.InputSource Javadoc:
+ // The SAX parser will use the InputSource object to determine how to
+ // read XML input. If there is a character stream available, the parser
+ // will read that stream directly, disregarding any text encoding
+ // declaration found in that stream. If there is no character stream,
+ // but there is a byte stream, the parser will use that byte stream,
+ // using the encoding specified in the InputSource or else (if no
+ // encoding is specified) autodetecting the character encoding using an
+ // algorithm such as the one in the XML specification. If neither a
+ // character stream nor a byte stream is available, the parser will
+ // attempt to open a URI connection to the resource identified by the
+ // system identifier.
+
+ // Then if we use an InputStream (it is not a character stream) and
+ // we do not specify the encoding, the encoding should be autodetected
+ // reading the XML header. :) That is what I want. :)
+
+
+
+ // Scope and Lifecycle
+ //
+ // 1. SqlSessionFactoryBuilder:
+ // This class can be instantiated, used and thrown away. There is no
+ // need to keep it around once you've created your SqlSessionFactory.
+ //
+ // 2. SqlSessionFactory:
+ // Once created, the SqlSessionFactory should exist for the duration of
+ // your application execution.
+ //
+ // 3. SqlSession:
+ // Each thread should have its own instance of SqlSession. Instances of
+ // SqlSession are not to be shared and are not thread safe. Therefore
+ // the best scope is request or method scope. You should always ensure
+ // that it's closed within a finally block.
+ //
+ // 4. Mapper Instances:
+ // Mappers are interfaces that you create to bind to your mapped
+ // statements. Instances of the mapper interfaces are acquired from the
+ // SqlSession. They do not need to be closed explicitly.
+
+ final SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
+ .build(/**TestMain.class.getResourceAsStream("sql-maps-config.xml")**/
+ Resources.getResourceAsStream("mybatis-sql-maps-config.xml"), "mybatisexample");
+
+ // The default openSession() method that takes no parameters will create
+ // a SqlSession with the following characteristics:
+ //
+ // * A transaction scope will be started (i.e. NOT auto-commit).
+ // * A Connection object will be acquired from the DataSource instance
+ // configured by the active environment.
+ // * The transaction isolation level will be the default used by the
+ // driver or data source.
+ // * No PreparedStatements will be reused, and no updates will be
+ // batched.
+
+ // 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.
+ /**
+ * OVERRIDE THE DECLARED EXECUTOR IN mybatis-sql-maps-config.xml
+ * BY DEFAULT autocommit = false (what means autocommit=0 until session.close is called)
+ */
+ SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
+
+ try {
+ final AdMapper adMapper = session.getMapper(AdMapper.class);
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("mobileImage.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+
+ // This first insert took ages because I was dropping IPV6 connections.
+ // That is because during the first socket connection, the JVM
+ // tries to find out if IPV6 is available by means of opening a random
+ // AF_INET6 POSIX socket.
+ /**
+ * WITH BATCH OPERATIONS, INSERT WILL NOT BE PEFORMED UNTIL CALLING COMMIT OR FLUSHSTATEMENTS
+ * BUT set autocommit=0 WILL BE PEFORMED JUST IN THIS VERY MOMENT EVEN IF WE ARE NOT
+ * YET SENDING DATA!!!!! So, it is as always but without sending data.
+ */
+ adMapper.insert(adTest);
+ adMapper.insert(adTest);
+ /**
+ * BY MEANS OF THIS METHOD WE CAN SEND THE BATCHED DATA TO DATA BASE AND
+ * RETRIEVE THE RESULTS OF THE BATCH OPERATIONS. OTHERWISE WE HAVE TO WAIT
+ * UNTIL session.commit AND WE LOOSE THE RESULTS.
+ */
+ session.flushStatements();
+
+ /**
+ * IF WE DIDN'T USE THE flushStatements METHOD, IN THIS VERY MOMENT BATCH DATA WOULD BE SENT TO SERVER
+ * (BUT BECAUSE WE USED THE flushStatements METHOD NO DATA WILL BE SENT)
+ * JUST THE commit COMMAND IS SENT RIGHT NOW!!!
+ */
+ session.commit();
+
+ final List<Ad> adLists = adMapper.selectByExample(null);
+ for (final Ad ad : adLists) {
+ logger.info("Ad id: " + ad.getId());
+ if (ad.getAdGps() != null) {
+ logger.info("Ad GPS: " + new String(ad.getAdGps(), "UTF-8"));
+ }
+ 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");
+ }
+ } finally {
+ // Besides this will restore the auto-commit value.
+ /**
+ * JUST IN THIS VERY MOMENT set autocommit=1 IS SENT!!!!!
+ *
+ * This is what @Transactional (Spring annotation) do when
+ * returning from an annotated transactional method.
+ */
+ session.close();
+ }
+
+ /**
+ * OVERRIDE THE DECLARED EXECUTOR IN mybatis-sql-maps-config.xml
+ * BY DEFAULT autocommit = false (what means autocommit=0 until session.close is called)
+ */
+ session = sqlSessionFactory.openSession(ExecutorType.BATCH);
+
+ try {
+ logger.info("Last insert");
+ final AdMapper adMapper = session.getMapper(AdMapper.class);
+ final Ad adTest = new Ad();
+ adTest.setAdMobileImage("mobileImage.jpg");
+ adTest.setCompanyCategId(200L);
+ adTest.setCreatedAt(new Date());
+ adTest.setCompanyId(2L);
+ adTest.setUpdatedAt(new Date());
+
+ /**
+ * WITH BATCH OPERATIONS, INSERT WILL NOT BE PEFORMED UNTIL CALLING COMMIT
+ * (IF WE DON'T USE THE flushStatements METHOD)
+ * BUT set autocommit=0 WILL BE PEFORMED JUST IN THIS VERY MOMENT EVEN IF WE ARE NOT
+ * YET SENDING DATA!!!!! So, it is as always but without sending data.
+ */
+ adMapper.insert(adTest);
+
+ /**
+ * JUST IN THIS VERY MOMENT DATA ARE SENT TO SERVER, BUT NOT BEFORE!!!!
+ * (BECAUSE WE DID NOT USE THE flushStatements METHOD)
+ * THE commit COMMAND IS SENT RIGHT NOW!!!!!
+ */
+ session.commit();
+
+ } finally {
+ // Besides this will restore the auto-commit value.
+ /**
+ * JUST IN THIS VERY MOMENT set autocommit=1 IS SENT!!!!!
+ *
+ * This is what @Transactional (Spring annotation) do when
+ * returning from an annotated transactional method.
+ */
+ session.close();
+ }
+
+ session = sqlSessionFactory.openSession();
+
+ try {
+ logger.info("Using criteria");
+
+ final AdCriteria adCriteria = new AdCriteria();
+
+ adCriteria.or().andAdMobileImageEqualTo("mobileImage.jpg")
+ .andCreatedAtNotEqualTo(new Date());
+
+ adCriteria.or().andAdMobileImageNotEqualTo("noMobileImage.jpg")
+ .andAdMobileImageIsNotNull();
+
+ // where (ad_mobile_image = "mobileImage.jpg" and created_at <> Now())
+ // or (ad_mobile_image <> "noMobileImage.jpg" and ad_mobile_image is not null)
+
+ final AdMapper adMapper = session.getMapper(AdMapper.class);
+ final List<Ad> adLists = adMapper.selectByExampleWithBLOBs(adCriteria);
+ for (final Ad ad : adLists) {
+ logger.info("Ad id: " + ad.getId());
+ if (ad.getAdGps() != null) {
+ logger.info("Ad GPS: " + new String(ad.getAdGps(), "UTF-8"));
+ }
+ 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");
+ }
+ } finally {
+ // Besides this will restore the auto-commit value.
+ /**
+ * JUST IN THIS VERY MOMENT set autocommit=1 IS SENT!!!!!
+ *
+ * This is what @Transactional (Spring annotation) do when
+ * returning from an annotated transactional method.
+ */
+ session.close();
+ }
+ }
+
+}