SqlSessionManager.java

  1. /*
  2.  *    Copyright 2009-2023 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.  *       https://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(SqlSessionFactory.class.getClassLoader(),
  39.         new Class[] { SqlSession.class }, new SqlSessionInterceptor());
  40.   }

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

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

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

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

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

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

  59.   public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
  60.     return new SqlSessionManager(sqlSessionFactory);
  61.   }

  62.   public void startManagedSession() {
  63.     this.localSqlSession.set(openSession());
  64.   }

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

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

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

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

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

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

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

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

  89.   @Override
  90.   public SqlSession openSession() {
  91.     return sqlSessionFactory.openSession();
  92.   }

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

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

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

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

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

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

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

  121.   @Override
  122.   public Configuration getConfiguration() {
  123.     return sqlSessionFactory.getConfiguration();
  124.   }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  303. }