SqlSessionManager.java

  1. /*
  2.  *    Copyright 2009-2022 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.session;

  17. import java.io.InputStream;
  18. import java.io.Reader;
  19. import java.lang.reflect.InvocationHandler;
  20. import java.lang.reflect.Method;
  21. import java.lang.reflect.Proxy;
  22. import java.sql.Connection;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Properties;

  26. import org.apache.ibatis.cursor.Cursor;
  27. import org.apache.ibatis.executor.BatchResult;
  28. import org.apache.ibatis.reflection.ExceptionUtil;

  29. /**
  30.  * @author Larry Meadors
  31.  */
  32. public class SqlSessionManager implements SqlSessionFactory, SqlSession {

  33.   private final SqlSessionFactory sqlSessionFactory;
  34.   private final SqlSession sqlSessionProxy;

  35.   private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();

  36.   private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
  37.     this.sqlSessionFactory = sqlSessionFactory;
  38.     this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
  39.         SqlSessionFactory.class.getClassLoader(),
  40.         new Class[]{SqlSession.class},
  41.         new SqlSessionInterceptor());
  42.   }

  43.   public static SqlSessionManager newInstance(Reader reader) {
  44.     return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
  45.   }

  46.   public static SqlSessionManager newInstance(Reader reader, String environment) {
  47.     return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
  48.   }

  49.   public static SqlSessionManager newInstance(Reader reader, Properties properties) {
  50.     return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, properties));
  51.   }

  52.   public static SqlSessionManager newInstance(InputStream inputStream) {
  53.     return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, null));
  54.   }

  55.   public static SqlSessionManager newInstance(InputStream inputStream, String environment) {
  56.     return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, environment, null));
  57.   }

  58.   public static SqlSessionManager newInstance(InputStream inputStream, Properties properties) {
  59.     return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, properties));
  60.   }

  61.   public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
  62.     return new SqlSessionManager(sqlSessionFactory);
  63.   }

  64.   public void startManagedSession() {
  65.     this.localSqlSession.set(openSession());
  66.   }

  67.   public void startManagedSession(boolean autoCommit) {
  68.     this.localSqlSession.set(openSession(autoCommit));
  69.   }

  70.   public void startManagedSession(Connection connection) {
  71.     this.localSqlSession.set(openSession(connection));
  72.   }

  73.   public void startManagedSession(TransactionIsolationLevel level) {
  74.     this.localSqlSession.set(openSession(level));
  75.   }

  76.   public void startManagedSession(ExecutorType execType) {
  77.     this.localSqlSession.set(openSession(execType));
  78.   }

  79.   public void startManagedSession(ExecutorType execType, boolean autoCommit) {
  80.     this.localSqlSession.set(openSession(execType, autoCommit));
  81.   }

  82.   public void startManagedSession(ExecutorType execType, TransactionIsolationLevel level) {
  83.     this.localSqlSession.set(openSession(execType, level));
  84.   }

  85.   public void startManagedSession(ExecutorType execType, Connection connection) {
  86.     this.localSqlSession.set(openSession(execType, connection));
  87.   }

  88.   public boolean isManagedSessionStarted() {
  89.     return this.localSqlSession.get() != null;
  90.   }

  91.   @Override
  92.   public SqlSession openSession() {
  93.     return sqlSessionFactory.openSession();
  94.   }

  95.   @Override
  96.   public SqlSession openSession(boolean autoCommit) {
  97.     return sqlSessionFactory.openSession(autoCommit);
  98.   }

  99.   @Override
  100.   public SqlSession openSession(Connection connection) {
  101.     return sqlSessionFactory.openSession(connection);
  102.   }

  103.   @Override
  104.   public SqlSession openSession(TransactionIsolationLevel level) {
  105.     return sqlSessionFactory.openSession(level);
  106.   }

  107.   @Override
  108.   public SqlSession openSession(ExecutorType execType) {
  109.     return sqlSessionFactory.openSession(execType);
  110.   }

  111.   @Override
  112.   public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
  113.     return sqlSessionFactory.openSession(execType, autoCommit);
  114.   }

  115.   @Override
  116.   public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
  117.     return sqlSessionFactory.openSession(execType, level);
  118.   }

  119.   @Override
  120.   public SqlSession openSession(ExecutorType execType, Connection connection) {
  121.     return sqlSessionFactory.openSession(execType, connection);
  122.   }

  123.   @Override
  124.   public Configuration getConfiguration() {
  125.     return sqlSessionFactory.getConfiguration();
  126.   }

  127.   @Override
  128.   public <T> T selectOne(String statement) {
  129.     return sqlSessionProxy.selectOne(statement);
  130.   }

  131.   @Override
  132.   public <T> T selectOne(String statement, Object parameter) {
  133.     return sqlSessionProxy.selectOne(statement, parameter);
  134.   }

  135.   @Override
  136.   public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
  137.     return sqlSessionProxy.selectMap(statement, mapKey);
  138.   }

  139.   @Override
  140.   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
  141.     return sqlSessionProxy.selectMap(statement, parameter, mapKey);
  142.   }

  143.   @Override
  144.   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
  145.     return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
  146.   }

  147.   @Override
  148.   public <T> Cursor<T> selectCursor(String statement) {
  149.     return sqlSessionProxy.selectCursor(statement);
  150.   }

  151.   @Override
  152.   public <T> Cursor<T> selectCursor(String statement, Object parameter) {
  153.     return sqlSessionProxy.selectCursor(statement, parameter);
  154.   }

  155.   @Override
  156.   public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
  157.     return sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
  158.   }

  159.   @Override
  160.   public <E> List<E> selectList(String statement) {
  161.     return sqlSessionProxy.selectList(statement);
  162.   }

  163.   @Override
  164.   public <E> List<E> selectList(String statement, Object parameter) {
  165.     return sqlSessionProxy.selectList(statement, parameter);
  166.   }

  167.   @Override
  168.   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  169.     return sqlSessionProxy.selectList(statement, parameter, rowBounds);
  170.   }

  171.   @Override
  172.   public void select(String statement, ResultHandler handler) {
  173.     sqlSessionProxy.select(statement, handler);
  174.   }

  175.   @Override
  176.   public void select(String statement, Object parameter, ResultHandler handler) {
  177.     sqlSessionProxy.select(statement, parameter, handler);
  178.   }

  179.   @Override
  180.   public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  181.     sqlSessionProxy.select(statement, parameter, rowBounds, handler);
  182.   }

  183.   @Override
  184.   public int insert(String statement) {
  185.     return sqlSessionProxy.insert(statement);
  186.   }

  187.   @Override
  188.   public int insert(String statement, Object parameter) {
  189.     return sqlSessionProxy.insert(statement, parameter);
  190.   }

  191.   @Override
  192.   public int update(String statement) {
  193.     return sqlSessionProxy.update(statement);
  194.   }

  195.   @Override
  196.   public int update(String statement, Object parameter) {
  197.     return sqlSessionProxy.update(statement, parameter);
  198.   }

  199.   @Override
  200.   public int delete(String statement) {
  201.     return sqlSessionProxy.delete(statement);
  202.   }

  203.   @Override
  204.   public int delete(String statement, Object parameter) {
  205.     return sqlSessionProxy.delete(statement, parameter);
  206.   }

  207.   @Override
  208.   public <T> T getMapper(Class<T> type) {
  209.     return getConfiguration().getMapper(type, this);
  210.   }

  211.   @Override
  212.   public Connection getConnection() {
  213.     final SqlSession sqlSession = localSqlSession.get();
  214.     if (sqlSession == null) {
  215.       throw new SqlSessionException("Error:  Cannot get connection.  No managed session is started.");
  216.     }
  217.     return sqlSession.getConnection();
  218.   }

  219.   @Override
  220.   public void clearCache() {
  221.     final SqlSession sqlSession = localSqlSession.get();
  222.     if (sqlSession == null) {
  223.       throw new SqlSessionException("Error:  Cannot clear the cache.  No managed session is started.");
  224.     }
  225.     sqlSession.clearCache();
  226.   }

  227.   @Override
  228.   public void commit() {
  229.     final SqlSession sqlSession = localSqlSession.get();
  230.     if (sqlSession == null) {
  231.       throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
  232.     }
  233.     sqlSession.commit();
  234.   }

  235.   @Override
  236.   public void commit(boolean force) {
  237.     final SqlSession sqlSession = localSqlSession.get();
  238.     if (sqlSession == null) {
  239.       throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
  240.     }
  241.     sqlSession.commit(force);
  242.   }

  243.   @Override
  244.   public void rollback() {
  245.     final SqlSession sqlSession = localSqlSession.get();
  246.     if (sqlSession == null) {
  247.       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
  248.     }
  249.     sqlSession.rollback();
  250.   }

  251.   @Override
  252.   public void rollback(boolean force) {
  253.     final SqlSession sqlSession = localSqlSession.get();
  254.     if (sqlSession == null) {
  255.       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
  256.     }
  257.     sqlSession.rollback(force);
  258.   }

  259.   @Override
  260.   public List<BatchResult> flushStatements() {
  261.     final SqlSession sqlSession = localSqlSession.get();
  262.     if (sqlSession == null) {
  263.       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
  264.     }
  265.     return sqlSession.flushStatements();
  266.   }

  267.   @Override
  268.   public void close() {
  269.     final SqlSession sqlSession = localSqlSession.get();
  270.     if (sqlSession == null) {
  271.       throw new SqlSessionException("Error:  Cannot close.  No managed session is started.");
  272.     }
  273.     try {
  274.       sqlSession.close();
  275.     } finally {
  276.       localSqlSession.remove();
  277.     }
  278.   }

  279.   private class SqlSessionInterceptor implements InvocationHandler {
  280.     public SqlSessionInterceptor() {
  281.         // Prevent Synthetic Access
  282.     }

  283.     @Override
  284.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  285.       final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
  286.       if (sqlSession != null) {
  287.         try {
  288.           return method.invoke(sqlSession, args);
  289.         } catch (Throwable t) {
  290.           throw ExceptionUtil.unwrapThrowable(t);
  291.         }
  292.       } else {
  293.         try (SqlSession autoSqlSession = openSession()) {
  294.           try {
  295.             final Object result = method.invoke(autoSqlSession, args);
  296.             autoSqlSession.commit();
  297.             return result;
  298.           } catch (Throwable t) {
  299.             autoSqlSession.rollback();
  300.             throw ExceptionUtil.unwrapThrowable(t);
  301.           }
  302.         }
  303.       }
  304.     }
  305.   }

  306. }