1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢(xún)
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問(wèn)題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
      MyBatis之SqlSession介紹

      魯春利的工作筆記,好記性不如爛筆頭

      創(chuàng)新互聯(lián)長(zhǎng)期為上千客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為平川企業(yè)提供專(zhuān)業(yè)的成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,平川網(wǎng)站改版等技術(shù)服務(wù)。擁有十余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。


      轉(zhuǎn)載自:深入淺出MyBatis-Sqlsession

      SqlSession的創(chuàng)建

      Sqlsession對(duì)應(yīng)著一次數(shù)據(jù)庫(kù)會(huì)話。由于數(shù)據(jù)庫(kù)回話不是永久的,因此Sqlsession的生命周期也不應(yīng)該是永久的,相反,在你每次訪問(wèn)數(shù)據(jù)庫(kù)時(shí)都需要?jiǎng)?chuàng)建它(當(dāng)然并不是說(shuō)在Sqlsession里只能執(zhí)行一次sql,你可以執(zhí)行多次,當(dāng)一旦關(guān)閉了Sqlsession就需要重新創(chuàng)建它)。創(chuàng)建Sqlsession的地方只有一個(gè),那就是SqlsessionFactory的openSession方法:

      package org.apache.ibatis.session;
      
      import java.sql.Connection;
      
      public interface SqlSessionFactory {
      
        SqlSession openSession();
      
        SqlSession openSession(boolean autoCommit);
        SqlSession openSession(Connection connection);
        SqlSession openSession(TransactionIsolationLevel level);
      
        SqlSession openSession(ExecutorType execType);
        SqlSession openSession(ExecutorType execType, boolean autoCommit);
        SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
        SqlSession openSession(ExecutorType execType, Connection connection);
      
        Configuration getConfiguration();
      
      }

      實(shí)際創(chuàng)建SqlSession的地方是openSessionFromDataSource,如下:

      package org.apache.ibatis.session.defaults;
      
      import java.sql.Connection;
      import java.sql.SQLException;
      
      import org.apache.ibatis.exceptions.ExceptionFactory;
      import org.apache.ibatis.executor.ErrorContext;
      import org.apache.ibatis.executor.Executor;
      import org.apache.ibatis.mapping.Environment;
      import org.apache.ibatis.session.Configuration;
      import org.apache.ibatis.session.ExecutorType;
      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.TransactionIsolationLevel;
      import org.apache.ibatis.transaction.Transaction;
      import org.apache.ibatis.transaction.TransactionFactory;
      import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
      
      public class DefaultSqlSessionFactory implements SqlSessionFactory {
      
        private final Configuration configuration;
      
        public DefaultSqlSessionFactory(Configuration configuration) {
          this.configuration = configuration;
        }
      
        public SqlSession openSession() {
          return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
        }
        
        private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
          Transaction tx = null;
          try {
            final Environment environment = configuration.getEnvironment();
            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
            return new DefaultSqlSession(configuration, executor);
          } catch (Exception e) {
            closeTransaction(tx); // may have fetched a connection so lets call close()
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
          } finally {
            ErrorContext.instance().reset();
          }
        }
      }

      可以看出,創(chuàng)建sqlsession經(jīng)過(guò)了以下幾個(gè)主要步驟:

      1)       從配置中獲取Environment;

      2)       從Environment中取得DataSource;

      3)       從Environment中取得TransactionFactory;

      4)       從DataSource里獲取數(shù)據(jù)庫(kù)連接對(duì)象Connection;

      5)       在取得的數(shù)據(jù)庫(kù)連接上創(chuàng)建事務(wù)對(duì)象Transaction;

      6)       創(chuàng)建Executor對(duì)象(該對(duì)象非常重要,事實(shí)上sqlsession的所有操作都是通過(guò)它完成的);

      7)       創(chuàng)建sqlsession對(duì)象。

      Executor的創(chuàng)建

      Sqlsession只是個(gè)門(mén)面,真正干事的是Executor,Sqlsession對(duì)數(shù)據(jù)庫(kù)的操作都是通過(guò)Executor來(lái)完成的。與Sqlsession一樣,Executor也是動(dòng)態(tài)創(chuàng)建的:

      final Executor executor = configuration.newExecutor(tx, execType, autoCommit);

      Configuration類(lèi)的實(shí)現(xiàn):

      public class Configuration {
      
        protected Environment environment;
        
        public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
          executorType = executorType == null ? defaultExecutorType : executorType;
          executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
          Executor executor;
          if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
          } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
          } else {
            executor = new SimpleExecutor(this, transaction);
          }
          if (cacheEnabled) {
            executor = new CachingExecutor(executor, autoCommit);
          }
          executor = (Executor) interceptorChain.pluginAll(executor);
          return executor;
        } 
      }

      Executor的定義:

      package org.apache.ibatis.executor;
      
      import java.sql.SQLException;
      import java.util.List;
      
      import org.apache.ibatis.cache.CacheKey;
      import org.apache.ibatis.mapping.BoundSql;
      import org.apache.ibatis.mapping.MappedStatement;
      import org.apache.ibatis.reflection.MetaObject;
      import org.apache.ibatis.session.ResultHandler;
      import org.apache.ibatis.session.RowBounds;
      import org.apache.ibatis.transaction.Transaction;
      
      public interface Executor {
      
        ResultHandler NO_RESULT_HANDLER = null;
      
        int update(MappedStatement ms, Object parameter) throws SQLException;
      
         List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
      
         List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
      
        List flushStatements() throws SQLException;
      
        void commit(boolean required) throws SQLException;
      
        void rollback(boolean required) throws SQLException;
      
        CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
      
        boolean isCached(MappedStatement ms, CacheKey key);
      
        void clearLocalCache();
      
        void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType);
      
        Transaction getTransaction();
      
        void close(boolean forceRollback);
      
        boolean isClosed();
      
      }

      MyBatis之SqlSession介紹

      可以看出,創(chuàng)建的Executor只是3中基礎(chǔ)類(lèi)型之一:

            BatchExecutor專(zhuān)門(mén)用于執(zhí)行批量sql操作

            ReuseExecutor會(huì)重用statement執(zhí)行sql操作

            SimpleExecutor只是簡(jiǎn)單執(zhí)行sql沒(méi)有什么特別的。

      如果開(kāi)啟cache的話(默認(rèn)是開(kāi)啟的并且沒(méi)有任何理由去關(guān)閉它),就會(huì)創(chuàng)建CachingExecutor,它以前面創(chuàng)建的Executor作為唯一參數(shù)。CachingExecutor在查詢(xún)數(shù)據(jù)庫(kù)前先查找緩存,若沒(méi)找到的話調(diào)用delegate(就是構(gòu)造時(shí)傳入的Executor對(duì)象)從數(shù)據(jù)庫(kù)查詢(xún),并將查詢(xún)結(jié)果存入緩存中。

      package org.apache.ibatis.executor;
      
      import java.sql.SQLException;
      import java.util.List;
      
      import org.apache.ibatis.cache.Cache;
      import org.apache.ibatis.cache.CacheKey;
      import org.apache.ibatis.cache.TransactionalCacheManager;
      import org.apache.ibatis.mapping.BoundSql;
      import org.apache.ibatis.mapping.MappedStatement;
      import org.apache.ibatis.mapping.ParameterMapping;
      import org.apache.ibatis.mapping.ParameterMode;
      import org.apache.ibatis.mapping.StatementType;
      import org.apache.ibatis.reflection.MetaObject;
      import org.apache.ibatis.session.ResultHandler;
      import org.apache.ibatis.session.RowBounds;
      import org.apache.ibatis.transaction.Transaction;
      
      public class CachingExecutor implements Executor {
      
        private Executor delegate;
        private boolean autoCommit; // issue #573. No need to call commit() on autoCommit sessions
        private TransactionalCacheManager tcm = new TransactionalCacheManager();
      
        private boolean dirty;
      
        public CachingExecutor(Executor delegate) {
          this(delegate, false);
        }
      
        public CachingExecutor(Executor delegate, boolean autoCommit) {
          this.delegate = delegate;
          this.autoCommit = autoCommit;
        }
      
        public Transaction getTransaction() {
          return delegate.getTransaction();
        }
      
        public void close(boolean forceRollback) {
          try {
            //issue #499. Unresolved session handling
            //issue #573. Autocommit sessions should commit
            if (dirty && !autoCommit) { 
              tcm.rollback();
            } else {
              tcm.commit();
            }
          } finally {
            delegate.close(forceRollback);
          }
        }
        
        // 其他代碼略  
        
      }

      Executor對(duì)象是可以被插件攔截的(攔截器Interceptor,如:

      @Intercepts({@Signature(type = Executor.class, method = "query",
              args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})

      ),如果定義了針對(duì)Executor類(lèi)型的插件,最終生成的Executor對(duì)象是被各個(gè)插件插入后的代理對(duì)象。

      Mapper介紹

      Mybatis官方手冊(cè)建議通過(guò)mapper對(duì)象訪問(wèn)mybatis,因?yàn)槭褂胢apper看起來(lái)更優(yōu)雅,就像下面這樣:

      session = sqlSessionFactory.openSession();  
      UserMapper userMapper= session.getMapper(UserMapper.class);  
      UserBo user = new UserBo();  
      user.setUsername("iMbatis");  
      user.setPassword("iMbatis");  
      userMapper.insertUser(user);

      那么這個(gè)mapper到底是什么呢,它是如何創(chuàng)建的呢,它又是怎么與sqlsession等關(guān)聯(lián)起來(lái)的呢?下面為你一一解答。

      表面上看mapper是在sqlsession里創(chuàng)建的,但實(shí)際創(chuàng)建它的地方是MapperRegistry:

      package org.apache.ibatis.session;
      
      import java.io.Closeable;
      import java.sql.Connection;
      import java.util.List;
      import java.util.Map;
      
      import org.apache.ibatis.executor.BatchResult;
      
      /**
       * The primary Java interface for working with MyBatis.
       * Through this interface you can execute commands, get mappers and manage transactions.
       *
       */
      public interface SqlSession extends Closeable {
      
         T selectOne(String statement);
      
         T selectOne(String statement, Object parameter);
      
         List selectList(String statement);
      
         List selectList(String statement, Object parameter);
      
         List selectList(String statement, Object parameter, RowBounds rowBounds);
      
         Map selectMap(String statement, String mapKey);
      
         Map selectMap(String statement, Object parameter, String mapKey);
      
         Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
      
        void select(String statement, Object parameter, ResultHandler handler);
      
        void select(String statement, ResultHandler handler);
      
        void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
      
        int insert(String statement);
      
        int insert(String statement, Object parameter);
      
        int update(String statement);
      
        int update(String statement, Object parameter);
      
        int delete(String statement);
      
      
        int delete(String statement, Object parameter);
      
        void commit();
      
        void commit(boolean force);
      
        void rollback();
      
        void rollback(boolean force);
      
        List flushStatements();
      
        void close();
      
        void clearCache();
      
        Configuration getConfiguration();
      
         T getMapper(Class type);
      
        Connection getConnection();
      }

      SqlSeesion是接口,getMapper肯定是通過(guò)起實(shí)現(xiàn)類(lèi)來(lái)完成的,查看其類(lèi)結(jié)構(gòu):

      MyBatis之SqlSession介紹

      package org.apache.ibatis.session.defaults;
      
      import org.apache.ibatis.session.Configuration;
      import org.apache.ibatis.session.RowBounds;
      import org.apache.ibatis.session.SqlSession;
      
      public class DefaultSqlSession implements SqlSession {
      
        private Configuration configuration;
        private Executor executor;
      
        private boolean dirty;
        
        
        public  T getMapper(Class type) {
          return configuration.getMapper(type, this);
        }
      }  
      
      -- 其中configuration的實(shí)現(xiàn)為
        public  T getMapper(Class type, SqlSession sqlSession) {
          return mapperRegistry.getMapper(type, sqlSession);
        }
        
      -- MapperRegistry的實(shí)現(xiàn)為
      package org.apache.ibatis.binding;
      
      public class MapperRegistry {
      
        private Configuration config;
        private final Map, MapperProxyFactory> knownMappers = new HashMap, MapperProxyFactory>();
      
        public MapperRegistry(Configuration config) {
          this.config = config;
        }
        
        @SuppressWarnings("unchecked")
        public  T getMapper(Class type, SqlSession sqlSession) {
          final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) knownMappers.get(type);
          if (mapperProxyFactory == null)
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
          try {
            // ------
            return mapperProxyFactory.newInstance(sqlSession);
          } catch (Exception e) {
            throw new BindingException("Error getting mapper instance. Cause: " + e, e);
          }
        }
        
        public  boolean hasMapper(Class type) {
              return knownMappers.containsKey(type);
          }
      
          public  void addMapper(Class type) {
           if (type.isInterface()) {
            if (hasMapper(type)) {
              throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
            }
            boolean loadCompleted = false;
            try {
              knownMappers.put(type, new MapperProxyFactory(type));
              // It's important that the type is added before the parser is run
              // otherwise the binding may automatically be attempted by the
              // mapper parser. If the type is already known, it won't try.
              MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
              parser.parse();
              loadCompleted = true;
            } finally {
              if (!loadCompleted) {
                knownMappers.remove(type);
              }
            }
          }
      }

      可以看到,mapper是一個(gè)代理對(duì)象,它實(shí)現(xiàn)的接口就是傳入的type,這就是為什么mapper對(duì)象可以通過(guò)接口直接訪問(wèn)。同時(shí)還可以看到,創(chuàng)建mapper代理對(duì)象時(shí)傳入了sqlsession對(duì)象,這樣就把sqlsession也關(guān)聯(lián)起來(lái)了。我們進(jìn)一步看看mapperProxyFactory.newInstance(sqlSession);背后發(fā)生了什么事情:

      package org.apache.ibatis.binding;
      
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      import java.util.Map;
      import java.util.concurrent.ConcurrentHashMap;
      
      import org.apache.ibatis.session.SqlSession;
      
      public class MapperProxyFactory {
      
        private final Class mapperInterface;
        private Map methodCache = new ConcurrentHashMap();
      
        public MapperProxyFactory(Class mapperInterface) {
          this.mapperInterface = mapperInterface;
        }
      
        public Class getMapperInterface() {
          return mapperInterface;
        }
      
        public Map getMethodCache() {
          return methodCache;
        }
      
         /**
          * newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
          *   ClassLoader loader :類(lèi)加載器,一般使用和被代理對(duì)象相同的類(lèi)加載器
          *   Class[] interfaces :被代理對(duì)象(目標(biāo)對(duì)象)的接口數(shù)組
          *   InvocationHandler h : 設(shè)置回調(diào)對(duì)象,當(dāng)代理對(duì)象的方法被調(diào)用時(shí),會(huì)委派給該參數(shù)指定對(duì)象的invoke方法 
          */
        @SuppressWarnings("unchecked")
        protected T newInstance(MapperProxy mapperProxy) {
          return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
        }
      
        public T newInstance(SqlSession sqlSession) {
          final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
          return newInstance(mapperProxy);
        }
      
      }

      看起來(lái)沒(méi)什么特別的,和其他代理類(lèi)的創(chuàng)建一樣,我們重點(diǎn)關(guān)注一下MapperProxy的invoke方法。

      我們知道對(duì)被代理對(duì)象的方法的訪問(wèn)都會(huì)落實(shí)到代理者的invoke上來(lái),MapperProxy的invoke如下:

      package org.apache.ibatis.binding;
      
      import java.io.Serializable;
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.util.Map;
      
      import org.apache.ibatis.reflection.ExceptionUtil;
      import org.apache.ibatis.session.SqlSession;
      
      /**
       * @author Clinton Begin
       * @author Eduardo Macarron
       */
      public class MapperProxy implements InvocationHandler, Serializable {
      
        private static final long serialVersionUID = -6424540398559729838L;
        private final SqlSession sqlSession;
        private final Class mapperInterface;
        private final Map methodCache;
      
        public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {
          this.sqlSession = sqlSession;
          this.mapperInterface = mapperInterface;
          this.methodCache = methodCache;
        }
      
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          if (Object.class.equals(method.getDeclaringClass())) {
            try {
              // 轉(zhuǎn)調(diào)具體目標(biāo)對(duì)象的方法,這里目標(biāo)對(duì)象為this
              return method.invoke(this, args);
            } catch (Throwable t) {
              throw ExceptionUtil.unwrapThrowable(t);
            }
          }
          final MapperMethod mapperMethod = cachedMapperMethod(method);
          return mapperMethod.execute(sqlSession, args);
        }
      
        private MapperMethod cachedMapperMethod(Method method) {
          MapperMethod mapperMethod = methodCache.get(method);
          if (mapperMethod == null) {
            mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
            methodCache.put(method, mapperMethod);
          }
          return mapperMethod;
        }
      
      }

      可以看到invoke把執(zhí)行權(quán)轉(zhuǎn)交給了MapperMethod,我們來(lái)看看MapperMethod里又是怎么運(yùn)作的:

      package org.apache.ibatis.binding;
      
      import org.apache.ibatis.annotations.Flush;
      import org.apache.ibatis.annotations.MapKey;
      import org.apache.ibatis.annotations.Param;
      import org.apache.ibatis.mapping.MappedStatement;
      import org.apache.ibatis.mapping.SqlCommandType;
      import org.apache.ibatis.reflection.MetaObject;
      import org.apache.ibatis.session.Configuration;
      import org.apache.ibatis.session.ResultHandler;
      import org.apache.ibatis.session.RowBounds;
      import org.apache.ibatis.session.SqlSession;
      
      import java.lang.reflect.Array;
      import java.lang.reflect.Method;
      import java.util.*;
      
      /**
       * @author Clinton Begin
       * @author Eduardo Macarron
       * @author Lasse Voss
       */
      public class MapperMethod {
      
        private final SqlCommand command;
        private final MethodSignature method;
      
        public MapperMethod(Class mapperInterface, Method method, Configuration config) {
          this.command = new SqlCommand(config, mapperInterface, method);
          this.method = new MethodSignature(config, method);
        }
      
        public Object execute(SqlSession sqlSession, Object[] args) {
          Object result;
          if (SqlCommandType.INSERT == command.getType()) {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
          } else if (SqlCommandType.UPDATE == command.getType()) {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
          } else if (SqlCommandType.DELETE == command.getType()) {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
          } else if (SqlCommandType.SELECT == command.getType()) {
            if (method.returnsVoid() && method.hasResultHandler()) {
              executeWithResultHandler(sqlSession, args);
              result = null;
            } else if (method.returnsMany()) {
              result = executeForMany(sqlSession, args);
            } else if (method.returnsMap()) {
              result = executeForMap(sqlSession, args);
            } else {
              Object param = method.convertArgsToSqlCommandParam(args);
              result = sqlSession.selectOne(command.getName(), param);
            }
          } else if (SqlCommandType.FLUSH == command.getType()) {
              result = sqlSession.flushStatements();
          } else {
            throw new BindingException("Unknown execution method for: " + command.getName());
          }
          if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
            throw new BindingException("Mapper method '" + command.getName() 
                + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
          }
          return result;
        }
      
      }

      可以看到,MapperMethod就像是一個(gè)分發(fā)者,他根據(jù)參數(shù)和返回值類(lèi)型選擇不同的sqlsession方法來(lái)執(zhí)行。這樣mapper對(duì)象與sqlsession就真正的關(guān)聯(lián)起來(lái)了。

      Executor介紹

      sqlsession只是一個(gè)門(mén)面,真正發(fā)揮作用的是executor,對(duì)sqlsession方法的訪問(wèn)最終都會(huì)落到executor的相應(yīng)方法上去。

      Executor分成兩大類(lèi):一類(lèi)是CacheExecutor,另一類(lèi)是普通Executor。

      CacheExecutor

      CacheExecutor有一個(gè)重要屬性delegate,它保存的是某類(lèi)普通的Executor,值在構(gòu)照時(shí)傳入。執(zhí)行數(shù)據(jù)庫(kù)update操作時(shí),它直接調(diào)用delegate的update方法,執(zhí)行query方法時(shí)先嘗試從cache中取值,取不到再調(diào)用delegate的查詢(xún)方法,并將查詢(xún)結(jié)果存入cache中。

        @Override
        public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
            throws SQLException {
          Cache cache = ms.getCache();
          if (cache != null) {
            flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
              ensureNoOutParams(ms, parameterObject, boundSql);
              @SuppressWarnings("unchecked")
              List list = (List) tcm.getObject(cache, key);
              if (list == null) {
                list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                tcm.putObject(cache, key, list); // issue #578 and #116
              }
              return list;
            }
          }
           // delegate.query實(shí)際是org.apache.ibatis.executor.BaseExecutor.query
           // 最終會(huì)調(diào)用BaseExecutor
           return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        }

      普通Executor

      普通Executor有3類(lèi),他們都繼承于BaseExecutor,BatchExecutor專(zhuān)門(mén)用于執(zhí)行批量sql操作,ReuseExecutor會(huì)重用statement執(zhí)行sql操作,SimpleExecutor只是簡(jiǎn)單執(zhí)行sql沒(méi)有什么特別的。下面以SimpleExecutor為例:

        @Override
        public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
          Statement stmt = null;
          try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            stmt = prepareStatement(handler, ms.getStatementLog());
            return handler.query(stmt, resultHandler);
          } finally {
            closeStatement(stmt);
          }
        }

      可以看出,Executor本質(zhì)上也是個(gè)甩手掌柜,具體的事情原來(lái)是StatementHandler來(lái)完成的。

      StatementHandler介紹

      當(dāng)Executor將指揮棒交給StatementHandler后,接下來(lái)的工作就是StatementHandler的事了。我們先看看StatementHandler是如何創(chuàng)建的。

      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

      configuration.newStatementHandler的實(shí)現(xiàn)為:

        public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
          StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
          statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
          return statementHandler;
        }

      可以看到每次創(chuàng)建的StatementHandler都是RoutingStatementHandler,它只是一個(gè)分發(fā)者,他一個(gè)屬性delegate用于指定用哪種具體的StatementHandler。

      同時(shí)還要注意到StatementHandler是可以被攔截器攔截的,和Executor一樣,被攔截器攔截后的對(duì)像是一個(gè)代理對(duì)象。由于mybatis沒(méi)有實(shí)現(xiàn)數(shù)據(jù)庫(kù)的物理分頁(yè),眾多物理分頁(yè)的實(shí)現(xiàn)都是在這個(gè)地方使用攔截器實(shí)現(xiàn)的。

      可選的StatementHandler有SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler三種。選用哪種在mapper配置文件的每個(gè)statement里指定,默認(rèn)的是PreparedStatementHandler。

      MyBatis之SqlSession介紹

      MyBatis之SqlSession介紹

      statementType的取值是通過(guò)DTD文件來(lái)約束的:

      詳見(jiàn):http://mybatis.org/dtd/mybatis-3-mapper.dtd

      
      

      StatementHandler創(chuàng)建后需要執(zhí)行一些初始操作,比如statement的開(kāi)啟和參數(shù)設(shè)置、對(duì)于PreparedStatement還需要執(zhí)行參數(shù)的設(shè)置操作等。

      代碼如下:org.apache.ibatis.executor.SimpleExecutor

        private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
          Statement stmt;
          Connection connection = getConnection(statementLog);
          stmt = handler.prepare(connection);
          handler.parameterize(stmt);
          return stmt;
        }

      MyBatis之SqlSession介紹

      statement的開(kāi)啟和參數(shù)設(shè)置沒(méi)什么特別的地方:

      package org.apache.ibatis.executor.statement;
      
      import java.sql.Connection;
      import java.sql.SQLException;
      import java.sql.Statement;
      import java.util.List;
      
      import org.apache.ibatis.executor.Executor;
      import org.apache.ibatis.executor.ExecutorException;
      import org.apache.ibatis.executor.parameter.ParameterHandler;
      import org.apache.ibatis.mapping.BoundSql;
      import org.apache.ibatis.mapping.MappedStatement;
      import org.apache.ibatis.session.ResultHandler;
      import org.apache.ibatis.session.RowBounds;
      
      /**
       * @author Clinton Begin
       */
      public class RoutingStatementHandler implements StatementHandler {
      
        private final StatementHandler delegate;
      
        public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
      
          switch (ms.getStatementType()) {
            case STATEMENT:
              delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
              break;
            case PREPARED:
              delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
              break;
            case CALLABLE:
              delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
              break;
            default:
              throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
          }
      
        }
      
        @Override
        public Statement prepare(Connection connection) throws SQLException {
          return delegate.prepare(connection);
        }
      }

      org.apache.ibatis.executor.statement.PreparedStatementHandler并沒(méi)有對(duì)prepare的具體實(shí)現(xiàn),調(diào)用的還是其父類(lèi)org.apache.ibatis.executor.statement.BaseStatementHandler的實(shí)現(xiàn):

        @Override
        public Statement prepare(Connection connection) throws SQLException {
          ErrorContext.instance().sql(boundSql.getSql());
          Statement statement = null;
          try {
            statement = instantiateStatement(connection);
            setStatementTimeout(statement);
            setFetchSize(statement);
            return statement;
          } catch (SQLException e) {
            closeStatement(statement);
            throw e;
          } catch (Exception e) {
            closeStatement(statement);
            throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
          }
        }

      handler.parameterize倒是可以看看是怎么回事:

      MyBatis之SqlSession介紹

      handler.parameterize通過(guò)調(diào)用ParameterHandler的setParameters完成參數(shù)的設(shè)置,ParameterHandler隨著StatementHandler的創(chuàng)建而創(chuàng)建,默認(rèn)的實(shí)現(xiàn)是DefaultParameterHandler:

      // ======================================================================
      package org.apache.ibatis.executor.statement;
      
      /**
       * @author Clinton Begin
       */
      public class PreparedStatementHandler extends BaseStatementHandler {
      
        public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
          super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
        }
      
        // 代碼略
      
        @Override
        public void parameterize(Statement statement) throws SQLException {
          parameterHandler.setParameters((PreparedStatement) statement);
        }
      
      }
      
      
      // ======================================================================
      package org.apache.ibatis.executor.statement;
      
      import java.sql.Connection;
      import java.sql.SQLException;
      import java.sql.Statement;
      
      import org.apache.ibatis.executor.ErrorContext;
      import org.apache.ibatis.executor.Executor;
      import org.apache.ibatis.executor.ExecutorException;
      import org.apache.ibatis.executor.keygen.KeyGenerator;
      import org.apache.ibatis.executor.parameter.ParameterHandler;
      import org.apache.ibatis.executor.resultset.ResultSetHandler;
      import org.apache.ibatis.mapping.BoundSql;
      import org.apache.ibatis.mapping.MappedStatement;
      import org.apache.ibatis.reflection.factory.ObjectFactory;
      import org.apache.ibatis.session.Configuration;
      import org.apache.ibatis.session.ResultHandler;
      import org.apache.ibatis.session.RowBounds;
      import org.apache.ibatis.type.TypeHandlerRegistry;
      
      /**
       * @author Clinton Begin
       */
      public abstract class BaseStatementHandler implements StatementHandler {
      
        protected final Configuration configuration;
        protected final ObjectFactory objectFactory;
        protected final TypeHandlerRegistry typeHandlerRegistry;
        protected final ResultSetHandler resultSetHandler;
        protected final ParameterHandler parameterHandler;
      
        protected final Executor executor;
        protected final MappedStatement mappedStatement;
        protected final RowBounds rowBounds;
      
        protected BoundSql boundSql;
      
        protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
          this.configuration = mappedStatement.getConfiguration();
          this.executor = executor;
          this.mappedStatement = mappedStatement;
          this.rowBounds = rowBounds;
      
          this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
          this.objectFactory = configuration.getObjectFactory();
      
          if (boundSql == null) { // issue #435, get the key before calculating the statement
            generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
          }
      
          this.boundSql = boundSql;
          
          // 默認(rèn)為org.apache.ibatis.scripting.defaults.DefaultParameterHandler
          this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
          this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
        }
      
      }

      同Executor和StatementHandler一樣,ParameterHandler也是可以被攔截的。

      DefaultParameterHandler

      DefaultParameterHandler里設(shè)置參數(shù)的代碼如下:

      package org.apache.ibatis.scripting.defaults;
      
      import java.sql.PreparedStatement;
      import java.sql.SQLException;
      import java.util.List;
      
      import org.apache.ibatis.executor.ErrorContext;
      import org.apache.ibatis.executor.parameter.ParameterHandler;
      import org.apache.ibatis.mapping.BoundSql;
      import org.apache.ibatis.mapping.MappedStatement;
      import org.apache.ibatis.mapping.ParameterMapping;
      import org.apache.ibatis.mapping.ParameterMode;
      import org.apache.ibatis.reflection.MetaObject;
      import org.apache.ibatis.session.Configuration;
      import org.apache.ibatis.type.JdbcType;
      import org.apache.ibatis.type.TypeException;
      import org.apache.ibatis.type.TypeHandler;
      import org.apache.ibatis.type.TypeHandlerRegistry;
      
      /**
       * @author Clinton Begin
       * @author Eduardo Macarron
       */
      public class DefaultParameterHandler implements ParameterHandler {
      
        private final TypeHandlerRegistry typeHandlerRegistry;
      
        private final MappedStatement mappedStatement;
        private final Object parameterObject;
        private BoundSql boundSql;
        private Configuration configuration;
      
        public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
          this.mappedStatement = mappedStatement;
          this.configuration = mappedStatement.getConfiguration();
          this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
          this.parameterObject = parameterObject;
          this.boundSql = boundSql;
        }
      
        @Override
        public Object getParameterObject() {
          return parameterObject;
        }
      
        @Override
        public void setParameters(PreparedStatement ps) {
          ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
          List parameterMappings = boundSql.getParameterMappings();
          if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
              ParameterMapping parameterMapping = parameterMappings.get(i);
              if (parameterMapping.getMode() != ParameterMode.OUT) {
                Object value;
                String propertyName = parameterMapping.getProperty();
                if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                  value = boundSql.getAdditionalParameter(propertyName);
                } else if (parameterObject == null) {
                  value = null;
                } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                  value = parameterObject;
                } else {
                  MetaObject metaObject = configuration.newMetaObject(parameterObject);
                  value = metaObject.getValue(propertyName);
                }
                TypeHandler typeHandler = parameterMapping.getTypeHandler();
                JdbcType jdbcType = parameterMapping.getJdbcType();
                if (value == null && jdbcType == null) {
                  jdbcType = configuration.getJdbcTypeForNull();
                }
                try {
                  typeHandler.setParameter(ps, i + 1, value, jdbcType);
                } catch (TypeException e) {
                  throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                } catch (SQLException e) {
                  throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                }
              }
            }
          }
        }
      
      }

      這里面最重要的一句其實(shí)就是最后一句代碼,它的作用是用合適的TypeHandler完成參數(shù)的設(shè)置。那么什么是合適的TypeHandler呢,它又是如何決斷出來(lái)的呢?BaseStatementHandler的構(gòu)造方法里有這么一句:

          if (boundSql == null) { // issue #435, get the key before calculating the statement
            generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
          }

      它觸發(fā)了sql 的解析,在解析sql的過(guò)程中,TypeHandler也被決斷出來(lái)了,決斷的原則就是根據(jù)參數(shù)的類(lèi)型和參數(shù)對(duì)應(yīng)的JDBC類(lèi)型決定使用哪個(gè)TypeHandler。比如:參數(shù)類(lèi)型是String的話就用StringTypeHandler,參數(shù)類(lèi)型是整數(shù)的話就用IntegerTypeHandler等。

      參數(shù)設(shè)置完畢后,執(zhí)行數(shù)據(jù)庫(kù)操作(update或query)。如果是query最后還有個(gè)查詢(xún)結(jié)果的處理過(guò)程。

      ResultSetHandler

      結(jié)果處理使用ResultSetHandler來(lái)完成,默認(rèn)的ResultSetHandler是FastResultSetHandler,它在創(chuàng)建StatementHandler時(shí)一起創(chuàng)建,代碼如下:

      org.apache.ibatis.executor.statement.BaseStatementHandler

          this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
          this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);

      org.apache.ibatis.session.Configuration

        public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
            ResultHandler resultHandler, BoundSql boundSql) {
          ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
          resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
          return resultSetHandler;
        }

      org.apache.ibatis.executor.statement.PreparedStatementHandler

        @Override
        public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
          PreparedStatement ps = (PreparedStatement) statement;
          ps.execute();
          return resultSetHandler. handleResultSets(ps);
        }

      可以看出ResultSetHandler也是可以被攔截的,可以編寫(xiě)自己的攔截器改變ResultSetHandler的默認(rèn)行為。

      MyBatis之SqlSession介紹

        private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
          List autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
          boolean foundValues = false;
          if (autoMapping.size() > 0) {
            for (UnMappedColumAutoMapping mapping : autoMapping) {
              final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
              // issue #377, call setter on nulls
              if (value != null || configuration.isCallSettersOnNulls()) {
                if (value != null || !mapping.primitive) {
                  metaObject.setValue(mapping.property, value);
                }
                foundValues = true;
              }
            }
          }
          return foundValues;
        }

      從代碼里可以看到,決斷TypeHandler使用的是結(jié)果參數(shù)的屬性類(lèi)型。因此我們?cè)诙x作為結(jié)果的對(duì)象的屬性時(shí)一定要考慮與數(shù)據(jù)庫(kù)字段類(lèi)型的兼容性。

      附件:http://down.51cto.com/data/2366409

      文章名稱(chēng):MyBatis之SqlSession介紹
      文章轉(zhuǎn)載:http://ef60e0e.cn/article/jjpcco.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        涟水县| 秭归县| 定州市| 桂平市| 申扎县| 云浮市| 泾川县| 龙岩市| 通州市| 绵阳市| 任丘市| 天门市| 改则县| 翼城县| 滨州市| 邢台县| 达尔| 五常市| 安顺市| 漳平市| 揭东县| 垦利县| 平武县| 年辖:市辖区| 襄汾县| 青岛市| 彰化市| 鹤壁市| 伊通| 中江县| 武城县| 奉化市| 东乡族自治县| 彭山县| 大庆市| 博爱县| 怀集县| 庆云县| 新安县| 塔河县| 商都县|