Skip to content

Latest commit

 

History

History
122 lines (78 loc) · 5.07 KB

File metadata and controls

122 lines (78 loc) · 5.07 KB

15.Mybatis

MyBatis 编程步骤

  1. 创建 SqlSessionFactory 对象。

  2. 通过 SqlSessionFactory 获取 SqlSession 对象。

  3. 通过 SqlSession 获得 Mapper 代理对象。

  4. 通过 Mapper 代理对象,执行数据库操作。

  5. 执行成功,则使用 SqlSession 提交事务。

  6. 执行失败,则使用 SqlSession 回滚事务。

  7. 最终,关闭会话。

MyBatis 如何执行批量插入?

  1. 使用Sql 拼接,有语句大小限制

    INSERT INTO [表名]([列名],[列名]) 
    VALUES
    ([列值],[列值])),
    ([列值],[列值])),
    ([列值],[列值]));
  2. 使用Mybatis 的批量插入方式

    private static SqlSessionFactory sqlSessionFactory;
    
    @Test
    public void testBatch() {
        // 创建要插入的用户的名字的数组
        List<String> names = new ArrayList<>();
        names.add("张三");
        names.add("李四");
        names.add("李二");
        names.add("王五");
    
        // 获得执行器类型为 Batch 的 SqlSession 对象,并且 autoCommit = false ,禁止事务自动提交
        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
            // 获得 Mapper 对象
            UserMapper mapper = session.getMapper(UserMapper.class);
            // 循环插入
            for (String name : names) {
                mapper.insertUser(name);
            }
            // 提交批量操作
            session.commit();
        }
    }
  3. 使用循环一条条插入

Mybatis 的 XML Mapper文件中,不同的 XML 映射文件,id 是否可以重复?

不同的 XML Mapper 文件,如果配置了 "namespace" ,那么 id 可以重复;如果没有配置 "namespace" ,那么 id 不能重复。毕竟"namespace" 不是必须的,只是最佳实践而已。

原因就是,namespace + id 是作为 Map<String, MappedStatement> 的 key 使用的。如果没有 "namespace",就剩下 id ,那么 id 重复会导致数据互相覆盖。如果有了 "namespace",自然 id 就可以重复,"namespace"不同,namespace + id 自然也就不同。

简述 Mybatis 的 XML 映射文件和 Mybatis 内部数据结构之间的映射关系?

Mybatis 将所有 XML 配置信息都封装到 All-In-One 重量级对象Configuration内部。

在 XML Mapper 文件中:

  • <parameterMap> 标签,会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。

  • <resultMap> 标签,会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。

  • 每一个 <select><insert><update><delete> 标签,均会被解析为一个 MappedStatement 对象,标签内的 SQL 会被解析为一个 BoundSql 对象。

通常一个 XML 映射文件,都会写一个 Mapper 接口与之对应。请问,这个 Mapper 接口的工作原理是什么?Mapper 接口里的方法,参数不同时,方法能重载吗?

Mapper 接口,对应的关系如下:

  • 接口的全限名,就是映射文件中的 "namespace" 的值。
  • 接口的方法名,就是映射文件中 MappedStatement 的 "id" 值。
  • 接口方法内的参数,就是传递给 SQL 的参数。

Mapper 接口是没有实现类的,当调用接口方法时,接口全限名 + 方法名拼接字符串作为 key 值,可唯一定位一个对应的 MappedStatement 。举例:com.mybatis3.mappers.StudentDao.findStudentById ,可以唯一找到 "namespace"com.mybatis3.mappers.StudentDao 下面 "id"findStudentById 的 MappedStatement 。

总结来说,在 Mybatis 中,每一个 <select /><insert /><update /><delete /> 标签,都会被解析为一个 MappedStatement 对象。

另外,Mapper 接口的实现类,通过 MyBatis 使用 JDK Proxy 自动生成其代理对象 Proxy ,而代理对象 Proxy 会拦截接口方法,从而“调用”对应的 MappedStatement 方法,最终执行 SQL ,返回执行结果。整体流程如下图:流程

  • 其中,SqlSession 在调用 Executor 之前,会获得对应的 MappedStatement 方法。例如:DefaultSqlSession#select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) 方法,代码如下:

    // DefaultSqlSession.java
    
    @Override
    public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        try {
            // 获得 MappedStatement 对象
            MappedStatement ms = configuration.getMappedStatement(statement);
            // 执行查询
            executor.query(ms, wrapCollection(parameter), rowBounds, handler);
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

Mapper 接口里的方法,是不能重载的,因为是全限名 + 方法名的保存和寻找策略