MyBatis: trying to make sure how session works.
authorGustavo Martin Morcuende <gustavo@supergusarapo.(none)>
Thu, 29 Aug 2013 20:18:02 +0000 (22:18 +0200)
committerGustavo Martin Morcuende <gustavo@supergusarapo.(none)>
Thu, 29 Aug 2013 20:18:02 +0000 (22:18 +0200)
Some nice comments about:
1. Default values for opened sessions.
2. Caches.
3. Scope and lifecycle of SqlSessionFactoryBuilder, SqlSessionFactory and SqlSession.

MyBatis/MyBatis-Spring/src/main/resources/config/mybatis-config.xml
MyBatis/MyBatis-Spring/src/main/resources/spring-config.xml
MyBatis/MyBatis/src/main/java/de/example/mybatis/TestMain.java
MyBatis/MyBatis/src/main/resources/mybatis-sql-maps-config.xml

index 43999df..5ee3309 100644 (file)
@@ -5,7 +5,27 @@
 
 <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. -->
     <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"/>
@@ -16,7 +36,6 @@
     <setting name="defaultStatementTimeout" value="5"/>
     <setting name="safeRowBoundsEnabled" value="false"/>
     <setting name="mapUnderscoreToCamelCase" value="false"/>
-    <setting name="localCacheScope" value="SESSION"/>
     <setting name="jdbcTypeForNull" value="OTHER"/>
     <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
     <setting name="logPrefix" value="mybatislogger"/>
index 91a76d5..9729c88 100644 (file)
@@ -31,6 +31,8 @@
         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?autoReconnect=true&amp;characterEncoding=UTF-8"/>
         <property name="initialPoolSize" value="5"/>
index 60e9bb2..d3a5194 100644 (file)
@@ -36,10 +36,65 @@ public class TestMain {
         // 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.
         SqlSession session = sqlSessionFactory.openSession();
 
         try {
@@ -50,6 +105,11 @@ public class TestMain {
             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.
             adMapper.insert(adTest);
             session.commit();
 
@@ -67,6 +127,7 @@ public class TestMain {
                 logger.info("\n");
             }
         } finally {
+            // Besides this will restore the auto-commit value.
             session.close();
         }
 
@@ -85,6 +146,7 @@ public class TestMain {
             session.commit();
 
         } finally {
+            // Besides this will restore the auto-commit value.
             session.close();
         }
 
@@ -119,6 +181,7 @@ public class TestMain {
                 logger.info("\n");
             }
         } finally {
+            // Besides this will restore the auto-commit value.
             session.close();
         }
     }
index ff80a44..4798228 100644 (file)
@@ -5,7 +5,27 @@
 
 <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. -->
     <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"/>
@@ -16,7 +36,6 @@
     <setting name="defaultStatementTimeout" value="5"/>
     <setting name="safeRowBoundsEnabled" value="false"/>
     <setting name="mapUnderscoreToCamelCase" value="false"/>
-    <setting name="localCacheScope" value="SESSION"/>
     <setting name="jdbcTypeForNull" value="OTHER"/>
     <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
     <setting name="logPrefix" value="mybatislogger"/>
@@ -33,6 +52,8 @@
         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="url" value="jdbc:mysql://localhost:3306/mybatis_example?characterEncoding=UTF-8"/>
         <property name="username" value="root"/>