Mybatis源码解析-Mapper执行SQL过程

测试准备

添加mybatis-config.xml全局配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 引入外部资源配置文件 -->
    <properties resource="jdbc.properties"/>

    <settings>
        <!-- 开启驼峰自动映射 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 设置二级缓存开关 默认开启 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 延迟加载的开关 默认关闭-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--
            true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。
            false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性)。
            默认为false
         -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    <typeAliases>
        <!-- 别名 type 指定java对象类型 alias 别名名称 -->
         <typeAlias type="com.laravelshao.learning.mybatis.pojo.User" alias="User"/>
        <!-- 指定扫描包 Mybatis会将该包下所有类都生成别名(别名首字母不区分大小写) -->
        <package name="com.laravelshao.learning.mybatis.pojo"/>
    </typeAliases>

    <!-- 配置分页插件 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
            <!-- 使用RowBounds分页是否进行count查询 默认false-->
            <property name="rowBoundsWithCount" value="true"/>
        </plugin>
    </plugins>

    <!-- 配置环境 指定数据库连接信息 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- 引入mapper配置文件 -->
        <!--<mapper resource="com/laravelshao/learning/mybatis/mapper/UserMapper.xml"/>-->
        <!-- 配置mapper接口扫描包 -->
        <package name="com.laravelshao.learning.mybatis.mapper"/>
    </mappers>

</configuration>

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
jdbc.username=root
jdbc.password=123456

添加实体类

public class User implements Serializable {

    private Long id;

    // 用户名
    private String userName;

    // 密码
    private String password;

    // 姓名
    private String name;

    // 年龄
    private Integer age;

    // 性别 1 男性 2 女性
    private Integer sex;

    // 出生日期
    private Date birthday;

    // 创建时间
    private Date created;

    // 更新时间
    private Date updated;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", name=" + name
                + ", age=" + age + ", sex=" + sex + ", birthday=" + birthday + ", created=" + created
                + ", updated=" + updated + "]";
    }
}

添加mapper接口

public interface UserMapper {

    /**
     * 根据id查询用户信息
     *
     * @param id
     * @return
     */
    User queryUserById(Long id);

    /**
     * 查询所有用户数据
     *
     * @return
     */
    List<User> queryAll();

    /**
     * 新增用户信息
     *
     * @param user
     */
    void saveUser(User user);

    /**
     * 更新用户信息
     *
     * @param user
     */
    void updateUser(User user);

    /**
     * 根据id删除用户信息
     *
     * @param id
     */
    void deleteUserById(Long id);
}

添加mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 命名空间(保持唯一) 如需mybatis生成mapper动态代理类 则必须使用mapper接口全路径 -->
<mapper namespace="com.laravelshao.learning.mybatis.mapper.UserMapper">

    <!--
        id:ResultMap唯一标识
        type:结果集映射的java对象全路径或者别名
        autoMapping:是否自动映射没有映射关系的属性和字段 默认开启
    -->
    <resultMap id="userResultMap" type="User" autoMapping="true">
        <!-- column:字段名 property:属性名 -->
        <id column="id" property="id"/>
        <result column="user_name" property="userName"/>
    </resultMap>

    <!-- 根据id查询用户信息 -->
    <!--<select id="queryUserById" resultType="User">-->
    <select id="queryUserById" resultMap="userResultMap">
        SELECT * FROM tb_user WHERE id = #{id}
    </select>

    <!-- 查询所有用户数据 -->
    <select id="queryAll" resultType="com.laravelshao.learning.mybatis.pojo.User">
      SELECT * FROM tb_user
   </select>

    <!-- 新增用户信息 -->
    <insert id="saveUser" parameterType="com.laravelshao.learning.mybatis.pojo.User">
      INSERT INTO tb_user (
         id,
         user_name,
         password,
         name,
         age,
         sex,
         birthday,
         created,
         updated
      )
      VALUES
         (
            NULL,
            #{userName},
            #{password},
            #{name},
            #{age},
            #{sex},
            #{birthday},
            NOW(),
            NOW()
         );
   </insert>

    <!-- 更新用户信息 -->
    <update id="updateUser" parameterType="com.laravelshao.learning.mybatis.pojo.User">
      UPDATE tb_user
      SET
        user_name = #{userName},
        password = #{password},
        name = #{name},
        age = #{age},
        sex = #{sex},
        birthday = #{birthday},
        updated = NOW()
      WHERE
        id = #{id}
   </update>

    <!-- 根据id删除用户信息 -->
    <delete id="deleteUserById" parameterType="java.lang.Long">
      DELETE FROM tb_user WHERE id = #{id}
   </delete>

</mapper>

添加测试方法

public class UserMapperTest {

    private UserMapper userMapper;

    SqlSession sqlSession = null;
    SqlSessionFactory sqlSessionFactory = null;

    @Before
    public void setUp() throws Exception {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //openSession(boolean autoCommit) 设置事务是否自动提交
        sqlSession = sqlSessionFactory.openSession(true);
        // 获取动态代理实现类
        this.userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void testQueryUserById() {
        User user = userMapper.queryUserById(1L);
        System.out.println(user);
    }

    @Test
    public void testQueryAll() {
        List<User> users = userMapper.queryAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void testSaveUser() {
        User user = new User();  
        user.setAge(20);
        user.setBirthday(new Date());
        user.setName("test_name_1");
        user.setPassword("123456");
        user.setSex(1);
        user.setUserName("test_userName_1");
        userMapper.saveUser(user);
    }

    @Test
    public void testUpdateUser() {
        User user = userMapper.queryUserById(2L);
        user.setAge(30);
        userMapper.updateUser(user);
    }

    @Test
    public void testDeleteUserById() {
        userMapper.deleteUserById(8L);
    }

}

执行过程分析

SqlSession创建

SqlSession创建通过调用DefaultSqlSessionFactory的openSession方法进而调用openSessionFromDataSource方法

// DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;

    DefaultSqlSession var8;
    try {
        Environment environment = this.configuration.getEnvironment(); // 从全局配置类configuration获取environment信息
        TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); // 获取事务工厂
        // 创建新的事务 
        // 参数1:数据源 参数2:事务隔离级别 参数3:是否自动提交事务
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        Executor executor = this.configuration.newExecutor(tx, execType); // 创建执行器
        var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
    } catch (Exception var12) {
        this.closeTransaction(tx);
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
    } finally {
        ErrorContext.instance().reset();
    }

    return var8;
}

创建执行器

// Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? this.defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Object 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 (this.cacheEnabled) {
        executor = new CachingExecutor((Executor)executor);
    }

    Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
    return executor;
}

摘自mybatis官网

ExecutorType枚举类型定义了三个值:
• ExecutorType.SIMPLE:这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
• ExecutorType.REUSE:这个执行器类型会复用预处理语句。
• ExecutorType.BATCH:这个执行器会批量执行所有更新语句,如果SELECT在它们中间执行,必要时请把它们区分开来以保证行为的易读性。

Executor定义了具体执行SQL方法

public interface Executor {
    ResultHandler NO_RESULT_HANDLER = null;

    int update(MappedStatement var1, Object var2) throws SQLException;

    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;

    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;

    <E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;

    List<BatchResult> flushStatements() throws SQLException;

    void commit(boolean var1) throws SQLException;

    void rollback(boolean var1) throws SQLException;

    CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);

    boolean isCached(MappedStatement var1, CacheKey var2);

    void clearLocalCache();

    void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);

    Transaction getTransaction();

    void close(boolean var1);

    boolean isClosed();

    void setExecutorWrapper(Executor var1);
}

Mapper代理类创建

调用DefaultSqlSession的getMapper方法,进而调用MapperRegistry,最后调用MapperProxyFactory最终创建出mapper代理对象

// DefaultSqlSession
public <T> T getMapper(Class<T> type) {
    return this.configuration.getMapper(type, this);
}
// Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return this.mapperRegistry.getMapper(type, sqlSession);
}
// MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession); // 交给mapper代理工厂创建对象
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

Mapper代理工厂创建代理类对象

// MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
    MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
}

protected T newInstance(MapperProxy<T> mapperProxy) {
    // JDK动态代理生成mapper代理类对象
    return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

SQL执行流程

查询流程分析

这里以方法queryAll为例分析SQL执行过程

@Test
public void testQueryAll() {
    List<User> users = userMapper.queryAll();
    for (User user : users) {
        System.out.println(user);
    }
}

调用代理类的invoke方法

// MapperProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }

        if (this.isDefaultMethod(method)) {
            return this.invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }

    MapperMethod mapperMethod = this.cachedMapperMethod(method);
    return mapperMethod.execute(this.sqlSession, args); // 执行mapper方法
}

执行具体方法

// MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
    Object param;
    Object result;
    switch(this.command.getType()) { // 根据方法类型执行不同方法
    case INSERT:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        break;
    case UPDATE:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        break;
    case DELETE:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        break;
    case SELECT:
        if (this.method.returnsVoid() && this.method.hasResultHandler()) {
            this.executeWithResultHandler(sqlSession, args);
            result = null;
        } else if (this.method.returnsMany()) {
            result = this.executeForMany(sqlSession, args);
        } else if (this.method.returnsMap()) {
            result = this.executeForMap(sqlSession, args);
        } else if (this.method.returnsCursor()) {
            result = this.executeForCursor(sqlSession, args);
        } else {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = sqlSession.selectOne(this.command.getName(), param);
        }
        break;
    case FLUSH:
        result = sqlSession.flushStatements();
        break;
    default:
        throw new BindingException("Unknown execution method for: " + this.command.getName());
    }

    if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
        throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
    } else {
        return result;
    }
}

这里,我们查询所有用户,执行executeForMany方法

// MapperMethod
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    Object param = this.method.convertArgsToSqlCommandParam(args);
    List result;
    if (this.method.hasRowBounds()) {
        RowBounds rowBounds = this.method.extractRowBounds(args);
        result = sqlSession.selectList(this.command.getName(), param, rowBounds);
    } else {
        result = sqlSession.selectList(this.command.getName(), param);
    }

    if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
        return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
    } else {
        return result;
    }
}

调用默认实现DefaultSqlSession的selectList方法

// DefaultSqlSession
public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    List var5;
    try {
        MappedStatement ms = this.configuration.getMappedStatement(statement); // 根据statement ID从configuration配置中获取MappedStatement
        // 执行器执行查询任务
        var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception var9) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
    } finally {
        ErrorContext.instance().reset();
    }

    return var5;
}
// BaseExecutor
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter); // 根据参数动态组装执行sql
    CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql); // 为当前查询任务创建缓存key
    return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (this.closed) {
        throw new ExecutorException("Executor was closed.");
    } else {
        if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
            this.clearLocalCache();
        }

        List list;
        try {
            ++this.queryStack;
            list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
            if (list != null) {
                this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
            } else {
                list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); // 从数据库中查询
            }
        } finally {
            --this.queryStack;
        }

        if (this.queryStack == 0) {
            Iterator var8 = this.deferredLoads.iterator();

            while(var8.hasNext()) {
                BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                deferredLoad.load();
            }

            this.deferredLoads.clear();
            if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                this.clearLocalCache();
            }
        }

        return list;
    }
}

// 数据库查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

    List list;
    try {
        list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);  // 查询结果
    } finally {
        this.localCache.removeObject(key); 
    }

    this.localCache.putObject(key, list); // 将结果放入缓存中
    if (ms.getStatementType() == StatementType.CALLABLE) {
        this.localOutputParameterCache.putObject(key, parameter);
    }

    return list;
}

调用SimpleExecutor的doQuery方法

// SimpleExecutor
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;

    List var9;
    try {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        stmt = this.prepareStatement(handler, ms.getStatementLog()); // 准备语句
        var9 = handler.query(stmt, resultHandler);
    } finally {
        this.closeStatement(stmt);
    }

    return var9;
}

准备语句

// SimpleExecutor
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Connection connection = this.getConnection(statementLog); // 获取一个数据库连接对象
    Statement stmt = handler.prepare(connection, this.transaction.getTimeout()); // 使用StatementHandler从数据库连接对象中获取Statement对象
    handler.parameterize(stmt); // 设置参数 将sql语句中的占位符替换为具体参数
    return stmt;
}

调用PreparedStatementHandler最终执行sql语句

// PreparedStatementHandler
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement)statement;
    ps.execute(); // 执行具体sql语句
    return this.resultSetHandler.handleResultSets(ps); // 处理结果集
}

从上面可以看出Executor的执行过程

  • 首先获取一个数据库连接对象
  • 使用StatementHandler.prepare()方法从数据库连接对象中获取Statement对象
  • 使用StatementHandler.parameterize()方法将sql中占位符替换为具体执行参数
  • 最后调用StatementHandler. query()方法执行sql

处理结果集

// DefaultResultSetHandler
public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
    List<Object> multipleResults = new ArrayList();
    int resultSetCount = 0;
    ResultSetWrapper rsw = this.getFirstResultSet(stmt);
    List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    this.validateResultMapsCount(rsw, resultMapCount);

    while(rsw != null && resultMapCount > resultSetCount) {
        ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
        this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
        rsw = this.getNextResultSet(stmt);
        this.cleanUpAfterHandlingResultSet();
        ++resultSetCount;
    }

    String[] resultSets = this.mappedStatement.getResultSets();
    if (resultSets != null) {
        while(rsw != null && resultSetCount < resultSets.length) {
            ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
            if (parentMapping != null) {
                String nestedResultMapId = parentMapping.getNestedResultMapId();
                ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
                this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
            }

            rsw = this.getNextResultSet(stmt);
            this.cleanUpAfterHandlingResultSet();
            ++resultSetCount;
        }
    }

    return this.collapseSingleResultList(multipleResults);
}

整个执行过程完成。

更新流程分析

下面再看看更新操作,以saveUser方法为例分析更新流程(最终调用的都是update方法)

@Test
public void testSaveUser() {
    User user = new User();
    user.setAge(20);
    user.setBirthday(new Date());
    user.setName("test_name_22");
    user.setPassword("123456");
    user.setSex(1);
    user.setUserName("test_userName_22");
    userMapper.saveUser(user);
}

执行insert、update、delete最后调用的都是下面update方法

// DefaultSqlSession
public int update(String statement, Object parameter) {
    int var4;
    try {
        this.dirty = true;
        MappedStatement ms = this.configuration.getMappedStatement(statement); // 获取对应的MappedStatement
        var4 = this.executor.update(ms, this.wrapCollection(parameter)); // 执行更新操作(包括包装集合类型参数)
    } catch (Exception var8) {
        throw ExceptionFactory.wrapException("Error updating database.  Cause: " + var8, var8);
    } finally {
        ErrorContext.instance().reset();
    }

    return var4;
}
// BaseExecutor
public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (this.closed) {
        throw new ExecutorException("Executor was closed.");
    } else {
        this.clearLocalCache(); // 清除本地缓存
        return this.doUpdate(ms, parameter); // 执行更新操作
    }
}
// SimpleExecutor
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;

    int var6;
    try {
        Configuration configuration = ms.getConfiguration(); // 获取全局配置信息configuration
        // 创建StatementHandler
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        stmt = this.prepareStatement(handler, ms.getStatementLog()); // 准备Statement
        var6 = handler.update(stmt); // 处理更新操作
    } finally {
        this.closeStatement(stmt);
    }

    return var6;
}

最终执行update语句

// PreparedStatementHandler
public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement)statement;
    ps.execute(); // 执行语句
    int rows = ps.getUpdateCount(); // 获取更新行数
    Object parameterObject = this.boundSql.getParameterObject();
    KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator(); // KeyGenerator后置处理
    keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
    return rows;
}

这里重点分析下使用selectKey标签的SelectKeyGenerator实现

// SelectKeyGenerator
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    if (!this.executeBefore) { // 如果不是前置处理
        this.processGeneratedKeys(executor, ms, parameter); // 处理生成的key
    }

}

private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
    try {
        if (parameter != null && this.keyStatement != null && this.keyStatement.getKeyProperties() != null) {
            String[] keyProperties = this.keyStatement.getKeyProperties(); // 获取配置key的属性信息
            Configuration configuration = ms.getConfiguration(); // 获取全局配置参数configuration参数
            MetaObject metaParam = configuration.newMetaObject(parameter);
            if (keyProperties != null) {
                Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE); // 创建执行器
                List<Object> values = keyExecutor.query(this.keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER); // 执行查询操作
                if (values.size() == 0) { // 返回结果校验
                    throw new ExecutorException("SelectKey returned no data.");
                }

                if (values.size() > 1) {
                    throw new ExecutorException("SelectKey returned more than one value.");
                }

                MetaObject metaResult = configuration.newMetaObject(values.get(0));
                if (keyProperties.length == 1) { // 只有一个参数属性
                    if (metaResult.hasGetter(keyProperties[0])) {
                        this.setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
                    } else {
                        this.setValue(metaParam, keyProperties[0], values.get(0));
                    }
                } else {
                    this.handleMultipleProperties(keyProperties, metaParam, metaResult); // 多个参数属性
                }
            }
        }

    } catch (ExecutorException var10) {
        throw var10;
    } catch (Exception var11) {
        throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + var11, var11);
    }
}

private void handleMultipleProperties(String[] keyProperties, MetaObject metaParam, MetaObject metaResult) {
    String[] keyColumns = this.keyStatement.getKeyColumns();
    if (keyColumns != null && keyColumns.length != 0) { 
        if (keyColumns.length != keyProperties.length) {
            throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
        }

        for(int i = 0; i < keyProperties.length; ++i) {
            this.setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i])); // 如果没有指定列表 则直接使用属性名称赋值
        }
    } else {
        String[] var5 = keyProperties;
        int var6 = keyProperties.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            String keyProperty = var5[var7];
            this.setValue(metaParam, keyProperty, metaResult.getValue(keyProperty)); // 使用列名赋值
        }
    }

}

根据方法返回值类型将影响行数转换为指定类型

// MapperMethod
private Object rowCountResult(int rowCount) {
    Object result;
    if (this.method.returnsVoid()) {
        result = null;
    } else if (!Integer.class.equals(this.method.getReturnType()) && !Integer.TYPE.equals(this.method.getReturnType())) {
        if (!Long.class.equals(this.method.getReturnType()) && !Long.TYPE.equals(this.method.getReturnType())) {
            if (!Boolean.class.equals(this.method.getReturnType()) && !Boolean.TYPE.equals(this.method.getReturnType())) {
                throw new BindingException("Mapper method '" + this.command.getName() + "' has an unsupported return type: " + this.method.getReturnType());
            }

            result = rowCount > 0;
        } else {
            result = (long)rowCount;
        }
    } else {
        result = rowCount;
    }

    return result;
}

更新操作流程分析完成。

参考资料

https://blog.csdn.net/ashan_li/article/details/50378393
https://blog.csdn.net/luanlouis/article/details/40422941
https://blog.csdn.net/heroqiang/article/details/79121516
https://www.cnblogs.com/jeffen/p/6277696.html?utm_source=itdadao&utm_medium=referral
http://www.ccblog.cn/88.htm

猜你喜欢

转载自blog.csdn.net/laravelshao/article/details/81260281