DefaultSqlSession.java

  1. /*
  2.  *    Copyright 2009-2024 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.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}. Note that this class is not Thread-Safe.
  41.  *
  42.  * @author Clinton Begin
  43.  */
  44. public class DefaultSqlSession implements SqlSession {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  146.   @Override
  147.   public void select(String statement, ResultHandler handler) {
  148.     select(statement, null, RowBounds.DEFAULT, handler);
  149.   }

  150.   @Override
  151.   public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  152.     selectList(statement, parameter, rowBounds, handler);
  153.   }

  154.   @Override
  155.   public int insert(String statement) {
  156.     return insert(statement, null);
  157.   }

  158.   @Override
  159.   public int insert(String statement, Object parameter) {
  160.     return update(statement, parameter);
  161.   }

  162.   @Override
  163.   public int update(String statement) {
  164.     return update(statement, null);
  165.   }

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

  178.   @Override
  179.   public int delete(String statement) {
  180.     return update(statement, null);
  181.   }

  182.   @Override
  183.   public int delete(String statement, Object parameter) {
  184.     return update(statement, parameter);
  185.   }

  186.   @Override
  187.   public void commit() {
  188.     commit(false);
  189.   }

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

  201.   @Override
  202.   public void rollback() {
  203.     rollback(false);
  204.   }

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

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

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

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

  248.   @Override
  249.   public Configuration getConfiguration() {
  250.     return configuration;
  251.   }

  252.   @Override
  253.   public <T> T getMapper(Class<T> type) {
  254.     return configuration.getMapper(type, this);
  255.   }

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

  264.   @Override
  265.   public void clearCache() {
  266.     executor.clearLocalCache();
  267.   }

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

  274.   private boolean isCommitOrRollbackRequired(boolean force) {
  275.     return !autoCommit && dirty || force;
  276.   }

  277.   private Object wrapCollection(final Object object) {
  278.     return ParamNameResolver.wrapToMapIfCollection(object, null);
  279.   }

  280.   /**
  281.    * @deprecated Since 3.5.5
  282.    */
  283.   @Deprecated
  284.   public static class StrictMap<V> extends HashMap<String, V> {

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

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

  293.   }

  294. }