DefaultSqlSession.java

  1. /*
  2.  *    Copyright 2009-2021 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.defaults;

  17. import java.io.IOException;
  18. import java.sql.Connection;
  19. import java.sql.SQLException;
  20. import java.util.ArrayList;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.apache.ibatis.binding.BindingException;
  25. import org.apache.ibatis.cursor.Cursor;
  26. import org.apache.ibatis.exceptions.ExceptionFactory;
  27. import org.apache.ibatis.exceptions.TooManyResultsException;
  28. import org.apache.ibatis.executor.BatchResult;
  29. import org.apache.ibatis.executor.ErrorContext;
  30. import org.apache.ibatis.executor.Executor;
  31. import org.apache.ibatis.executor.result.DefaultMapResultHandler;
  32. import org.apache.ibatis.executor.result.DefaultResultContext;
  33. import org.apache.ibatis.mapping.MappedStatement;
  34. import org.apache.ibatis.reflection.ParamNameResolver;
  35. import org.apache.ibatis.session.Configuration;
  36. import org.apache.ibatis.session.ResultHandler;
  37. import org.apache.ibatis.session.RowBounds;
  38. import org.apache.ibatis.session.SqlSession;

  39. /**
  40.  * The default implementation for {@link SqlSession}.
  41.  * Note that this class is not Thread-Safe.
  42.  *
  43.  * @author Clinton Begin
  44.  */
  45. public class DefaultSqlSession implements SqlSession {

  46.   private final Configuration configuration;
  47.   private final Executor executor;

  48.   private final boolean autoCommit;
  49.   private boolean dirty;
  50.   private List<Cursor<?>> cursorList;

  51.   public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
  52.     this.configuration = configuration;
  53.     this.executor = executor;
  54.     this.dirty = false;
  55.     this.autoCommit = autoCommit;
  56.   }

  57.   public DefaultSqlSession(Configuration configuration, Executor executor) {
  58.     this(configuration, executor, false);
  59.   }

  60.   @Override
  61.   public <T> T selectOne(String statement) {
  62.     return this.selectOne(statement, null);
  63.   }

  64.   @Override
  65.   public <T> T selectOne(String statement, Object parameter) {
  66.     // Popular vote was to return null on 0 results and throw exception on too many.
  67.     List<T> list = this.selectList(statement, parameter);
  68.     if (list.size() == 1) {
  69.       return list.get(0);
  70.     } else if (list.size() > 1) {
  71.       throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
  72.     } else {
  73.       return null;
  74.     }
  75.   }

  76.   @Override
  77.   public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
  78.     return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
  79.   }

  80.   @Override
  81.   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
  82.     return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
  83.   }

  84.   @Override
  85.   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
  86.     final List<? extends V> list = selectList(statement, parameter, rowBounds);
  87.     final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
  88.             configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
  89.     final DefaultResultContext<V> context = new DefaultResultContext<>();
  90.     for (V o : list) {
  91.       context.nextResultObject(o);
  92.       mapResultHandler.handleResult(context);
  93.     }
  94.     return mapResultHandler.getMappedResults();
  95.   }

  96.   @Override
  97.   public <T> Cursor<T> selectCursor(String statement) {
  98.     return selectCursor(statement, null);
  99.   }

  100.   @Override
  101.   public <T> Cursor<T> selectCursor(String statement, Object parameter) {
  102.     return selectCursor(statement, parameter, RowBounds.DEFAULT);
  103.   }

  104.   @Override
  105.   public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
  106.     try {
  107.       MappedStatement ms = configuration.getMappedStatement(statement);
  108.       Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
  109.       registerCursor(cursor);
  110.       return cursor;
  111.     } catch (Exception e) {
  112.       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  113.     } finally {
  114.       ErrorContext.instance().reset();
  115.     }
  116.   }

  117.   @Override
  118.   public <E> List<E> selectList(String statement) {
  119.     return this.selectList(statement, null);
  120.   }

  121.   @Override
  122.   public <E> List<E> selectList(String statement, Object parameter) {
  123.     return this.selectList(statement, parameter, RowBounds.DEFAULT);
  124.   }

  125.   @Override
  126.   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  127.     return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
  128.   }

  129.   private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  130.     try {
  131.       MappedStatement ms = configuration.getMappedStatement(statement);
  132.       return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
  133.     } catch (Exception e) {
  134.       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  135.     } finally {
  136.       ErrorContext.instance().reset();
  137.     }
  138.   }

  139.   @Override
  140.   public void select(String statement, Object parameter, ResultHandler handler) {
  141.     select(statement, parameter, RowBounds.DEFAULT, handler);
  142.   }

  143.   @Override
  144.   public void select(String statement, ResultHandler handler) {
  145.     select(statement, null, RowBounds.DEFAULT, handler);
  146.   }

  147.   @Override
  148.   public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  149.     selectList(statement, parameter, rowBounds, handler);
  150.   }

  151.   @Override
  152.   public int insert(String statement) {
  153.     return insert(statement, null);
  154.   }

  155.   @Override
  156.   public int insert(String statement, Object parameter) {
  157.     return update(statement, parameter);
  158.   }

  159.   @Override
  160.   public int update(String statement) {
  161.     return update(statement, null);
  162.   }

  163.   @Override
  164.   public int update(String statement, Object parameter) {
  165.     try {
  166.       dirty = true;
  167.       MappedStatement ms = configuration.getMappedStatement(statement);
  168.       return executor.update(ms, wrapCollection(parameter));
  169.     } catch (Exception e) {
  170.       throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
  171.     } finally {
  172.       ErrorContext.instance().reset();
  173.     }
  174.   }

  175.   @Override
  176.   public int delete(String statement) {
  177.     return update(statement, null);
  178.   }

  179.   @Override
  180.   public int delete(String statement, Object parameter) {
  181.     return update(statement, parameter);
  182.   }

  183.   @Override
  184.   public void commit() {
  185.     commit(false);
  186.   }

  187.   @Override
  188.   public void commit(boolean force) {
  189.     try {
  190.       executor.commit(isCommitOrRollbackRequired(force));
  191.       dirty = false;
  192.     } catch (Exception e) {
  193.       throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
  194.     } finally {
  195.       ErrorContext.instance().reset();
  196.     }
  197.   }

  198.   @Override
  199.   public void rollback() {
  200.     rollback(false);
  201.   }

  202.   @Override
  203.   public void rollback(boolean force) {
  204.     try {
  205.       executor.rollback(isCommitOrRollbackRequired(force));
  206.       dirty = false;
  207.     } catch (Exception e) {
  208.       throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);
  209.     } finally {
  210.       ErrorContext.instance().reset();
  211.     }
  212.   }

  213.   @Override
  214.   public List<BatchResult> flushStatements() {
  215.     try {
  216.       return executor.flushStatements();
  217.     } catch (Exception e) {
  218.       throw ExceptionFactory.wrapException("Error flushing statements.  Cause: " + e, e);
  219.     } finally {
  220.       ErrorContext.instance().reset();
  221.     }
  222.   }

  223.   @Override
  224.   public void close() {
  225.     try {
  226.       executor.close(isCommitOrRollbackRequired(false));
  227.       closeCursors();
  228.       dirty = false;
  229.     } finally {
  230.       ErrorContext.instance().reset();
  231.     }
  232.   }

  233.   private void closeCursors() {
  234.     if (cursorList != null && !cursorList.isEmpty()) {
  235.       for (Cursor<?> cursor : cursorList) {
  236.         try {
  237.           cursor.close();
  238.         } catch (IOException e) {
  239.           throw ExceptionFactory.wrapException("Error closing cursor.  Cause: " + e, e);
  240.         }
  241.       }
  242.       cursorList.clear();
  243.     }
  244.   }

  245.   @Override
  246.   public Configuration getConfiguration() {
  247.     return configuration;
  248.   }

  249.   @Override
  250.   public <T> T getMapper(Class<T> type) {
  251.     return configuration.getMapper(type, this);
  252.   }

  253.   @Override
  254.   public Connection getConnection() {
  255.     try {
  256.       return executor.getTransaction().getConnection();
  257.     } catch (SQLException e) {
  258.       throw ExceptionFactory.wrapException("Error getting a new connection.  Cause: " + e, e);
  259.     }
  260.   }

  261.   @Override
  262.   public void clearCache() {
  263.     executor.clearLocalCache();
  264.   }

  265.   private <T> void registerCursor(Cursor<T> cursor) {
  266.     if (cursorList == null) {
  267.       cursorList = new ArrayList<>();
  268.     }
  269.     cursorList.add(cursor);
  270.   }

  271.   private boolean isCommitOrRollbackRequired(boolean force) {
  272.     return (!autoCommit && dirty) || force;
  273.   }

  274.   private Object wrapCollection(final Object object) {
  275.     return ParamNameResolver.wrapToMapIfCollection(object, null);
  276.   }

  277.   /**
  278.    * @deprecated Since 3.5.5
  279.    */
  280.   @Deprecated
  281.   public static class StrictMap<V> extends HashMap<String, V> {

  282.     private static final long serialVersionUID = -5741767162221585340L;

  283.     @Override
  284.     public V get(Object key) {
  285.       if (!super.containsKey(key)) {
  286.         throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
  287.       }
  288.       return super.get(key);
  289.     }

  290.   }

  291. }