美文网首页
Mybatis(一)

Mybatis(一)

作者: 纸箱子的一 | 来源:发表于2018-09-13 18:25 被阅读0次

    Mybatis

    从BindingTest开始debug,,,
    配置初始化

      @BeforeClass
      public static void setup() throws Exception {
        DataSource dataSource = BaseDataTest.createBlogDataSource();
        BaseDataTest.runScript(dataSource, BaseDataTest.BLOG_DDL);
        BaseDataTest.runScript(dataSource, BaseDataTest.BLOG_DATA);
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("Production", transactionFactory, dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.setLazyLoadingEnabled(true);
        configuration.setUseActualParamName(false); // to test legacy style reference (#{0} #{1})
        //1、注册别名
        configuration.getTypeAliasRegistry().registerAlias(Blog.class);
        configuration.getTypeAliasRegistry().registerAlias(Post.class);
        configuration.getTypeAliasRegistry().registerAlias(Author.class);
        // 2、Mapper接口注册
        configuration.addMapper(BoundBlogMapper.class);
        configuration.addMapper(BoundAuthorMapper.class);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
      }
    

    1、注册别名

      public void registerAlias(Class<?> type) {
        String alias = type.getSimpleName();
        Alias aliasAnnotation = type.getAnnotation(Alias.class);
        if (aliasAnnotation != null) {
          alias = aliasAnnotation.value();
        } 
        registerAlias(alias, type);
      }
    
      public void registerAlias(String alias, Class<?> value) {
        if (alias == null) {
          throw new TypeException("The parameter alias cannot be null");
        }
        // issue #748
        String key = alias.toLowerCase(Locale.ENGLISH);
        if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
          throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
        }
        TYPE_ALIASES.put(key, value);
      }
    

    2、在MapperRegistry中进行Mapper接口注册

      public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
      }
      public <T> void addMapper(Class<T> type) {
        if (type.isInterface()) {
          if (hasMapper(type)) {
            throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
          }
          boolean loadCompleted = false;
          try {
            //  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
            knownMappers.put(type, new MapperProxyFactory<T>(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);
            // 解析mapper接口对应的Mapper.xml
            parser.parse();
            loadCompleted = true;
          } finally {
            if (!loadCompleted) {
              knownMappers.remove(type);
            }
          }
        }
      }
    

    knownMappers 在这个Map中存储了Mapper接口与其mapperProxyFactory的映射关系。将来MapperProxy-->invoke 中mapperMethod.execute(sqlSession, args) 是执行sql的关键。
    继续Test测试类

      @Test
      public void shouldSelectBlogWithPostsUsingSubSelect() throws Exception {
        // 获取sqlsession对象  可以commit  rollback close(close conn归还给线程池)
        SqlSession session = sqlSessionFactory.openSession();
        try {
        // 1、获取Mapper接口的代理类
          BoundBlogMapper mapper = session.getMapper(BoundBlogMapper.class);
        //2、通过代理Mapper执行sql
          Blog b = mapper.selectBlogWithPostsUsingSubSelect(1);
          assertEquals(1, b.getId());
          session.close();
          assertNotNull(b.getAuthor());
          assertEquals(101, b.getAuthor().getId());
          assertEquals("jim", b.getAuthor().getUsername());
          assertEquals("********", b.getAuthor().getPassword());
          assertEquals(2, b.getPosts().size());
        } finally {
          session.close();
        }
      }
    

    1、获取Mapper接口的代理类,经过DefaultSqlSession--->getMapper(Class<T> type)与Configuration--->getMapper(Class<T> type, SqlSession sqlSession),最终调用mapperRegistry.getMapper(type, sqlSession)获取mapper代理。

      @SuppressWarnings("unchecked")
      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) 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);
        }
      }
      @SuppressWarnings("unchecked")
      protected T newInstance(MapperProxy<T> mapperProxy) {
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
      }
    
      public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    

    2、通过代理Mapper执行sql

      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
          } else if (isDefaultMethod(method)) {
            return invokeDefaultMethod(proxy, method, args);
          }
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        // 执行mapperMethod.execute方法
        return mapperMethod.execute(sqlSession, args);
      }
    
    // mapperMethod.execute 部分代码
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        switch (command.getType()) {
          case INSERT: {
          Object param = method.convertArgsToSqlCommandParam(args);
          // Sqlsession 中执行insert 方法
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
          }
          case UPDATE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
          }
          case DELETE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
          }
    ........
    
      @Override
      public int insert(String statement, Object parameter) {
        return update(statement, parameter);
      }
    
      @Override
      public int update(String statement, Object parameter) {
        try {
          dirty = true;
          MappedStatement ms = configuration.getMappedStatement(statement);
          // executor.update
          return executor.update(ms, wrapCollection(parameter));
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
    

    3、Executor对象(以后对Executor进行分析)


    Executor.png

    BaseExecutor 执行update

      @Override
      public int update(MappedStatement ms, Object parameter) throws SQLException {
        ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
        if (closed) {
          throw new ExecutorException("Executor was closed.");
        }
        clearLocalCache();
        // doUpdate  交给具体的子类执行  BaseExecutor   里边是个抽象方法
        return doUpdate(ms, parameter);
      }
         //抽象方法  doUpdate  交给具体的子类执行
      protected abstract int doUpdate(MappedStatement ms, Object parameter)
          throws SQLException;
    

    在SimpleExecutor中执行

      @Override
      public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;
        try {
          Configuration configuration = ms.getConfiguration();
          // 获取 StatementHandler
          StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
          // 获取Statement  对象
          stmt = prepareStatement(handler, ms.getStatementLog());
          // Statement处理器
          return handler.update(stmt);
        } finally {
          closeStatement(stmt);
        }
      }
          // 获取Statement  对象
      private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        Connection connection = getConnection(statementLog);
        stmt = handler.prepare(connection, transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
      }
    

    StatementHandler(简单语句处理器)进行处理 (以后对StatementHandler 进行分析)


    StatementHandler.png
      @Override
      public int update(Statement statement) throws SQLException {
        String sql = boundSql.getSql();
        Object parameterObject = boundSql.getParameterObject();
        // 键值生成器
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        int rows;
        // 键值生成器的类型
        if (keyGenerator instanceof Jdbc3KeyGenerator) {
        //  执行sql语句
          statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
          rows = statement.getUpdateCount();
          keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
        } else if (keyGenerator instanceof SelectKeyGenerator) {
          statement.execute(sql);
          rows = statement.getUpdateCount();
          keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
        } else {
          // 如果不使用键值生成器 直接执行sql
          statement.execute(sql);
          rows = statement.getUpdateCount();
        }
        return rows;
      }
    
    
    mybatis.png

    相关文章

      网友评论

          本文标题:Mybatis(一)

          本文链接:https://www.haomeiwen.com/subject/lwxvgftx.html