MyBatis常见面试题汇总

说一下MyBatis执行流程?

MyBatis是一款优秀的基于Java的持久层框架,它内部封装了JDBC,使开发者只需要关注SQL语句本身,而不需要花费精力去处理加载驱动、创建连接等的过程,MyBatis的执行流程如下:

  1. 加载配置文件:MyBatis的执行流程从加载配置文件开始。通常,MyBatis的配置文件是一个XML文件,其中包含了了数据源配置,SQL映射配置、连接池配置
  2. 构架SqlSessionFactory:在配置文件加载后,MyBatis使用配置信息来构建SqlSessionFactory,这是MyBatis的核心工厂类。SqlSessionFactory是线程安全的,它用于创建SqlSession对象
  3. 创建SqlSession:应用程序通过SqlSessionFactory床渐渐SqlSession对象。SqlSession代表依次数据库会话,它提供了执行SQL操作的方法。通常情况下,每个线程都应该由自己的SqlSession对象
  4. 执行SQL查询:在SqlSession种,开发人员可以执行SQL查询你,这可以通过两种方式实现:
    1. 使用注解加SQL:Mybatis提供了注解加执行SQL的实现方式,MyBatis会为Mapper接口生成实现类的代理对象,实际执行SQL查询
    2. 使用XML映射文件:开发人员可以在XML映射文件中定义SQL查询语句和映射关系。然后,通过SqlSession执行这些SQL擦汗寻,将结果有映射到Java对象上
  5. SQL解析和执行:MyBatis会解析SQL查询,执行查询操作,并获取查询结果
  6. 结果映射:MyBatis使用配置的结果映射规则,将查询结果映射到Java对象上。这包括将数据库列映射到Java对象的属性上,并处理关联关系
  7. 返回结果:查询结果被返回给应用程序,开发热恩于那可以对结果进行进一步处理、展示或之旧话
  8. 关闭SqlSession:完成数据库操作后,关闭SqlSession释放资源

${}#{}有什么区别?什么情况下一定要使用${}

${}和#{}都是MyBatis种用来代替参数的特殊标识,如下:

但是二者的区别二还是很大的,主要区别如下:

  1. 含义不同:${}是直接替换(运行时已经替换成具体的执行SQL了),而#{}是预处理(运行时只设置了占位符"?",之后通过声明器(statement)来替换占位符)
  2. 使用场景不同:普通参数使用#{},如果传递的是SQL命令(如desc还是asc)或者SQL关键字的时候,需要使用${},但是使用之前一定要做好安全验证
  3. 安全性不同:使用${}存在安全性问题,#{}不存在安全性问题

也就是说,为了防止安全问题,所以大部分场景都要使用 #{} 替换参数,但是如果传递的是 SQL 关键字,例如order by xxx asc/desc 时(传递 asc 后 desc),一定要使用 $,因为它需要在执行时就被替换成关键字,而不能使用占位符替代(占位符不用应用于 SQL 关键字,否则会报错)。

在传递 SOL 关键字时,一定要使用 ${},但使用前,一定要进行过滤和安全检査,以防止 SQL 注入。

什么是SQL注入?如何防止SQL注入?

SQL注入就是指应用程序对用户输入的数据的合法性没有判断或过滤不严,攻击者可以在应用程序中事先定义好查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,依次来实现欺骗数据库服务器执行非授权的热议操作,从而进一步得到相应的数据信息


也就是说所谓的 SQL 注入指的是,使用某个特殊的 SQL 语句,利用 SQL 的执行特性,绕过 SQL 的安全检查,查询到本不该查询到的结果

如以下代码:

<select id="doLogin" resultType="com.example.demo.model.User">
    select *from userinfo where username='${name}' and password='${pwd}
</select>

sql注入以下代码 :"'or 1='1",如下图所示:

从上述结果可以看出,以上程序在应用程序不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的敏感数据

如何防止SQL注入

预编译语句与参数化查询:使用 PreparedStatement 可以有效防止 SQL 注入,因为它允许你先定义 SQL 语句的结构,然后将变量作为参数传入,数据库驱动程序会自动处理这些参数的安全性,确保它们不会干扰 SQL 语句的结构,如下代码所示:

String sql ="SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt= connection.prepareStatement(sql);
pstmt.setString(1,userInputUsername);
pstmt.setstring(2,userInputPassword);
ResultSet rs=pstmt.executeQuery();

输入验证和过滤:对用户输入的信息进行验证和过滤,确保其符合预期的类型和格式 

说一下MyBaits中的二级缓存?

MyBatis二级缓存是用于提高MyBatis查询数据库的性能和减少访问数据库的机制。MyBatis的二级缓存总共由两个缓存机制:

  • 一级缓存:SqlSession级别的,MyBatis自带的缓存功能。并且无法关闭,因此当有两个SqlSession访问相同的SQL时,一级缓存也不会生效,也需要查询两次数据库。在一个service调用两个相同的mapper方法的时候,依然是查询两次,因为他会创建那两个SqlSession进行查询(为了提高查询性能)
  • 二级缓存:Mapper级别的,只要是同一个Mapper,无论是使用多少个SqlSession来操作,数据都是共享的。也就是说,一个sessionFactory下的多个session之间是共享缓存的,它的作用范围更大,生命周期更长,可以减少数据库的查询次数,提高系统性能。但是MyBatis二级缓存时默认关闭的需要手动开启

二级缓存默认是不开启的,手动开启MyBatis步骤如下:

  1. 在mapper.xml中添加<cache/>标签
  2. 在需要缓存的标签上添加usrCache="true"(新版本可以忽略,为了兼顾老版本,保留)

完整示例如下:

<?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.mybatis.demo.mapper.StudentMapper">
    <cache/>
    <select id="getStudentCount" resultType="Integer" usecache="true">
        select count(*)from student
    </select>
</mapper>

编写单元测试代码:

import org.junit.jupiter.api.Test;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.context.SpringBootTest;  
  
@SpringBootTest  
public class StudentMapperTest {  
    @Autowired  
    private StudentMapper studentMapper;  
  
    @Test  
    void testGetStudentCount() {  
        int count = studentMapper.getStudentCount();  
        System.out.println("查询结果:" + count);  
        int count2 = studentMapper.getStudentCount();  
        System.out.println("查询结果2:" + count2);  
    }  
}

运行结果:

从以上结果可以看出,两次查询虽然使用了不同的 SqlSession,但第二次查询使用了缓存,并未查询数据库 

ORM项目中类属性名和数据库字段名不一致会导致什么问题?它的解决方案有哪些?

在ORM项目中,如果类的属性名称和数据库字段名不一致会场导致插入、修改时设置的这个不一致字段为null,查询的时候即使数据库有数据,但是查询的结果也是为null。它的常见解决方法如下:

  1. 更改程序中属性名或数据库的字段名,使其一致
  2. 使用结果映射,使用<resultMap>映射对应的字段
    1. <!-- 在 XML 配置文件中定义 resultMap -->
      <resultMap id="userResultMap" type="com.example.User">
        <!-- 指定 id 字段映射 -->
        <id property="id" column="id"/>
        <!-- 指定 username 字段映射 -->
        <result property="username" column="username"/>
        <!-- 指定 email 字段映射 -->
        <result property="email" column="email"/>
      </resultMap>
      //在SQL映射文件中,可以使用这个<resultMap>来进行查询结果的映射:
      <select id="selectUser" resultMap="userResultMap">
        SELECT id, username, email
        FROM user
        WHERE id = #{id}
      </select>
      
  3. 使用MyBatis Plus框架中的@TableFild注解映射二者的字段,如下图:
  4. 如果是查询操作 ,可以使用as重命名字段名,这样查询也就不会为null了

MyBatis中如何实现分页?它有几种实现分页的方式?

MyBatis中实现分页主要是一下两种实现方式:

  • 物理分页:物理上是使用SQL擦哈寻语句,在数据库引擎层面实现的,如MySQL的LIMIT语法进行分页
  • 逻辑分页:逻辑分页时在应用程序层面进行的分页,通常是先查询出所有符合条件的数据,然后在内存中对数据进行分页操作

物理分页

使用limit实现分页

物理分页是可以直接在XML中拼加SQL进行分页:

<select id="getUserList"resultType="User">
    select *from user
    limit #{limit} offset #{offset}
</select>

使用PageHelper插件实现分页

实现代码如下:

PageHelper.startPage(1,10);
//1 表示要查询的页码为第一页,10 表示每页显示的记录数为 10 条
List<User>list=userMapper.selectIf(1);
 PageHelper实现原理分析

PageHelper底层是使用MyBatis的拦截器(Interceptor)机制,在MyBatis进行查询时,拦截并对SQL语句进行动态修改(添加limit等分页查询操作),之后查询数据库、并对查询结果进行包装,包装成分页对象(如包含数据列表、总记录数、总页数等信息的分页对象),最后再将这个分页对象返回给客户端

逻辑分页

MyBatis自带的RowBounds进行分页就是逻辑分页,它的一次性查询很多数据,然后在数据中在进行检索,实现代码如下:

RowBounds rowBounds = new RowBounds(offset, limit);
List<User> users = sqlSession.selectList("getUserList", null, rowBounds);

其中 offset 为起始行偏移量,limit 是每页数据量,虽然设置了这两个值,但在使用 RowBounds 时,它会一次性查询多条数据,然后再在内存中进行 offset 和 limit 的筛选,最后在返回符合结果的数据 

MyBaits二级缓存有几种淘汰策略?如何设置缓存淘汰策略?

  1. LRU-最近最少使用:移除最长时间不被使用的对象
  2. FIFO-先进先出:按照对象进入缓存的顺序来移除对象
  3. SOFT-软引用:基于垃圾回收器状态和软引用规则移除对象
  4. WEAK-弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象

默认的缓存淘汰策略时LRU

可以通过eviction属性来设置淘汰策略,如下:

<cache eviction="FIFO"/>

MyBatisPlus如何实现分页功能?它的底层是如何实现的?

MyBatis-Plus 是 MyBatis 的增强工具,在 MyBatis 的基础上提供了更多方便的功能,包括分页功能。在 MyBatis-Plus 中,实现分页功能非常简单,主要使用 Page 类进行分页操作。

以下是使用 MyBatis-Plus 实现分页功能的基本步骤:

  • 在 Mapper 接口中定义查询方法,并接收一个 Page 类型的参数,用于分页
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

public interface UserMapper extends BaseMapper<User> {
    Page<User> selectUserPage(Page<User> page);
}
  • 在 Mapper XML 文件中编写对应的 SQL 查询语句
<select id="selectUserPage" resultType="com.example.User">
    select * from user
</select>
  • 在 Service 层调用 Mapper 中定义的查询方法,并传入一个 Page 对象作为参数
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public Page<User> selectUserPage(int pageNum, int pageSize) {
        Page<User> page = new Page<>(pageNum, pageSize);
        return userMapper.selectUserPage(page);
    }
}

这样就完成了分页功能的实现。MyBatis-Plus会自动将查询结果封装到Page对象中,其中包含了分页的相关信息,比如当前页码、每页大小、总记录数等

MyBatis-Plus底层是通过拦截器实现分页的,它会在执行SQL语句前进行拦截,并根据传入的分页参数自动生成对应的分页SQL语句,然后执行分页查询。最后将查询结果封装到Page对象中返回给调用方。这样,开发人员不需要手动编写分页的SQL语句,简化了开发流程

MyBatis中使用了哪些设计模式?举例说明一下

  1. 工厂模式:工厂模式是Java中最常见的设计模式之一。工厂模式就是它提供一个工厂,当有客户需要调用的时候,只调用这个工厂类就可以得到自己想要的结果,从而无需关注某类的具体实现过程。工厂模式在MyBatis中典型的代表就是SqlSessionFactory。SqlSession是MyBatis中的重要而Java接口,可以通过该接口来执行SQL语句,获取映射器示例和管理事务,而SqlSessionFactory正在用来产生SqlSession对象的,所以它在MyBatis中是比较核心的接口
  2. 建造者模式:建造者模式就是将一个复杂对象的构建与它的表示分离,使得的同样的构建过程可以创建不同的表示。也就是说建造者可以通过多个模块一步一步实现对象的构建,相同的构建过程可以创建不同产品。建造者模式在MyBatis中典型代表就是SqlSessionFactoryBuilder。普通的对象都是通过new关键字直接创建的,但是如果创建对象需要构造参数很多,且不能保证每个参数都是正确的或者不能一次性得到构建所需的所有参数,那么就需要将构建逻辑从对象本身抽离出来,让对象只关注功能,把构建交给构建类,这样就可以简化对象的构建,也可以达到分布构建对象的目的
  3. 单例模式:单例模式是Java中最简单的设计模式之一,此模式保证某个类在运行期间,只有一个实例对外提供服务,而这类被称为单例类。单例模式在MyBatis中典型的代表就是ErrorContext。ErrorContext是线程级别的单例,每一个线程有一个此对象的单例,用于记录该现成的执行环境的错误信息
  4. 代理模式:代理模式是指给某个对象提供一个代理对象,并由代理对象控制原对象的调用。代理模式在MyBatis中典型的代表就是MapperProxyFactory。MapperProxyFactory的newInstance()方法就是生成一个具体的代理类来实现某个功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/367754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

车载测试Vector工具——基于DoIP的ECU/车辆的连接故障排除

车载测试Vector工具——基于DoIP的ECU/车辆的连接故障排除 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和…

计算huggingface模型占用硬盘空间的实战代码

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

景联文科技受邀出席全国信标委生物特征识别分委会二届五次全会

全国信息技术标准化技术委员会生物特征识别分技术委员会&#xff08;SAC/TC28/SC37&#xff0c;以下简称“分委会”&#xff09;二届五次全会于2024年1月30日在北京顺利召开&#xff0c;会议由分委员秘书长王文峰主持。 分委会由国家标准化管理委员会批准成立&#xff0c;主要负…

N 叉树的层序遍历

给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [1,null…

配置实例—VLAN间跨三层通信的交换机配置实例

一、组网需求 企业的不同用户拥有相同的业务&#xff0c;且位于不同的网段。现在相同业务的用户所属的VLAN不相同&#xff0c;需要实现不同VLAN中的用户相互通信。 如图1所示&#xff0c;User1和User2中拥有相同的业务&#xff0c;但是属于不同的VLAN且位于不同的网段。现需要…

【笔记】React Native实战练习(仿网易云游戏网页移动端)

/** * 如果系统看一遍RN相关官方文档&#xff0c;可能很快就忘记了。一味看文档也很枯燥无味&#xff0c; * 于是大概看了关键文档后&#xff0c;想着直接开发一个Demo出来&#xff0c;边学边写&#xff0c;对往后工作 * 开发衔接上能够更顺。这期间肯定会遇到各种各样的问题&a…

基于SpringBoot Vue学生成绩管理系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

分布式事务 笔记

为什么使用分布式事务 分布式环境下一个业务可能会涉及到多个模块之间的调用&#xff0c;为了保证操作的原子性&#xff0c;分布式事务是最好的解决方案。假设会员服务异常&#xff0c;这是已经完成锁库&#xff0c;锁库无法回滚。 本地事务 事务特性&#xff08;ACID&#…

计算机服务器中了DevicData勒索病毒如何解密,DevicData勒索病毒解密流程

网络数据安全一直是企业关心的主要话题&#xff0c;近期&#xff0c;云天数据恢复中心接到很多企业的求助&#xff0c;企业的计算机服务器遭到了DevicData勒索病毒攻击&#xff0c;导致企业计算机服务器瘫痪无法正常工作&#xff0c;严重影响了工作业务开展。经过云天数据恢复中…

debian12 解决 github 访问难的问题

可以在 /etc/hosts 文件中添加几个域名与IP对应关系&#xff0c;从而提高 github.com 的访问速度。 据搜索了解&#xff08;不太确定&#xff09;&#xff0c;可以添加这几个域名&#xff1a;github.com&#xff0c;github.global.ssl.fastly.net&#xff0c;github.global.fa…

计算机组成原理(0)冯诺依曼体系结构

文章目录 定义**主要特点&#xff1a;****缺陷&#xff1a;** 定义 冯诺依曼体系结构&#xff08;Von Neumann architecture&#xff09;&#xff0c;也称为普林斯顿体系结构&#xff08;Princeton architecture&#xff09;&#xff0c;是一种计算机架构理论&#xff0c;由匈…

在centos 7 中 安装 配置 并 远程连接 MySQL5.7

目录 安装MySQL 1.卸载CentOS7系统自带的mariadb 2.安装依赖库 3.上传MySQL并解压 4.安装MySQL 配置MySQL 1.修改登录密码 2.修改字符集 3.配置远程连接 前言&#xff1a; 安装MySQL版本&#xff1a;mysql-5.7.30-1.el7.x86_64.rpm-bundle 文件需求后台私信 以下7条为…

【C语言】数组的应用:扫雷游戏(包含扩展和标记功能)附完整源代码

这个代码还是比较长的&#xff0c;为了增加可读性&#xff0c;我们还是把他的功能分装到了test.c&#xff0c;game.c&#xff0c;game.h里面。 扫雷游戏的规则相信大家来阅读本文之前已经知晓了&#xff0c;如果点到雷就输了&#xff0c;如果不是雷&#xff0c;点到的格子会显…

红队渗透靶机:LORD OF THE ROOT: 1.0.1

目录 信息收集 1、arp 2、nmap 3、knock 4、nikto 目录探测 1、gobuster 2、dirsearch WEB sqlmap 爆库 爆表 爆列 爆字段 hydra爆破 ssh登录 提权 信息收集 内核提权 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface: eth0, ty…

十年饮冰难凉热血——HTX重塑巴别塔

明天将会是不同的世界&#xff0c;该由不同的人来塑造。 2024年1月18日&#xff0c;HTX DAO正式成立。 作为区块链生态系统中领先的去中心化自治组织&#xff0c;HTX DAO以创新的治理方式&#xff0c;专注于开放金融和去中心化的代币化经济。 HTX DAO是一个富有远见和包容性…

基于springboot企业客户信息反馈平台源码和论文

网络的广泛应用给生活带来了十分的便利。所以把企业客户信息反馈管理与现在网络相结合&#xff0c;利用java技术建设企业客户信息反馈平台&#xff0c;实现企业客户信息反馈的信息化。则对于进一步提高企业客户信息反馈管理发展&#xff0c;丰富企业客户信息反馈管理经验能起到…

问题:在下列选项中,下列哪种情况不属于生理排泄过程的是() #媒体#学习方法#经验分享

问题&#xff1a;在下列选项中&#xff0c;下列哪种情况不属于生理排泄过程的是&#xff08;&#xff09; A.CO2由呼吸系统排出 B.食物残渣由消化道排出 C.皮肤排出汗液 D.肾脏排出尿液 E.由消化道排出的胆色素 参考答案如图所示

Leetcode的AC指南 —— 栈与队列 :1047.删除字符串中的所有相邻重复项

摘要&#xff1a; **Leetcode的AC指南 —— 栈与队列 &#xff1a;1047.删除字符串中的所有相邻重复项 **。题目介绍&#xff1a;给出由小写字母组成的字符串 S&#xff0c;重复项删除操作会选择两个相邻且相同的字母&#xff0c;并删除它们。 在 S 上反复执行重复项删除操作&a…

高宇辰:打造“π”型人才 | 提升之路系列(七)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

抽象类(Java)、模板方法设计模式

一、概念 在Java中有abstract关键字&#xff0c;就是抽象的意思&#xff0c;可用来修饰类和成员方法。 用abstract来修饰类&#xff0c;那这个类就是抽象类&#xff1b;修饰方法&#xff0c;那这个方法就是抽象方法。 修饰符 abstract class 类名{修饰符 abstract 返回值类型…
最新文章