我把问烂了的⭐MyBatis面试题⭐总结了一下(带答案,万字总结,精心打磨,建议收藏)

个人主页: Java程序鱼

如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)和订阅专栏

微信号:hzy1014211086,想加入技术交流群的小伙伴可以加我好友,群里会分享学习资料、学习方法


序号 内容 链接地址
1 Java基础知识面试题 https://blog.csdn.net/qq_35620342/article/details/119636436
2 Java集合容器面试题 https://blog.csdn.net/qq_35620342/article/details/119947254
3 Java并发编程面试题 https://blog.csdn.net/qq_35620342/article/details/119977224
4 Java异常面试题 https://blog.csdn.net/qq_35620342/article/details/119977051
5 JVM面试题 https://blog.csdn.net/qq_35620342/article/details/119948989
6 Java Web面试题 https://blog.csdn.net/qq_35620342/article/details/119642114
7 Spring面试题 https://blog.csdn.net/qq_35620342/article/details/119956512
8 Spring MVC面试题 https://blog.csdn.net/qq_35620342/article/details/119965560
9 Spring Boot面试题 https://blog.csdn.net/qq_35620342/article/details/120333717
10 MyBatis面试题 https://blog.csdn.net/qq_35620342/article/details/119956541
11 Spring Cloud面试题 待分享
12 Redis面试题 https://blog.csdn.net/qq_35620342/article/details/119575020
13 MySQL数据库面试题 https://blog.csdn.net/qq_35620342/article/details/119930887
14 RabbitMQ面试题 待分享
15 Dubbo面试题 待分享
16 Linux面试题 待分享
17 Tomcat面试题 待分享
18 ZooKeeper面试题 待分享
19 Netty面试题 待分享
20 数据结构与算法面试题 待分享

文章目录

  • 1.MyBatis是什么?
  • 2.ORM是什么
  • 3.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
  • 4.传统JDBC开发存在的问题
  • 5.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
  • 6.MyBatis与Hibernate
  • 7.Mybatis优缺点
  • 8.MyBatis框架适用场景
  • 9.MyBatis编程步骤是什么样的?
  • 10.请说说MyBatis的工作原理
  • 11.MyBatis功能架构
  • 12.MyBatis的框架架构设计是怎么样的
  • 13.为什么需要预编译
  • 14.Mybatis都有哪些Executor执行器?它们之间的区别是什么?
  • 15.Mybatis中如何指定使用哪一种Executor执行器?
  • 16.Mybatis延迟加载
  • 17.#{}和${}的区别
  • 18.模糊查询like语句该怎么写
  • 19.在mapper中如何传递多个参数
  • 20.Mybatis如何执行批量操作
  • 21.如何获取生成的主键
  • 22.当实体类中的属性名和表中的字段名不一样 ,怎么办
  • 23.Mapper 编写有哪几种方式?
  • 24.MyBatis接口绑定的几种方式
  • 25.使用MyBatis的mapper接口调用时有哪些要求?
  • 26.通常一个mapper.XML对应一个DAO接口,DAO是否可以重载?
  • 27.MyBatis不同映射文件中的id是否可以重复?
  • 28.简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?
  • 29.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
  • 30.Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
  • 31.MyBatis映射文件中A标签引用B标签,如果B标签在A的后面定义,可以吗?
  • 32.MyBatis实现一对一,一对多有几种方式,怎么操作的?
  • 33.Mybatis是否可以映射Enum枚举类?
  • 34.Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
  • 35.Mybatis是如何进行分页的?
  • 36.简述Mybatis的插件运行原理,以及如何编写一个插件。
  • 37.Mybatis缓存机制


1.MyBatis是什么?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

2.ORM是什么

ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。

3.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?

Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。

而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。

4.传统JDBC开发存在的问题

JDBC是Java连接关系数据库的底层API,利用JDBC开发持久层存在诸多问题,而MyBatis正是为了解决JDBC的以下问题而生的。

  • 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
  • Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
  • 使用PreparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
  • 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

5.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。

2、Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、使用PreparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。

解决: Mybatis自动将java对象映射至sql语句。

4、对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象。

6.MyBatis与Hibernate

MyBatis和Hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过Mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

MyBatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用Hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

7.Mybatis优缺点

优点

与传统的数据库访问技术相比,ORM有以下优点:

  • 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用
  • 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
  • 很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)
  • 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护
  • 能够与Spring很好的集成

缺点

  • SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求
  • SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库

8.MyBatis框架适用场景

  • MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
  • 对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。

9.MyBatis编程步骤是什么样的?

(1)获取SqlSessionFactory对象
解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession;
注意:【MappedStatement】:代表一个增删改查的详细信息

(2)获取SqlSession对象
返回一个DefaultSqlSession对象,包含Executor和Configuration;
这一步会创建Executor;

(3)获取接口的代理对象(MapperProxy)
getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象,代理对象里包含了DefaultSqlSession(Executor)

(4)执行增删改查方法

(5)关闭会话

10.请说说MyBatis的工作原理

在学习 MyBatis 程序之前,需要了解一下 MyBatis 工作原理,以便于理解程序。MyBatis 的工作原理如下图

MyBatis工作原理

  • SqlMapConfig.xml,此文件作为MyBatis的全局配置文件,配置了mybatis的运行环境等信息。Mapper.xml文件即SQL映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
  • 通过MyBatis环境等配置信息构造SqlSessionFactory即会话工厂
  • 由会话工厂创建SqlSession即会话,操作数据库需要通过SqlSession进行。
  • Mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  • Mapped Statement也是MyBatis一个底层封装对象,它包装了MyBatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
  • Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对PreparedStatement设置参数。
  • Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、Pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至Java对象中,输出结果映射过程相当于Jdbc编程中对结果的解析处理过程。

11.MyBatis功能架构

Mybatis功能框架
我们把Mybatis的功能架构分为三层:

  • API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
  • 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
  • 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

12.MyBatis的框架架构设计是怎么样的

Mybatis框架架构

这张图从上往下看。MyBatis的初始化,会从mybatis-config.xml配置文件,解析构造成Configuration这个类,就是图中的红框。

(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。

(2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。

(3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。

(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。

13.为什么需要预编译

1.定义:
SQL 预编译指的是数据库驱动在发送 SQL 语句和参数给 DBMS 之前对 SQL 语句进行编译,这样 DBMS 执行 SQL 时,就不需要重新编译。

2.为什么需要预编译
JDBC 中使用对象 PreparedStatement 来抽象预编译语句,使用预编译。预编译阶段可以优化 SQL 的执行。预编译之后的 SQL 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。同时预编译语句对象可以重复利用。把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的 PreparedState 对象。Mybatis默认情况下,将对所有的 SQL 进行预编译。

14.Mybatis都有哪些Executor执行器?它们之间的区别是什么?

  • SimpleExecutor是最简单的执行器,根据对应的sql直接执行即可,不会做一些额外的操作;
  • BatchExecutor执行器,顾名思义,通过批量操作来优化性能。通常需要注意的是批量更新操作,由于内部有缓存的实现,使用完成后记得调用flushStatements来清除缓存。
  • ReuseExecutor 可重用的执行器,重用的对象是Statement,也就是说该执行器会缓存同一个sql的Statement,省去Statement的重新创建,优化性能。内部的实现是通过一个HashMap来维护Statement对象的。由于当前Map只在该session中有效,所以使用完成后记得调用flushStatements来清除Map。

15.Mybatis中如何指定使用哪一种Executor执行器?

在Mybatis配置文件中,在设置(settings)可以指定默认的ExecutorType执行器类型,也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数,如SqlSession openSession(ExecutorType execType)。

配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。

16.Mybatis延迟加载

在实际使用中,我们会经常性的涉及到多表联合查询,但是有时候,并不会立即用到所有的查询结果,我来举两个例子:

  • 例如,查询一批笔记本电脑的进货明细,而不直接展示每列明细对应电脑配置或者价格等的详细信息,等到用户需要取出某笔记本相关的详细信息的时候,再进行单表查询
  • 再例如 ,银行中,某个用户拥有50个账户(打比方),再我们查询这个而用户的信息,这个用户下所有账户的详细信息很显然,在使用的时候再查询才是比较合理的

针对这样一种情况,延迟加载这一种机制就出现了,延迟加载(懒加载)顾名思义,就是对某种信息推迟加载,这样的技术也就帮助我们实现了 “按需查询” 的机制,在一对多,或者多对多的情况下

既然提到了延迟加载,当然顺便提一句立即加载,它的含义就是不管是否用户需要,一调用,则马上查询,这种方式,适合与多对一,或者一对一的情况下。

首先,配置基本的环境,然后我们首先在数据库准备两张表

User表

CREATE TABLE USER (
 `id`            INT(11)NOT NULL AUTO_INCREMENT,
 `username`     VARCHAR(32) NOT NULL COMMENT '用户名',
 `telephone`    VARCHAR(11) NOT NULL COMMENT '手机',
 `birthday`        DATETIME DEFAULT NULL COMMENT '生日',
 `gender`          CHAR(1) DEFAULT NULL COMMENT '性别',
 `address`         VARCHAR(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY  (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

Account表

CREATE TABLE `account` (
  `ID` int(11) NOT NULL COMMENT '编号',
  `UID` int(11) default NULL COMMENT '用户编号',
  `MONEY` double default NULL COMMENT '金额',
  PRIMARY KEY  (`ID`),
  KEY `FK_Reference_8` (`UID`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后分别创建出其对应的实体类

User类

public class User implements Serializable {
    private Integer id;
    private String username;
    private String telephone;
    private Date birthday;
    private String gender;
    private String address;
    //一对多关系映射,主表实体应该包含从表实体的集合引用
    private List<Account> accounts;
    ...... 请补充 get set 和 toString 方法
}

Account类

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //从表实体应该包含一个主表实体的对象引用
    private User user;
    ...... 请补充 get set 和 toString 方法
}

UserMapper.xml





    
    
        
        
        
        
        
        
        
            
            
            
        
    
    
    
    

    
    
    

两个接口中创建对应方法

public interface AccountMapper {
    /**
     * 查询所有账户
     * @return
     */
    List<Account> findAll();
}
public interface UserMapper {
    /**
     * 查询所有用户信息,同时显示出该用户下的所有账户
     *
     * @return
     */
    List<User> findAll();

    /**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);
}

延迟加载代码实现

首先,给大家演示一下,我们之前一对一查询用户的方式,同时会将用户对应所有的账户信息,也查询出来

/**
* 测试查询所有
*/
@Test
public void testFindAll() {
    List<User> users= userMapper.findAll();
    for (User user : users) {
        System.out.println("---------------------");
        System.out.println(user);
        System.out.println(user.getAccounts());
    }
}

效果:
我把问烂了的⭐MyBatis面试题⭐总结了一下(带答案,万字总结,精心打磨,建议收藏)_第1张图片

这种方式是通过 SQL 语句,以及resultMap将 用户和账户的信息同时查询出来

那么如何实现我们上面所说的延迟加载呢?

这次我们选择 查询账户,然后延迟加载用户的信息

修改AccountMapper.xml
首先需要修改的就是账户的映射配置文件,可以看到我们在查询时,依旧定义了一个 resultMap 先封装了 Account ,然后通过association 进行关联 User,其中使用的就是 select 和 column 实现了延迟加载用户信息

  • select 用来指定延迟加载所需要执行的 SQL 语句,也就是指定 某个SQL映射文件中的某个select标签对的 id,在这里我们指定了用户中通过id查询信息的方法
  • column 是指关联的用户信息查询的列,在这里也就是关联的用户的主键即,id
<mapper namespace="cn.ideal.mapper.AccountMapper">
    
    <resultMap id="userAccountMap" type="Account">
        <id property="id" column="id">id>
        <result property="uid" column="uid">result>
        <result property="money" column="money">result>
        
        <association property="user" column="uid" javaType="User" select="cn.ideal.mapper.UserMapper.findById">association>
    resultMap>

    
    <select id="findAll" resultMap="userAccountMap">
        SELECT * FROM account
    select>
mapper>

第一次测试代码
我们只执行一下账户的查询所有方法,看一下,是否能够实现我们的效果

@Test
public void testFindAll(){
    List<Account> accounts = accountMapper.findAll();
}

执行效果
我把问烂了的⭐MyBatis面试题⭐总结了一下(带答案,万字总结,精心打磨,建议收藏)_第2张图片
可以看到,三条 SQL 语句都执行了,这是为什么呢?

这是因为,我们在测试方法之前,需要开启延迟加载功能

延迟加载功能

经过查阅文档,我们知道了,如果想要开始延迟加载功能,就需要在总配置文件 SqlMapConfig.xml 中配置 setting 属性,也就是将延迟加载 lazyLoadingEnable 的开关设置成 teue ,由于是按需加载,所以还需要将积极加载修改为消极加载,也就是将 aggressiveLazyLoading 改为 false

当然,由于我这里导入的 MyBatis 版本为 3.4.5 所以这个值默认就是 false 实际上不用设置也可以,不过我们还是写出来

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
     <setting name="aggressiveLazyLoading" value="false">setting>
settings>

注意:如果有使用typeAliases配置别名的话一定要将 typeAliases 标签放在后面

再次测试

仍然只执行查询方法

@Test
public void testFindAll(){
    List<Account> accounts = accountMapper.findAll();
}

执行效果
在这里插入图片描述

这一次果然只执行了一条查询 account 的命令

那么当用户想要查看到,每个账户对应下的用户的时候呢?这也就是按需查询,只需要在测试时,加入对应获取方法就可以了

@Test
public void testFindAll(){
    List<Account> accounts = accountMapper.findAll();
    for (Account account : accounts){
        System.out.println("----------------------------");
        System.out.println(account);
        System.out.println(account.getUser());
    }
}

执行一下
我把问烂了的⭐MyBatis面试题⭐总结了一下(带答案,万字总结,精心打磨,建议收藏)_第3张图片
可以看到,我们延迟加载的目的达到了

17.#{}和${}的区别

#{} 是预编译处理,像传进来的数据会加个" "(#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号)

就 是 字 符 串 替 换 。 直 接 替 换 掉 占 位 符 。 {} 就是字符串替换。直接替换掉占位符。 方式一般用于传入数据库对象,例如传入表名.

使用 ${} 的话会导致 sql 注入。什么是 SQL 注入呢?比如 select * from user where id = ${value}

value 应该是一个数值吧。然后如果对方传过来的是 001 and name = tom。这样不就相当于多加了一个条件嘛?把SQL语句直接写进来了。如果是攻击性的语句呢?001;drop table user,直接把表给删了

所以为了防止 SQL 注入,能用 #{} 的不要去用 ${}

如果非要用 ${} 的话,那要注意防止 SQL 注入问题,可以手动判定传入的变量,进行过滤,一般 SQL 注入会输入很长的一条 SQL 语句

18.模糊查询like语句该怎么写

方式1:$ 这种方式,简单,但是无法防止SQL注入,所以不推荐使用

LIKE  '%${name}%'

方式2:#

LIKE "%"#{name}"%"

方式3:字符串拼接

AND name LIKE CONCAT(CONCAT('%',#{name},'%'))

方式4:bind标签


方式5:java代码里写
param.setUsername("%CD%"); 在 java 代码中传参的时候直接写上

 AND username LIKE #{username}

然后 mapper 里面直接写 #{} 就可以了

19.在mapper中如何传递多个参数

方法一:使用map接口传递参数
严格来说,map适用几乎所有场景,但是我们用得不多。原因有两个:首先,map是一个键值对应的集合,使用者要通过阅读它的键,才能明了其作用;其次,使用map不能限定其传递的数据类型,因此业务性质不强,可读性差,使用者要读懂代码才能知道需要传递什么参数给它,所以不推荐用这种方式传递多个参数。

public List findRolesByMap(Map parameterMap);

方法二:使用注解传递多个参数  
MyBatis为开发者提供了一个注解@Param(org.apache.ibatis.annotations.Param),可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性  这个时候需要修改映射文件的代码,此时并不需要给出parameterType属性,让MyBatis自动探索便可以了  使可读性大大提高,使用者也方便了,但是这会带来一个麻烦。如果SQL很复杂,拥有大于10个参数,那么接口方法的参数个数就多了,使用起来就很不容易,不过不必担心,MyBatis还提供传递Java Bean的形式。

public List findRolesByAnnotation(@Param("roleName") String rolename, @Param("note") String note);

方法三:通过Java Bean传递多个参数

public List findRolesByBean(RoleParams roleParam);

方法四:混合使用  
在某些情况下可能需要混合使用几种方法来传递参数。举个例子,查询一个角色,可以通过角色名称和备注进行查询,与此同时还需要支持分页

public List findByMix(@Param("params") RoleParams roleParams, @Param("page") PageParam PageParam);

20.Mybatis如何执行批量操作

Mybatis常会出现批量操作,如批量查询,批量插入,批量修改(replace into)。批量操作要比循环执行效率提升很多,这里对mybatis的批量操作做一个总结讲解。

(1)Foreach
foreach:foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。它是批量操作的核心标签,下面都是foreach在不同场景的应用和写法。

List

select id, accid, key1, key1createtime key1CreateTime, key2, key2createtime key2CreateTime
        from m_acc_keys where accid in

       #{item}

注意:你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list”作为键,而数组实例将会以“array”作为键。

List
这是一个批量保存(插入或修改)的例子


    replace into xx (id, c1,c2) values
    
        (#{it.id},#{it.c1},#{it.c2})
    

replace:会根据主键和唯一索引判断该记录是否存在,存在就删除在插入(修改),不存在就插入(insert)。

(2)数组
还是一个查询的例子

public List selectByIds(String[] ids); 

(3)多重循环
colids和proids是两个平级的数据。


	insert into b_column_programme(columnId, programmeId) 
	values 
      	
           
            (#{colid}, #{proid})
        
       

(4)批量插入id自增长
Mybatis在版本3.4.x以上支持批量插入绑定自增长id,常用版本3.4.1。

对应的maven支持


    org.mybatis
    mybatis
    3.4.1


    org.mybatis
    mybatis-spring
    1.3.1

Mapper.xml写法


    insert into xx
    (c1,c2)
    values
    
        (#{it.c1},#{it.c2})
    

21.如何获取生成的主键

MySQL:Mapper 文件 insert 语句设置

useGeneratedKeys="true" keyProperty="id"

Oracle:Mapper 文件 insert 语句增加


    select xxx_SEQ.nextval from dual

22.当实体类中的属性名和表中的字段名不一样 ,怎么办

第1种: 通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。


第2种: 通过来映射字段名和实体类属性名的一一对应的关系。




    
    

    
    
    

23.Mapper 编写有哪几种方式?

第一种:接口实现类继承 SqlSessionDaoSupport:使用此种方法需要编写mapper 接口,mapper 接口实现类、mapper.xml 文件。

(1)在 sqlMapConfig.xml 中配置 mapper.xml 的位置


    
    

(2)定义 mapper 接口

(3)实现类集成 SqlSessionDaoSupport

mapper 方法中可以 this.getSqlSession()进行数据增删改查。

(4)spring 配置


    

第二种:使用 org.mybatis.spring.mapper.MapperFactoryBean:

(1)在 sqlMapConfig.xml 中配置 mapper.xml 的位置,如果 mapper.xml 和mappre 接口的名称相同且在同一个目录,这里可以不用配置


    
    

(2)定义 mapper 接口:

(3)mapper.xml 中的 namespace 为 mapper 接口的地址

(4)mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致

(5)Spring 中定义


    
    


第三种:使用 mapper 扫描器:

(1)mapper.xml 文件编写:

mapper.xml 中的 namespace 为 mapper 接口的地址;

mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致;

如果将 mapper.xml 和 mapper 接口的名称保持一致则不用在 sqlMapConfig.xml中进行配置。

(2)定义 mapper 接口:

注意 mapper.xml 的文件名和 mapper 的接口名称保持一致,且放在同一个目录

(3)配置 mapper 扫描器:


    
    

(4)使用扫描器后从 spring 容器中获取 mapper 的实现对象。

24.MyBatis接口绑定的几种方式

接口绑定有两种方式

(1)使用注解,在接口的方法上面添加@Select@Update等注解,里面写上对应的SQL语句进行SQL语句的绑定。

(2)通过映射文件xml方式进行绑定,指定xml映射文件中的namespace对应的接口的全路径名

什么时候用注解绑定?什么时候用xml绑定?

当SQL语句比较简单的时候,使用注解绑定就可以了,当SQL语句比较复杂的话,使用xml方式绑定,一般用xml方式绑定比较多

25.使用MyBatis的mapper接口调用时有哪些要求?

  • Mapper接口方法名和mapper.xml中定义的每个sql的id相同。

  • Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。

  • Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。

  • Mapper.xml文件中的namespace即是mapper接口的类路径。

26.通常一个mapper.XML对应一个DAO接口,DAO是否可以重载?

答:不能重载,方法名对应的 mapper.xml 文件里的一个 id,这个与方法名对应,系统会根据 namespace+id 找到对应的方法对应。

Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值;接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法内的参数,就是传递给 sql 的参数。Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个标签,都会被解析为一个MapperStatement 对象。

举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到 namespace 为 com.mybatis3.mappers.StudentDao 下面 id 为findStudentById 的 MapperStatement。

Mapper 接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。

27.MyBatis不同映射文件中的id是否可以重复?

可以重复,但是需要映射文件的namespace不同

不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复。

原因就是 namespace+id 是作为 Map的 key使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。

有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。

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

答:Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。在Xml映射文件中,标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。每一个

具体流程:

1.当一个​ sqlseesion ​执行了一次​ select​ 后,在关闭此​ session​ 的时候,会将查询结果缓存到二级缓存

2.当另一个​ sqlsession ​执行​ select​ 时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能

注意:

1、如果 ​SqlSession​ 执行了 DML 操作​(insert、update、delete)​,并 ​commit​ 了,那么 ​mybatis​ 就会清空当前​ mapper​ 缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现差异

2、​ mybatis​ 的缓存是基于​ [namespace:sql语句:参数] ​来进行缓存的,意思就是,​SqlSession​ 的 ​HashMap​ 存储缓存数据时,是使用 ​[namespace:sql:参数] ​作为 ​key​ ,查询返回的语句作为 ​value​ 保存的。

你可能感兴趣的:(面试题专栏,mybatis,面试)