当前位置: 首页 > article >正文

Java面试题精选:MyBatis(一)

一、MyBatis的工作原理

MyBatis是一个ORM(对象关系映射)框架,用于实现面向对象编程语言中不同类型系统的数据之间的转换。

MyBatis的源码结构
image.png
MyBatis的原理

  • MyBatis框架的初始化操作
  • 处理SQL请求的流程

  系统启动的时候会加载解析全局配置文件和对应映射文件。加载解析的相关信息存储在 Configuration 对象

@Test
    public void test1() throws  Exception{
        // 1.获取配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        // 2.加载解析配置文件并获取SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.根据SqlSessionFactory对象获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        // 4.通过SqlSession中提供的 API方法来操作数据库
        List<User> list = sqlSession.selectList("com.boge.mapper.UserMapper.selectUserList");
        // 获取接口的代码对象  得到的其实是 通过JDBC代理模式获取的一个代理对象
       // UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //List<User> list = mapper.selectUserList();
        System.out.println("list.size() = " + list.size());
        // 5.关闭会话
        sqlSession.close(); // 关闭session  清空一级缓存

    }

MyBatis的主要工作流程图
image.png

  • SqlSessionFactoryBuiler:是用来构建SqlSessionFactory的,而SqlSessionFactory只需要一个,所以只要构建了这一个SqlSessionFactory,它的使命就完成了,也就没有存在的意义了。所以它的生命周期只存在于方法的局部。
  • SqlSessionFactory:是用来创建SqlSession的,每次应用程序访问数据库,都需要创建一个会话。因为我们一直有创建会话的需要,所以SqlSessionFactory应该存在于应用的整个生命周期中(作用域是应用作用域)。创建SqlSession只需要一个实例来做这件事就行了,否则会产生很多的混乱,和浪费资源。所以我们要采用单例模式
  • SqlSession:是一个会话,因为它不是线程安全的,不能在线程间共享。所以我们在请求开始的时候创建一个SqlSession对象,在请求结束或者说方法执行完毕的时候要及时关闭它(一次请求或者操作中)。

二、介绍下MyBatis中的缓存设计

  1. 首先了解缓存的作用:
      减低数据源的访问频率,从而提高数据源的处理能力,或提高服务器的响应速度。
  2. MyBatis中的缓存设计:
    结构设计:装饰器模式
    缓存级别:先二级缓存再一级缓存

为什么会先走二级缓存再走一级缓存?
二级缓存的作用域是SqlSessionFactory级别,90%找到
一级缓存是SqlSession级别,5%找到

三、聊下MyBatis中如何实现缓存的扩展

首先可以回答下MyBatis中的缓存机构
其次回答MyBatis缓存的扩展

  • 创建Cache接口的实现。重写getObject和putObject方法
  • 如何让自定义的缓存实现:在cache标签中通过type属性关联我们自定义的Cache接口的实现
import org.apache.ibatis.cache.Cache;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
 
public class CustomCache implements Cache {
    private final String id;
    private final ConcurrentMap<Object, Object> cache = new ConcurrentHashMap<>();
 
    public CustomCache(String id) {
        this.id = id;
    }
 
    @Override
    public String getId() {
        return id;
    }
 
    @Override
    public void putObject(Object key, Object value) {
        cache.put(key, value);
    }
 
    @Override
    public Object getObject(Object key) {
        return cache.get(key);
    }
 
    @Override
    public Object removeObject(Object key) {
        return cache.remove(key);
    }
 
    @Override
    public void clear() {
        cache.clear();
    }
 
    @Override
    public int getSize() {
        return cache.size();
    }
 
    // 其他必要的方法可以根据需要实现
}

要使用自定义缓存,需要在MyBatis的配置文件中注册缓存类型,并指定要使用的自定义缓存实现:

<cache type="com.example.CustomCache"/>

或者在Mapper文件中使用元素来为特定的Mapper启用缓存:

<cache type="com.example.CustomCache"/>

在Mapper接口或者语句中使用该缓存:

<select ... useCache="true">
  <!-- 查询语句 -->
</select>

这样就通过实现Cache接口并在配置中指定,为MyBatis引入了自定义的缓存机制。

四、MyBatis中涉及到的设计模式

(1)建造者模式

  • 在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder会调用 XMLConfigBuilder读取所有的 MybatisMapConfig.xml和所有的 *Mapper.xml文件,构建Mybatis运行的核心对象 Configuration对象,然后将该 Configuration对象作为参数构建一个 SqlSessionFactory对象。

(2)工厂模式

  • 在Mybatis中比如 SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂模式。
    image.png
  • SqlSession可以认为是一个Mybatis工作的核心的接口,通过这个接口可以执行执行SQL语句、获取Mappers、管理事务。类似于连接MySQL的 Connection对象。

(3)单例模式
在Mybatis中有两个地方用到单例模式,ErrorContextLogFactory,其中 ErrorContext是用在每个线程范围内的单例,用于记录该线程的执行环境错误信息,而 LogFactory则是提供给整个Mybatis使用的日志工厂,用于获得针对项目配置好的日志对象。

public class ErrorContext {private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();​​    
	private ErrorContext() {  
	}public static ErrorContext instance() {        
		ErrorContext context = LOCAL.get();       
		if (context == null) {            
			context = new ErrorContext();            
			LOCAL.set(context);        
		}        
	return context;    
	}}

(4)代理模式

  • 代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写 Mapper.java接口,不需要实现,由Mybatis后台帮我们完成具体SQL的执行。

(5)适配器模式
在Mybatsi的logging包中,有一个Log接口,该接口定义了Mybatis直接使用的日志方法,而Log接口具体由谁来实现呢?Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配。
image.png

五、谈谈你对SqlSessionFactory的理解

SqlSessionFactory是MyBatis中非常核心的一个API。
目的是创建SqlSession对象。
SqlSessionFactory应该是单例。
SqlSessionFactory对象的创建是通过SqlSessionFactoryBuilder来实现。
在SqlSessionFactoryBuilder即完成了SqlSessionFactory对象的创建。也完成了全局配置文件和相关的映射文件的加载和解析操作。相关的加载解析的信息会被保存在Configuration对象中。

而且涉及到了两种涉及模式:工厂模式(SqlSessionFactory),建造者模式(SqlSessionFactoryBuilder)

六、谈谈你对SqlSession的理解

SqlSession是MyBatis中非常核心的一个API:通过这个接口可以执行执行SQL语句、获取Mappers、管理事务。类似于连接MySQL的 Connection对象。

SqlSession对象的获取需要通过SqlSessionFactory来实现。是一个会话级别的。当一个新的会话到来的时候。我们需要新建一个SqlSession对象来处理。当一个会话结束后我们需要关闭相关的会话资源。

处理请求的方式:

  1. 通过相关的增删改查的API直接处理
  2. 可以通过getMapper(xxx.class) 来获取相关的mapper接口的代理对象来处理

七、谈谈你对MyBatis的理解

MyBatis应该是我们在工作中使用频率最高的一个ORM框架。持久层框架

  1. 提供非常方便的API来实现增删改查操作
  2. 支持灵活的缓存处理方案,一级缓存、二级缓存,三级缓存
  3. 还支持相关的延迟数据加载的处理
  4. 还提供了非常多的灵活标签来实现复杂的业务处理,if forech where trim set bind …
  5. 相比于Hibernate会更加的灵活

八、谈谈MyBatis中的分页原理

SQL语句中的分页查询:
(1)MySQL:limit
(2)Oracle:rowid

在MyBatis中实现分页有两种实现

  1. 逻辑分页:RowBounds
      ○ 原理:执行完整的SQL查询,将结果集全部加载到内存中,然后根据RowBounds指定的偏移量offset和限制数limit进行分页处理。
      ○ 优点:减少IO次数,对于频繁访问且数据量较小的情况较为适合。
      ○ 缺点:当数据量非常大时,容易造成内存溢出,性能下降。
int offset = 10; // 偏移量
int limit = 5; // 每页数据条数
RowBounds rowBounds = new RowBounds(offset, limit);
List<User> userList = sqlSession.selectList("getUsers", null, rowBounds);
  1. 逻辑分页:基于插件的分页(PageHelper )
      ○ 原理:MyBatis提供了插件机制,通过自定义插件来拦截SQL语句的执行,并在查询结果返回之前添加分页逻辑。
      ○ 优点:插件封装了分页的具体实现细节,使用起来简单方便,适用于多种分页需求。
      ○ 缺点:可能需要一定的开发成本来编写和维护插件。
// Java代码中使用 PageHelper
PageHelper.startPage(1, 10);
List<User> userList = userMapper.getUsers();
PageInfo<User> pageInfo = new PageInfo<>(userList);
  1. 基于MyBatis-Plus实现分页
    MyBatis-Plus提供了分页插件,可实现简单易用的分页功能,可以根据传入的分页参数自动计算出分页信息,无需手动编写分页SQL语句。
public interface UserMapper extends BaseMapper<User> {
    List<User> selectUserPage(@Param("page") Page<User> page, @Param("name") String name);
}

九、Spring中是如何解决DefaultSqlSession的数据安全问题的

DefaultSqlSession是线程非安全的。也就意味着我们不能够把DefaultSqlSession声明在成员变量中。

在Spring中提供了一个SqlSessionTemplate来实现SqlSession的相关的定义。
然后在SqlSessionTemplate中的每个方法都通过SqlSessionProxy来操作。这个是一个动态代理对象。然后在动态代理对象中通过方法级别的DefaultSqlSession来实现相关的数据库的操作

十、谈谈你对MyBatis中的延迟加载的理解

延迟加载:等一会加载。
在多表关联查询操作的时候可以使用到的一种方案。
如果是单表操作就完全没有延迟加载的概念。

MyBatis的懒加载是指在需要数据时才进行数据加载,而不是在加载实体对象时就立即加载其关联的所有数据。这样可以提高数据加载的效率,因为只有当确实需要时才会进行数据加载。

  1. 需要开启延迟加载

image.png

  1. 需要配置多表关联
  • association 一对一的关联配置
  • collection 一对多的关联配置

在MyBatis中,可以通过配置或标签的lazy属性来控制是否懒加载。当lazy属性设置为true时,表示启用懒加载。


<mapper namespace="com.example.mapper.UserMapper">
    <!-- 配置懒加载的关联查询 -->
    <collection property="orders" ofType="com.example.entity.Order" 
                column="user_id" select="selectOrdersByUserId" lazy="true"/>
</mapper>
  1. 需要全局配置

全局懒加载设置:在mybatis-config.xml配置文件中,可以通过标签的lazyLoadingEnabled属性全局设置懒加载。


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

延迟加载的原理:代理对象


http://www.kler.cn/a/450742.html

相关文章:

  • 【C++】B2066救援题目分析和解决讲解
  • 搭建Elastic search群集
  • 《智启新材:人工智能重塑分子结构设计蓝图》
  • 第十四章 C++ 数字
  • amazon广告授权
  • 申请腾讯混元的API Key并且使用LobeChat调用混元AI
  • 使用RKNN进行YOLOv8人体姿态估计的实战教程:yolov8-pose.onnx转yolov8-pose.rknn+推理全流程
  • Excel生成DBC脚本源文件
  • 分布式 IO 模块:赋能造纸业,革新高速纸机主传动
  • 【MFC】如何修改多文档视图的标签
  • 深入解析Android Recovery系统
  • 代写软件标书哪里找:如何让标书撰写变得高效轻松
  • 自动驾驶---Parking端到端架构
  • 在 .NET Core 中使用 ActionBlock 实现高效率的多步骤数据处理
  • 阿里云ESC服务器一次性全部迁移到另一个ESC
  • 以“技”出圈,珈和科技农业典型案例 “盛放”2024湖北农博会
  • 问题小记-达梦数据库报错“字符串转换出错”处理
  • 深入理解C++23的Deducing this特性(上):基础概念与语法详解
  • curl 放弃对 Hyper Rust HTTP 后端的支持
  • 《Opencv》基础操作详解(3)
  • 全国硕士研究生入学考试(考研)考研时间线之大四
  • 24.12.25 AOP
  • CASA模型相关遥感数据及MODIS NDVI、FPAR遥感产品数据时序重建
  • SpringBoot3——Web开发
  • 软件测试之压力测试【详解】
  • 安卓修改进程数 termux报错signal 9 vmos