MyBatis学习总结

news2025/4/13 21:55:02

MyBatis分页如何实现

分页分为
逻辑分页:查询出所有的数据缓存到内存里面,在从内存中筛选出需要的数据进行分页
物理分页:直接用数据库语法进行分页limit
mybatis提供四种方法分页:

  1. 直接在sql语句中分页,传递分页参数
    select _column,_column from _table [where Clause] [limit N][offset M]
    select * : 返回所有记录
    limit N : 返回 N 条记录
    offset M : 跳过 M 条记录, 默认 M=0, 单独使用似乎不起作用
    limit N,M = limit M offset N , 从第 N+1 条记录开始, 返回 M 条记录
  2. MyBatis提供了RowBounds对象实现逻辑分页
 @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //RowBounds实现
        RowBounds rowBounds = new RowBounds(1,2);

        //通过java代码层面实现分页
        List<Map> userList = sqlSession.selectList("com.jin.mapper.UserMapper.getUserByRowBounds", null, rowBounds);
        for (Map map1 : userList) {
            System.out.println(map1);
        }

        sqlSession.close();
    }

但是:RowBounds是将所有符合条件的数据全都查询到内存中,然后在内存中对数据进行分页,数据量非常大时,造成内存OOM。
3.MyBatis拦截器interceptor实现分页,截获所执行方法的sql语句与参数,动态拼接sql分页语句

利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用StatementHandler对象的prepare方法,即调用invocation.proceed()

4.分页插件
例如pagehelper,物理分页,实际原理就是修改最后的执行sql,增加相应的分页内容,是基于拦截器实现的。
在这里插入图片描述

MyBatis二级缓存

  1. 功能 - 提高查询效率
  2. 工作流程-一级缓存-缺点-二级缓存
  3. 实现原理
    MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。默认定义了两级缓存,分别是一级缓存和二级缓存。
    默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。二级缓存需要手动开启和配置,他是基于namespace级别的缓存。为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存。
    一级缓存(本地缓存)
    sqlSession级别的缓存,一级缓存一直是开启的,它实质上就是sqlSession级别的一个Map。
    一级缓存失效:
    sqlSession不同。
    sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)。
    sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响),实际上,这个是因为每个增删改查都有标签flushCache,增删改默认为flushCache=“true”,即执行完后就清除一级缓存和二级缓存。
    sqlSession相同,手动清除了一级缓存(缓存清空,session.clearCache(),注意,该方法只清除当前session的一级缓存)。
    二级缓存(全局缓存)
    namespace级别的缓存,一个namespace对应一个二级缓存。
    工作机制
    一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中。
    如果会话关闭或提交,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存中的内容。
    注意:不同的namespace查出的数据会放在自己对应的缓存(map)中。
    效果:数据会从二级缓存中取出。查出的数据都会被默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中。

先查询二级缓存,再查询一级缓存,最后查询数据库。
在这里插入图片描述
原理:sqlSession的executor持有一个Local cache对象,当用户发起查询,会根据执行语句到缓存查找,如果命中,直接返回,否则查询数据库再写入缓存。二级缓存则是executor的基础上做了一个装饰CachingExecutor装饰器,查询时先通过CachingExecutor查询二级缓存。

{}和\${}的区别

mybatis会对这两个符号解析,实现动态sql。

#{}匹配的是一个占位符,相当于JDBC中的一个?,会对一些敏感的字符进行过滤,编译过后会对传递的值加上双引号,因此可以防止SQL注入问题。

\${}匹配的是真实传递的值,传递过后,会与sql语句进行字符串拼接。${}会与其他sql进行字符串拼接,不能预防sql注入问题。

#{}的应用场景是为给SQL语句的where字句传递条件值,${}的应用场景是为了传递一些需要参与SQL语句语法生成的值。

mybatis代理模式

在这里插入图片描述
mapper接口和mapper配置文件的目录要对应。

//mybatis代理开发
public class MyBatisDemo2 {
    public static void main(String[] args) throws IOException {
        //1. 加载mybatis的核心配置文件,获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,用来执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.执行sql namespace+id
        //List<Student> students = sqlSession.selectList("test.findAll");
        //3.1 获取StudentMapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        studentMapper.findAll();
        //System.out.println(students);
        //mybatis提供了mapper接口代理的开发方式,不需要再编写dao类,只需要编写一个mapper接口,一个mapper的接口和一个mapper.xml相对应,
        // 只需要调用SqlSession对象上的getMapper(),传入mapper接口的class信息,即可获得一个mapper代理对象,
        // 直接调用mapper接口中的方法,即相当于调用mapper.xml中的各个SQL标签,此时就不需要指定SQL标签的id字符串了,
        // mapper接口中的一个方法,就对应了mapper.xml中的一个SQL标签
        //4.释放资源
        sqlSession.close();
    }

mybatis动态数据源配置

Spring内置了一个AbstractRoutingDataSource,它可以把多个数据源配置成一个Map,然后,根据不同的key返回不同的数据源。因AbstractRoutingDataSource也是一个DataSource接口。应用程序可以先设置好key, 访问数据库的代码就可以从AbstractRoutingDataSource拿到对应的一个真实的数据源,从而访问指定的数据库。
源码中有一个核心的方法 setTargetDataSources(Map<Object, Object> targetDataSources) ,它需要一个Map,在方法注释中我们可以得知,这个Map存储的就是我们配置的多个数据源的键值对。我们整理一下这个类切换数据源的运作方式,这个类在连接数据库之前会执行determineCurrentLookupKey()方法,这个方法返回的数据将作为key去targetDataSources中查找相应的值,如果查找到相对应的DataSource,那么就使用此DataSource获取数据库连接它是一个abstract类,所以我们使用的话,推荐的方式是创建一个类来继承它并且实现它的determineCurrentLookupKey() 方法,这个方法介绍上面也进行了说明,就是通过这个方法进行数据源的切换。

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
    @Nullable
    private Map<Object, Object> targetDataSources;
    @Nullable
    private Object defaultTargetDataSource;
    private boolean lenientFallback = true;
    private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
	// 存放的数据对象的Map集合类
    @Nullable
    private Map<Object, DataSource> resolvedDataSources;
    @Nullable
    private DataSource resolvedDefaultDataSource;

    public AbstractRoutingDataSource() {
    }
    // 初始化设置数据源
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        this.targetDataSources = targetDataSources;
    }
	// ...
    protected DataSource determineTargetDataSource() {
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
		// 决策当前选择的数据源的Key
        Object lookupKey = this.determineCurrentLookupKey();
		// 当前选择的数据源
        DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
            dataSource = this.resolvedDefaultDataSource;
        }

        if (dataSource == null) {
            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
        } else {
            return dataSource;
        }
    }
	// 数据源Key的实现方法,由子类去实现
    @Nullable
    protected abstract Object determineCurrentLookupKey();
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多进程(1)

1> 使用多个进程实现文件拷贝 #include<myhead.h> int main(int argc, const char *argv[]) {pid_t pid;pidfork();int fdr;char buf;if((fdropen(argv[1],O_RDONLY))-1){perror("open error");return -1;}int lenlseek(fdr,0,SEEK_END)-lseek(fdr,0,SEEK_…

openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优

文章目录 openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优224.1 全局并发队列224.2 局部并发队列 openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优 数据库提供两种手段进行并发队…

掌握社区店选址技巧,提升商业成功率

对于想开实体店或创业的人来说&#xff0c;选址是决定商业成功的关键因素之一。本人在社区店开鲜奶吧5年时间&#xff0c;我将分享一些实用的社区店选址技巧&#xff0c;帮助你提升商业成功率。 1、人口密度和流量&#xff1a; 选择人口密集、流量大的社区&#xff0c;这样可以…

redis scan命令导致cpu飙升

一.背景 今天下午Redis的cpu占用突然异常升高&#xff0c;一度占用达到了90%&#xff0c;触发了钉钉告警&#xff0c;之后又回到正常水平&#xff0c;跟DBA沟通&#xff0c;他说主要是下面这个语句的问题 SCAN 0 MATCH fastUser:6136* COUNT 10000这个语句的执行时长很短&…

苍穹外卖学习-----2024/02/19

1.开发环境搭建 我的git截图我使用的datagrip 运行sql学习到jwt令牌一种新的配置方式&#xff0c;写配置文件学习到了build属性nginx解决跨域的问题2.导入接口的文档 结果如图所示 3.Swagger /*** 通过knife4j生成接口文档* return*/Beanpublic Docket docket() {ApiInfo api…

论文阅读——ONE-PEACE

ONE-PEACE: EXPLORING ONE GENERAL REPRESENTATION MODEL TOWARD UNLIMITED MODALITIES 适应不同模态并且支持多模态交互。 预训练任务不仅能提取单模态信息&#xff0c;还能模态间对齐。 预训练任务通用且直接&#xff0c;使得他们可以应用到不同模态。 各个模态独立编码&am…

阿里云服务器多少钱一台?61元一年您看行吗?

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

Python简单小案例之 筷手美女下载保存本地

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 知识点: 动态数据抓包 requests发送请求 开发环境: python 3.8 运行代码 解释器 pycharm 2022.3 辅助敲代码 编辑器 requests pip install requests &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&…

【C++】类与对象(构造函数、析构函数、拷贝构造函数、常引用)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 类的6个默认成员函数 构造函数 特性 析构函数 特性 析构的顺序 拷贝构造函数 特性 常引用 前言 &…

频谱仿真平台HTZ Communications为私有5G建设铺平道路

韩国的国家监管机构韩国通信委员会&#xff08;KCA&#xff09;计划在德思特频谱仿真平台HTZ Communications的支持下加快扩大无线电接入范围&#xff0c;提升全国电信服务的质量和效率。 韩国通信委员会&#xff08;KCA&#xff09;在韩国的监管环境中扮演着至关重要的角色&am…

Spring6学习技术|IoC+基于xml管理bean

学习材料 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09; IoC 控制反转。是一种设计思想。 1.获取bean对象的方法 通过id&#xff0c;通过class&#xff0c;和双重方式。 ApplicationContext context new Cla…

云呐智能运维硬件包括哪些?智能运维体系包括哪些?

智能运维体系时&#xff0c;能够详细了解该体系包含的各个组成部分。具体来说&#xff0c;我们应该知道智能运维体系中涉及的软件组件有哪些&#xff0c;以及这些组件是如何相互协作以实现高效运维的。此外&#xff0c;智能运维体系中使用的硬件设备感兴趣。列举了智能运维硬件…

测试工具之压测工具JMeter(一)

有时候我们接到的需求是秒杀或者抽奖类的功能开发&#xff0c;这时候可能会在某一时间点大量请求并发&#xff0c;我们手工自测很难发现一些高并发场景下的问题&#xff0c;这时候可以借助一些压测工具帮我们模拟出大量请求来测试我们的接口是否能满足业务要求。JMeter是Apache…

数据分析 — 招聘数据爬取和分析

目录 一、数据获取二、词云图语法1、jieba 分词2、词云图 一、数据获取 需求&#xff1a; 招聘数据获取地址&#xff1a;https://careers.tencent.com/home.html 获取字段&#xff1a;岗位的名称、岗位职责、发布时间 import pandas as pd # 导入 Pandas 库并使用别名 pd im…

深度学习——概念引入

深度学习 深度学习简介深度学习分类根据网络结构划分&#xff1a;循环神经网络卷积神经网络 根据学习方式划分&#xff1a;监督学习无监督学习半监督学习 根据应用领域划分&#xff1a;计算机视觉自然语言处理语音识别生物信息学 深度学习简介 深度学习&#xff08;Deep Learni…

什么是矩阵的秩?如何计算矩阵的秩?(done)

什么是矩阵的秩&#xff1f;https://search.bilibili.com/all?vt21986927&keyword%E4%BB%80%E4%B9%88%E6%98%AF%E7%9F%A9%E9%98%B5%E7%9A%84%E7%A7%A9%EF%BC%9F&from_sourcewebtop_search&spm_id_from333.1007&search_source5 矩阵本质上是线性方程组。但是方…

Rust可以解决的常见问题

文章目录 前言1. 悬垂指针&#xff08;Dangling Pointers&#xff09;修复悬垂指针问题 2. 缓冲区溢出&#xff08;Buffer Overflow&#xff09;那么是什么是缓冲区溢出&#xff1f;rust处理缓冲区溢出问题 3. 数据竞争&#xff08;Data Races&#xff09;4. 空指针&#xff08…

SICTF Round#3 Web方向 题解WP

100&#xff05;_upload 题目描述&#xff1a;小茂夫说&#xff1a;一直上传恶意文件尊嘟要生气了&#xff0c;世事莫固守&#xff0c;转变思路求突破 开题&#xff0c;注意有个文件包含 题目把后缀过滤死了&#xff0c;无法上传php后缀文件。文件内容些许过滤&#xff0c;短…

猫头虎分享已解决Bug || Python AI错误处理:IndexError

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

城市智慧驿站是什么?城市智慧驿站有哪些功能

城市智慧驿站作为一种创新性的社会配套设施&#xff0c;开始在多个城市落地使用&#xff0c;引起了社会的关注。 城市智慧驿站是什么&#xff1f;城市智慧驿站是在智慧城市的背景下&#xff0c;城市智慧驿站智慧公厕成为了一种创新性的社会配套建筑。作为景观式模块化建筑&…