zoukankan      html  css  js  c++  java
  • mybatis源码解析5---SqlSession解析

    由之前解析可知,mybatis启动的时候会加载XML配置文件解析生成全局配置对象Configuration对象,SqlSessionFactoryBuilder类会根据Configuration对象创建一个DefaultSqlSessionFactory对象,而DefaultSqlSessionFactory对象实现了SqlSessionFactory中的创建SqlSession的方法,最终新建了一个SqlSession接口的默认实现类DefaultSqlSession,现在先来了解下SqlSession以及它的实现类

    SqlSession解析

    SqlSession位于mybatis包的org.apache.ibatis.session目录下,字面意思就是sql的会话,用于程序和数据库直接的sql会话,程序执行一次数据库操作就需要创建一个sqlSession,操作结束即关闭sqlSession;

    既然是程序和数据库之间的会话,那么sqlSession接口的方法应该是程序和数据库都容易理解的,sqlSession中定义的方法都是关于数据库操作的方法,源码如下:

     1 package org.apache.ibatis.session;
     2 
     3 import java.io.Closeable;
     4 import java.sql.Connection;
     5 import java.util.List;
     6 import java.util.Map;
     7 
     8 import org.apache.ibatis.cursor.Cursor;
     9 import org.apache.ibatis.executor.BatchResult;
    10 
    11 public interface SqlSession extends Closeable {
    12 
    13     //根据Sql语句查询单条记录
    14   <T> T selectOne(String statement);
    15   <T> T selectOne(String statement, Object parameter);//根据Sql语句和参数查询单条记录
    16 
    17   //根据Sql语句查询多条记录
    18   <E> List<E> selectList(String statement);
    19   <E> List<E> selectList(String statement, Object parameter);//根据Sql语句和参数查询多条记录
    20   <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);//根据Sql语句和参数以及分页参数查询多条记录
    21 
    22    //selectMap和selectList原理一样,只是将结果集映射成Map对象返回
    23   <K, V> Map<K, V> selectMap(String statement, String mapKey);
    24   <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
    25   <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
    26 
    27   //返回游标对象
    28   <T> Cursor<T> selectCursor(String statement);
    29   <T> Cursor<T> selectCursor(String statement, Object parameter);
    30   <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
    31 
    32   //查询的结果对象由指定的ResultHandler处理
    33   void select(String statement, Object parameter, ResultHandler handler);
    34   void select(String statement, ResultHandler handler);
    35   void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
    36 
    37   //执行insert语句
    38   int insert(String statement);
    39   int insert(String statement, Object parameter);
    40 
    41   //执行update语句
    42   int update(String statement);
    43   int update(String statement, Object parameter);
    44 
    45   //执行delete语句
    46   int delete(String statement);
    47   int delete(String statement, Object parameter);
    48 
    49   //提交事务
    50   void commit();
    51   void commit(boolean force);
    52 
    53   //事务回滚
    54   void rollback();
    55   void rollback(boolean force);
    56 
    57   //将请求刷新到数据库
    58   List<BatchResult> flushStatements();
    59 
    60   //关闭sqlSession
    61   @Override
    62   void close();
    63 
    64   //清除缓存  
    65   void clearCache();
    66   
    67   //获取Configuration对象
    68   Configuration getConfiguration();
    69 
    70   //获取Type对象的Mapper对象
    71   <T> T getMapper(Class<T> type);
    72 
    73   //获取sqlSession对象的数据库连接
    74   Connection getConnection();
    75 }

    SqlSession中的方法全是和数据库相关的增删改查以及事务的提交方法。

    SqlSession有三个实现类,除了默认的DefaultSqlSession之外,还有SqlSessionManager和SqlSessionTemplate

    接下来先看下SqlSession默认的实现类DefaultSqlSession是如何实现的。

    DefaultSqlSession类解析

    DefaultSqlSession有5个属性和2个构造方法如下:

     1   private Configuration configuration;//全局配置
     2   private Executor executor;//执行器
     3 
     4   private boolean autoCommit;//自动提交标识
     5   private boolean dirty;
     6   private List<Cursor<?>> cursorList;//游标列表
     7 
     8   public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
     9     this.configuration = configuration;
    10     this.executor = executor;
    11     this.dirty = false;
    12     this.autoCommit = autoCommit;
    13   }
    14 
    15   public DefaultSqlSession(Configuration configuration, Executor executor) {
    16     this(configuration, executor, false);
    17   }

    下面以select方法为例

     1 @Override
     2   public <T> T selectOne(String statement) {
     3     return this.<T>selectOne(statement, null);
     4   }
     5 
     6   @Override
     7   public <T> T selectOne(String statement, Object parameter) {
     8     // Popular vote was to return null on 0 results and throw exception on too many.
     9     List<T> list = this.<T>selectList(statement, parameter);
    10     if (list.size() == 1) {
    11       return list.get(0);
    12     } else if (list.size() > 1) {
    13       throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    14     } else {
    15       return null;
    16     }
    17   }

    很明显selectOne的方法最终都是调用了selectList方法,然后取唯一的一条数据返回。那在看看selectList相关的代码

     1 @Override
     2   public <E> List<E> selectList(String statement) {
     3     return this.selectList(statement, null);
     4   }
     5 
     6   @Override
     7   public <E> List<E> selectList(String statement, Object parameter) {
     8     return this.selectList(statement, parameter, RowBounds.DEFAULT);
     9   }
    10 
    11   @Override
    12   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    13     try {
    14       MappedStatement ms = configuration.getMappedStatement(statement);
    15       return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    16     } catch (Exception e) {
    17       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    18     } finally {
    19       ErrorContext.instance().reset();
    20     }
    21   }

    共有三个selectList方法,最终都是调用了最后一个selectList方法,这里有三个参数:statement是sql语句;parameter是传入的参数;RowBounds是和分页相关的参数

    RowBounds源码如下:

     1 package org.apache.ibatis.session;
     2 
     3 /**
     4  * @author Clinton Begin
     5  */
     6 public class RowBounds {
     7 
     8   public static final int NO_ROW_OFFSET = 0;
     9   public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; //int的最大值
    10   public static final RowBounds DEFAULT = new RowBounds();
    11 
    12   private int offset;
    13   private int limit;
    14 
    15   public RowBounds() {
    16     this.offset = NO_ROW_OFFSET;
    17     this.limit = NO_ROW_LIMIT;
    18   }
    19 
    20   public RowBounds(int offset, int limit) {
    21     this.offset = offset;
    22     this.limit = limit;
    23   }
    24 
    25   public int getOffset() {
    26     return offset;
    27   }
    28 
    29   public int getLimit() {
    30     return limit;
    31   }
    32 
    33 }

    RowBounds的两个属性:offSet是指查询数据时从多少位置开始查询,limit是指返回数据的调试,默认是从0位置开始查询到Integer的最大值,相关于默认是不做分页处理;

    回到正题,selectList最后执行的方法中执行了两行代码

    1 MappedStatement ms = configuration.getMappedStatement(statement);
    2 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

    调用configuration的getMapped的Statement方法获取MappedStatement对象,然后调用执行器executor的query方法获取查询结果。

    这是select方法,再来看看其他的insert、update、delete方法

     1 @Override
     2   public int insert(String statement) {
     3     return insert(statement, null);
     4   }
     5 
     6   @Override
     7   public int insert(String statement, Object parameter) {
     8     return update(statement, parameter);
     9   }
    10 
    11   @Override
    12   public int update(String statement) {
    13     return update(statement, null);
    14   }
    15 
    16   @Override
    17   public int update(String statement, Object parameter) {
    18     try {
    19       dirty = true;
    20       MappedStatement ms = configuration.getMappedStatement(statement);
    21       return executor.update(ms, wrapCollection(parameter));
    22     } catch (Exception e) {
    23       throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    24     } finally {
    25       ErrorContext.instance().reset();
    26     }
    27   }
    28 
    29   @Override
    30   public int delete(String statement) {
    31     return update(statement, null);
    32   }
    33 
    34   @Override
    35   public int delete(String statement, Object parameter) {
    36     return update(statement, parameter);
    37   }

    可以看出SqlSession的insert和delete的方法最终都是调用了update方法,而update方法最终也是调用了Executor的update

    由此可得出结论sqlSession虽然叫程序和数据库之间的SQL会话,但是它并没有具体去执行sql语句,最终的sql语句的执行是由执行器Executor执行的,而SqlSession的作用只是创建了MappedStatement对象以及调用执行器去执行SQL

    其他的commit、rollback方法同样最终都是调用的执行器Executor的对应的方法,那么接下来就去了解下执行器Executor是干嘛的,以及SqlSession创建的MappedStatement又是什么?

    DefaultSqlSession完整源码如下:

      1 /**
      2  *    Copyright 2009-2015 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 
     18 import java.io.IOException;
     19 import java.sql.Connection;
     20 import java.sql.SQLException;
     21 import java.util.ArrayList;
     22 import java.util.Collection;
     23 import java.util.HashMap;
     24 import java.util.List;
     25 import java.util.Map;
     26 
     27 import org.apache.ibatis.binding.BindingException;
     28 import org.apache.ibatis.cursor.Cursor;
     29 import org.apache.ibatis.exceptions.ExceptionFactory;
     30 import org.apache.ibatis.exceptions.TooManyResultsException;
     31 import org.apache.ibatis.executor.BatchResult;
     32 import org.apache.ibatis.executor.ErrorContext;
     33 import org.apache.ibatis.executor.Executor;
     34 import org.apache.ibatis.executor.result.DefaultMapResultHandler;
     35 import org.apache.ibatis.executor.result.DefaultResultContext;
     36 import org.apache.ibatis.mapping.MappedStatement;
     37 import org.apache.ibatis.session.Configuration;
     38 import org.apache.ibatis.session.ResultHandler;
     39 import org.apache.ibatis.session.RowBounds;
     40 import org.apache.ibatis.session.SqlSession;
     41 
     42 /**
     43  *
     44  * The default implementation for {@link SqlSession}.
     45  * Note that this class is not Thread-Safe.
     46  *
     47  * @author Clinton Begin
     48  */
     49 public class DefaultSqlSession implements SqlSession {
     50 
     51   private Configuration configuration;
     52   private Executor executor;
     53 
     54   private boolean autoCommit;
     55   private boolean dirty;
     56   private List<Cursor<?>> cursorList;
     57 
     58   public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
     59     this.configuration = configuration;
     60     this.executor = executor;
     61     this.dirty = false;
     62     this.autoCommit = autoCommit;
     63   }
     64 
     65   public DefaultSqlSession(Configuration configuration, Executor executor) {
     66     this(configuration, executor, false);
     67   }
     68 
     69   @Override
     70   public <T> T selectOne(String statement) {
     71     return this.<T>selectOne(statement, null);
     72   }
     73 
     74   @Override
     75   public <T> T selectOne(String statement, Object parameter) {
     76     // Popular vote was to return null on 0 results and throw exception on too many.
     77     List<T> list = this.<T>selectList(statement, parameter);
     78     if (list.size() == 1) {
     79       return list.get(0);
     80     } else if (list.size() > 1) {
     81       throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
     82     } else {
     83       return null;
     84     }
     85   }
     86 
     87   @Override
     88   public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
     89     return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
     90   }
     91 
     92   @Override
     93   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
     94     return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
     95   }
     96 
     97   @Override
     98   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
     99     final List<? extends V> list = selectList(statement, parameter, rowBounds);
    100     final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
    101         configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
    102     final DefaultResultContext<V> context = new DefaultResultContext<V>();
    103     for (V o : list) {
    104       context.nextResultObject(o);
    105       mapResultHandler.handleResult(context);
    106     }
    107     return mapResultHandler.getMappedResults();
    108   }
    109 
    110   @Override
    111   public <T> Cursor<T> selectCursor(String statement) {
    112     return selectCursor(statement, null);
    113   }
    114 
    115   @Override
    116   public <T> Cursor<T> selectCursor(String statement, Object parameter) {
    117     return selectCursor(statement, parameter, RowBounds.DEFAULT);
    118   }
    119 
    120   @Override
    121   public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
    122     try {
    123       MappedStatement ms = configuration.getMappedStatement(statement);
    124       Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
    125       registerCursor(cursor);
    126       return cursor;
    127     } catch (Exception e) {
    128       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    129     } finally {
    130       ErrorContext.instance().reset();
    131     }
    132   }
    133 
    134   @Override
    135   public <E> List<E> selectList(String statement) {
    136     return this.selectList(statement, null);
    137   }
    138 
    139   @Override
    140   public <E> List<E> selectList(String statement, Object parameter) {
    141     return this.selectList(statement, parameter, RowBounds.DEFAULT);
    142   }
    143 
    144   @Override
    145   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    146     try {
    147       MappedStatement ms = configuration.getMappedStatement(statement);
    148       return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    149     } catch (Exception e) {
    150       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    151     } finally {
    152       ErrorContext.instance().reset();
    153     }
    154   }
    155 
    156   @Override
    157   public void select(String statement, Object parameter, ResultHandler handler) {
    158     select(statement, parameter, RowBounds.DEFAULT, handler);
    159   }
    160 
    161   @Override
    162   public void select(String statement, ResultHandler handler) {
    163     select(statement, null, RowBounds.DEFAULT, handler);
    164   }
    165 
    166   @Override
    167   public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    168     try {
    169       MappedStatement ms = configuration.getMappedStatement(statement);
    170       executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    171     } catch (Exception e) {
    172       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    173     } finally {
    174       ErrorContext.instance().reset();
    175     }
    176   }
    177 
    178   @Override
    179   public int insert(String statement) {
    180     return insert(statement, null);
    181   }
    182 
    183   @Override
    184   public int insert(String statement, Object parameter) {
    185     return update(statement, parameter);
    186   }
    187 
    188   @Override
    189   public int update(String statement) {
    190     return update(statement, null);
    191   }
    192 
    193   @Override
    194   public int update(String statement, Object parameter) {
    195     try {
    196       dirty = true;
    197       MappedStatement ms = configuration.getMappedStatement(statement);
    198       return executor.update(ms, wrapCollection(parameter));
    199     } catch (Exception e) {
    200       throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    201     } finally {
    202       ErrorContext.instance().reset();
    203     }
    204   }
    205 
    206   @Override
    207   public int delete(String statement) {
    208     return update(statement, null);
    209   }
    210 
    211   @Override
    212   public int delete(String statement, Object parameter) {
    213     return update(statement, parameter);
    214   }
    215 
    216   @Override
    217   public void commit() {
    218     commit(false);
    219   }
    220 
    221   @Override
    222   public void commit(boolean force) {
    223     try {
    224       executor.commit(isCommitOrRollbackRequired(force));
    225       dirty = false;
    226     } catch (Exception e) {
    227       throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
    228     } finally {
    229       ErrorContext.instance().reset();
    230     }
    231   }
    232 
    233   @Override
    234   public void rollback() {
    235     rollback(false);
    236   }
    237 
    238   @Override
    239   public void rollback(boolean force) {
    240     try {
    241       executor.rollback(isCommitOrRollbackRequired(force));
    242       dirty = false;
    243     } catch (Exception e) {
    244       throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);
    245     } finally {
    246       ErrorContext.instance().reset();
    247     }
    248   }
    249 
    250   @Override
    251   public List<BatchResult> flushStatements() {
    252     try {
    253       return executor.flushStatements();
    254     } catch (Exception e) {
    255       throw ExceptionFactory.wrapException("Error flushing statements.  Cause: " + e, e);
    256     } finally {
    257       ErrorContext.instance().reset();
    258     }
    259   }
    260 
    261   @Override
    262   public void close() {
    263     try {
    264       executor.close(isCommitOrRollbackRequired(false));
    265       closeCursors();
    266       dirty = false;
    267     } finally {
    268       ErrorContext.instance().reset();
    269     }
    270   }
    271 
    272   private void closeCursors() {
    273     if (cursorList != null && cursorList.size() != 0) {
    274       for (Cursor<?> cursor : cursorList) {
    275         try {
    276           cursor.close();
    277         } catch (IOException e) {
    278           throw ExceptionFactory.wrapException("Error closing cursor.  Cause: " + e, e);
    279         }
    280       }
    281       cursorList.clear();
    282     }
    283   }
    284 
    285   @Override
    286   public Configuration getConfiguration() {
    287     return configuration;
    288   }
    289 
    290   @Override
    291   public <T> T getMapper(Class<T> type) {
    292     return configuration.<T>getMapper(type, this);
    293   }
    294 
    295   @Override
    296   public Connection getConnection() {
    297     try {
    298       return executor.getTransaction().getConnection();
    299     } catch (SQLException e) {
    300       throw ExceptionFactory.wrapException("Error getting a new connection.  Cause: " + e, e);
    301     }
    302   }
    303 
    304   @Override
    305   public void clearCache() {
    306     executor.clearLocalCache();
    307   }
    308 
    309   private <T> void registerCursor(Cursor<T> cursor) {
    310     if (cursorList == null) {
    311       cursorList = new ArrayList<Cursor<?>>();
    312     }
    313     cursorList.add(cursor);
    314   }
    315 
    316   private boolean isCommitOrRollbackRequired(boolean force) {
    317     return (!autoCommit && dirty) || force;
    318   }
    319 
    320   private Object wrapCollection(final Object object) {
    321     if (object instanceof Collection) {
    322       StrictMap<Object> map = new StrictMap<Object>();
    323       map.put("collection", object);
    324       if (object instanceof List) {
    325         map.put("list", object);
    326       }
    327       return map;
    328     } else if (object != null && object.getClass().isArray()) {
    329       StrictMap<Object> map = new StrictMap<Object>();
    330       map.put("array", object);
    331       return map;
    332     }
    333     return object;
    334   }
    335 
    336   public static class StrictMap<V> extends HashMap<String, V> {
    337 
    338     private static final long serialVersionUID = -5741767162221585340L;
    339 
    340     @Override
    341     public V get(Object key) {
    342       if (!super.containsKey(key)) {
    343         throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
    344       }
    345       return super.get(key);
    346     }
    347 
    348   }
    349 
    350 }
    View Code
  • 相关阅读:
    wget: command not found
    小程序循环多个picker选择器,实现动态增、减
    小程序 picker 多列选择器 数据动态获取
    有关https有的网站可以访问有的访问不了的问题
    微信小程序填坑之路
    linux如何搭建sftp服务器
    微信小程序模板中使用循环
    C#学习笔记(20)——使用IComparer(自己写的)
    C#学习笔记(19)——使用IComparer(百度文库)
    C#学习笔记(18)——C#构造函数中this和base的使用
  • 原文地址:https://www.cnblogs.com/jackion5/p/9480868.html
Copyright © 2011-2022 走看看