MyBatis面试题(2022最新版)

MyBatis

1、MyBatis 是什么框架?

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2、MyBatis 和 ORM 的区别?

在这里插入图片描述在这里插入图片描述

3、MyBatis 为什么是半自动 ORM 映射?

Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具

4、MyBatis 框架的应用场景?

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

5、MyBatis 有哪些优点?

优点

1.与JDBC相比,减少了50%以上的代码量。
2.MyBatis是最简单的持久层框架,小巧并且简单易学。
3.提供映射标签,支持对象与数据库的ORM字段关系映射。
4.提供XML标签,支持编写动态SQL语句。

6、MyBatis 有哪些缺点?

缺点

1.SQL语句编写工作量较大,对开发人员有一定的SQL语句功底要求。
2.SQL语句依赖于数据库,不能随便更改。

7、MyBatis 和 Hibernate 的区别?

  1. hibernate是全自动,而mybatis是半自动
hibernate完全可以自动生成sql。而mybatis仅有基本的字段映射,仍然需要通过手写sql来实现和管理。
  1. hibernate数据库移植性远大于mybatis
hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,
而mybatis由于需要手写sql,移植性也会随之降低很多,成本很高。
  1. hibernate拥有完整的日志系统,mybatis则欠缺一些
hibernate日志系统非常健全,涉及广泛,而mybatis则除了基本记录功能外,功能薄弱很多。
  1. mybatis相比hibernate需要关心很多细节
hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为mybatis使用简单,
才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,
hibernate则正好与之相反。但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。
  1. sql直接优化上,mybatis要比hibernate方便很多
由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,
无法直接维护sql;总之写sql的灵活度上hibernate不及mybatis。

8、MyBatis 和 JPA 的区别?

首先,Spring Data JPA可以理解为 JPA 规范的再次封装抽象底层还是使用了 Hibernate 的 JPA 技术实现

JPA默认使用hibernate作为ORM实现,所以,一般使用Spring Data JPA即会使用hibernate。Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

所以,这里说 jap和mybatis的区别也就是 hibernate和mybatis的区别了。

9、MyBatis 有哪几种 SQL 编写形式?

三种

  1. 在mapper文件中配置SQL
  <?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">
    <mapper namespace="com.test.cis.dao.accounts.FinanceRefundApplyDao">
     
    	<select id="queryById" resultType="FinanceRefundApplyModel" parameterType="String">
    		select * from FINANCE_REFUND_APPLY where ID = #{id}
    	</select>
     
    </mapper>
  1. 注解式的SQL定义
public interface UserMapper {   
    @Select("select * from user ")
    List<User> AnnotationGetUserList();
}

如果想要的是动态SQL,那么就加上<script>

 public interface UserMapper {
        
   @Select("select * from user ")
        List<User> AnnotationGetUserList();
        
   @Select("<script>"
                + "select * from user "
                + "<if test='id!=null'>"
                + "where id=#{id}"
                + "</if>"
                + "</script>")
        List<User> AnnotationGetUserById(@Param("id")String id);
}

3.通过@SelectProvider来声明sql提供类

public interface UserMapper {
    @SelectProvider(type=SqlProvider.class,method="getUserById")
    List<User> AnnotationProviderGetUserById(String id);
}

public class SqlProvider {
    public String getUserById(String id) {
        String sql = "select * from user ";
        if (id!=null) {
            sql += "    where id="+id;
        }
        return sql;
    }
}

10、MyBatis 支持哪些传参数的方法?

方式一、顺序传递参数

mapper.java文件:

public User selectUser(String name, int deptId);

mapper.xml文件:

<select id="selectUser" resultType="com.wyj.entity.po.User">
	select * from user where userName = #{0} and deptId = #{1}
</select>

注意:里面的数字代表你传入参数的顺序,不是特别建议使用这种方法传递参数,特别是参数个数多的时候

方式二、注解@Param传递参数

mapper.java文件:

public User selectUser(@Param("userName") String name, int @Param("deptId") id);

mapper.xml文件:

<select id="selectUser" resultType="com.wyj.entity.po.User">
	select * from user where userName = #{userName} and deptId = #{deptId}
</select>

注意:在xml文件中就只能以在@Param注解中声明的参数名称获取参数

方式三、使用Map集合传递参数

mapper.java文件:

public User selectUser(Map<String, Object> params);

mapper.xml文件:

<select id="selectUser" parameterType="java.util.Map" resultType="com.wyj.entity.po.User">
	select * from user where userName = #{userName} and deptId = #{deptId}
</select>

方式四、使用JavaBean实体类传递参数

mapper.java文件:

public User selectUser(User user);

mapper.xml文件:

<select id="selectUser" parameterType="com.wyj.entity.po.User" resultType="com.wyj.entity.po.User">
	select * from user where userName = #{userName} and deptId = #{deptId}
</select>

11、MyBatis 的 $ 和 # 传参的区别?

区别一: #传过来的数据会自动加上引号,$则不会
区别二: ${} 容易被sql注入,#{} 安全,
安全问题怎么理解?

#{}:解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。#{} 相当于一个占位符,使用占位符,防止sql注入。
${}:取出的值会直接拼装在sql中,会有安全问题。

12、MyBatis 可以映射到枚举类吗?

Mybatis 可以映射枚举类。

可以,需要自定义对枚举类的类型转换器。例如写一个类为EnumTypeHandler继承BaseTypeHandler<枚举类型>,重写其中的方法,在getNullableResult方法中更具返回结果做响应的转换操作。

13、MyBatis 怎么封装动态 SQL?

映射方式

1、当列名和封装查询结果的类的属性名一一对应时

这时MyBatis 有自动映射功能,将查询的记录封装到resultType 指定的类的对象中去

<mapper namespace="com.hanT.dao.UserDao">
    <!--id对应接口中的方法名,resultType为返回结果的类型,要用类的全限定名-->
    <select id="getUserList" resultType="com.hanT.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

2、当列名和封装查询结果的类的属性名不对应时
使用resultMap 标签,在标签中配置属性名和列名的映射关系

<resultMap type="cn.com.mybatis.pojo.User" id="UserResult">
    <result property="username" column="name"/>
</resultMap>
<select id="findUserById" parameterType="java.lang.Long" resultMap="UserResult">
    select id,name,email from t_user where id=#{id}
</select>

14、Mybatis trim 标签有什么用?

1.<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>

prefix:在trim标签内sql语句加上前缀。

suffix:在trim标签内sql语句加上后缀。

suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=“,”,去除trim标签内sql语句多余的后缀","。

prefixOverrides:指定去除多余的前缀内容

2.下面是一个往购物车表中插入数据的mybatis语句

<insert id="insert" parameterType="com.tortuousroad.groupon.cart.entity.Cart">
        insert into cart
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                id,
            </if>
            <if test="userId != null">
                user_id,
            </if>
            <if test="dealId != null">
                deal_id,
            </if>
            <if test="dealSkuId != null">
                deal_sku_id,
            </if>
            <if test="count != null">
                count,
            </if>
            <if test="createTime != null">
                create_time,
            </if>
            <if test="updateTime != null">
                update_time,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">
                #{id,jdbcType=BIGINT},
            </if>
            <if test="userId != null">
                #{userId,jdbcType=BIGINT},
            </if>
            <if test="dealId != null">
                #{dealId,jdbcType=BIGINT},
            </if>
            <if test="dealSkuId != null">
                #{dealSkuId,jdbcType=BIGINT},
            </if>
            <if test="count != null">
                #{count,jdbcType=INTEGER},
            </if>
            <if test="createTime != null">
                #{createTime,jdbcType=TIMESTAMP},
            </if>
            <if test="updateTime != null">
                #{updateTime,jdbcType=TIMESTAMP},
            </if>
        </trim>
    </insert>

15、MyBatis 怎么实现分页?

1、使用SQL的LIMIT做分页,分页参数可以使用Mybatis提供的Page封装,传给Mapper。
然后使用LIMIT (page-1)*size,size方式查询数据

2、使用PageHelper插件实现

3、使用MybatisInterceptor拦截器实现

16、MyBatis 流式查询有什么用?

流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。

如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。

流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。

17、MyBatis 模糊查询 like 语句该怎么写?

(1)直接传参法

直接传参法,就是将要查询的关键字keyword,在代码中拼接好要查询的格式,如%keyword%,然后直接作为参数传入mapper.xml的映射文件中。

public void selectBykeyWord(String keyword) {     
	String id = "%" + keyword + "%";     
	String roleType = "%" + keyword + "%";     
	String roleName = "%" + keyword + "%";     
	userDao.selectBykeyWord(id,roleName,roleType); 
}
<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">    
	SELECT * FROM t_role WHERE role_name LIKE #{roleName}   
	 OR id LIKE #{id}    
	 OR role_type LIKE #{roleType}
</select>

注意:此方法可以完成模糊查询任务,但是不推荐,因为与Java代码耦合了,不利于维护和修改。

(2)mysql的CONCAT()函数

MySQL的CONCAT()函数用于将多个字符串连接成一个字符串,是最重要的mysql函数之一。用法:CONCAT(str1,str2,…)

<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity"> 
   SELECT * FROM t_role WHERE role_name LIKE CONCAT('%',#{keyword},'%')    
   OR id LIKE CONCAT('%',#{keyword},'%')    
   OR role_type LIKE CONCAT('%',#{keyword},'%')
</select>

注意:执行效果与上面的直接传参一样,但比直接传参法更好,因为与代码解耦了,但是此方法只针对mysql数据库所用,如果换成Oracle数据库则需要修改sql代码,因此此方法不通用,但可以使用。

(3)mybatis的bind元素

mybatis针对这种情况作出了调整,提供了一个bind元素,此元素可以跨越数据库限制,也就是说不管是mysql还是Oracle数据库都可以通用模糊查询。

dao层接口如下:

List<RoleEntity> selectBykeyWord(@Param("keyword") String keyword);

mapper文件如下:

<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">	
	<!--keyword就是传入的参数,bind相当于是一个参数,这个参数的值就是value拼接出来的值-->	   
	 <bind name="pattern" value="'%' + keyword + '%'" />     
	 SELECT * FROM t_role WHERE role_name LIKE #{pattern}    
	 OR id LIKE #{pattern}    OR role_type like #{pattern}
 </select>

18、MyBatis 配置文件中的 SQL id 是否能重复?

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

19、MyBatis 如何防止 SQL 注入?

1、使用#{}来设置参数

2、正则表达式过滤非法字符

20、MyBatis 如何获取自动生成的主键id?

1、XML配置文件

<insert id="insert" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
    insert into person(name,pswd) values(#{name},#{pswd})
</insert>

2、Mapper中的方法

int insert(Person person);

注意在调用这个方法时,返回的int值并不是主键,而是插入的记录数。主键id会被赋值到输入的person对象里,自动赋值给person对象的id属性。比如:

Person person = new Person("name","psw");
//num是插入的记录数
int num = PersonMapper.insert(person);
//person对象的id属性会变成自生成的id
int id = person.getId();

21、MyBatis 使用了哪些设计模式?

	Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、
	XMLStatementBuilder、  CacheBuilder;
	工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
	单例模式,例如ErrorContext和LogFactory;
	代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,
	用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
	组合模式,例如SqlNode和各个子类ChooseSqlNode等;
	模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
	适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;

22、MyBatis 中的缓存机制有啥用?

做服务器的进程内部缓存,提高查询效率,降低数据库访问频率。Mybatis有三种缓存,一级缓存、二级缓存、第三方缓存EhCache,一级缓存时默认开启的,作用域时SqlSession。二级缓存默认关闭需要在配置中使用enableCache="true"开启,二级缓存时namespace作用域的。第三方缓存需要引入额外Jar包,并且在配置中开启二级缓存开关,配置第三方缓存的核心类。

二级缓存是SqlSessionFactory的缓存。只要是同一个SqlSessionFactory创建的SqlSession就共享二级缓存的内容,并且可以操作二级缓存.

23、MyBatis 一级缓存和二级缓存的区别?

在这里插入图片描述
1、作用域不同:

​ 一级缓存的作用域是SqlSession级别的Map,二级缓存是namespace级别的,也叫全局缓存

2、默认配置不同

​ 一级缓存默认开启,二级缓存默认关闭,需要在mybatis.cfg.xml配置文件中开启

<settings>
   <setting name="cacheEnabled" value="true"/>
</settings

24、MyBatis-Plus 是什么框架?

Mybatis的增强框架,帮助开发人员更加简化开发。这些框架提供了大部分的简单SQL语句封装的API,提供了分页插件,简化了配置流程。不过只对单表有好的支持,多表关联查询支持差,一般需要手动编写多表的SQL,不过可以原生和增强一起使用。

25、mybatis延迟加载

延迟加载:就是在需要用到数据时才进行加载不需要用到数据时就不加载数据。延迟加载也称懒加载.

懒加载的配置

● 局部懒加载: 在association标签或者collection标签中,设置fetchType属性的值为lazy

<resultMap id="empAndDeptByStepResultMap" type="Emp">
	<id property="eid" column="eid"></id>
	<result property="empName" column="emp_name"></result>
	<result property="age" column="age"></result>
	<result property="sex" column="sex"></result>
	<result property="email" column="email"></result>
	<association property="dept"
				 select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
				 column="did"
				 fetchType="lazy"></association>
</resultMap>

● 全局懒加载: 在mybatis的核心配置文件中添加

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值