MyBatis —— 动态SQL和缓存

前言

        在上一篇文章中荔枝梳理了一些特殊的SQL查询和一对多、多对一的映射关系,而在这篇文章中荔枝将会梳理有关MyBatis动态SQL和MyBatis缓存的相关知识,同时也稍微了解了有关MyBatis中借助MAVEN中的插件管理来实现逆向工程。希望对需要的小伙伴有帮助哈哈哈~~~


文章目录

目录

一、动态SQL

1.1 if标签

1.2 where标签

1.3 trim标签 

1.4 choose、when、otherwise标签

1.5 foreach标签

1.5 sql标签

二、MyBatis的缓存

2.1 一级缓存

2.2 二级缓存

2.3 MyBatis缓存查询顺序

三、MyBatis的逆向工程(MBG)

总结


一、动态SQL

        Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的问题。在执行SQL查询时,只有属性值存在我们才能做相应的SQL语句的拼接,因此我们需要动态来拼装SQL语句。在JDBC中我们根据不同的条件拼接SQL语句时往往需要注意一些预留处理,而MyBatis的动态SQL特性就极大地简化了这一处理过程。

1.1 if标签

根据if标签中的test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.crj.mybatis.mapper.DynamicSQLMapper"><!--    List<Emp> getEmpByCondition(Emp emp);--><select id="getEmpByCondition" resultType="Emp">select * from t_emp where 1=1<if test="empName != null and empName != ''">and emp_name = #{empName}</if><if test="age != null and age != ''">and age = #{age}</if><if test="sex != null and sex != ''">and sex = #{sex}</if></select>
</mapper>

        这段实例demo中,我们需要在select语句中添加一个恒成立的条件1=1,这是为了防止SQL语句在某些属性不存在时出现的拼接错误。动态SQL的特性其实类似一种按需加载的过程,弹性拼接起SQL语句。if标签中的test属性其实就是if标签中的SQL语句段拼接的条件,满足这个条件才能拼接在原有的查询SQL语句中。

1.2 where标签

        where标签可以辅助我们动态生成SQL语句中的where关键字,当where后面有内容时,where标签会帮助我们自动生成where关键字,同时会去掉内容前多余的and和or关键字,此时就无需我们手动添加where关键字和恒成立的条件了;当where后面没有内容时,此时不会生成where关键字。

<!--    List<Emp> getEmpByCondition(Emp emp);--><select id="getEmpByCondition" resultType="Emp">select * from t_emp<where><if test="empName != null and empName != ''">and emp_name = #{empName}</if><if test="age != null and age != ''">and age = #{age}</if><if test="sex != null and sex != ''">and sex = #{sex}</if></where></select>

1.3 trim标签 

若标签中有内容时,属性功能正常;若标签没有内容时, trim不会有任何效果。

几个属性:

prefix:将trim标签中内容前面添加指定内容

suffix:将trim标签中内容后面添加指定内容

prefixOverrides:将trim标签中内容前面去掉指定内容

suffixOverrides:将trim标签中内容后面去掉指定内容

<!--    List<Emp> getEmpByCondition(Emp emp);--><select id="getEmpByCondition" resultType="Emp">select * from t_emp<trim prefix="where" suffixOverrides="and|or"><if test="empName != null and empName != ''">emp_name = #{empName} and</if><if test="age != null and age != ''">age = #{age} and</if><if test="sex != null and sex != ''">sex = #{sex}</if></trim></select>

1.4 choose、when、otherwise标签

choose和when标签组合起来相当于if...else if...else的结构,如果所有的when条件都不满足,则会执行otherwise中的条件。

<!--    List<Emp> getEmpByChoose(Emp emp);--><select id="getEmpByChoose" resultType="Emp">select * from t_emp<where><choose><when test="empName != null and empName != ''">emp_name = #{empName}</when><when test="age != null and age != ''">age = #{age}</when><when test="sex != null and sex != ''">sex = #{sex}</when><otherwise>did = 1</otherwise></choose></where></select>

1.5 foreach标签

foreach标签简单来说就是一个循环,可以被用来执行批量操作,foreach标签有五种属性:

  • collection:设置需要循环的数组或集合
  • item:循环出来的单个对象
  • sqparator:循环体之间的分隔符
  • open:循环的所有内容开头的内容
  • close:循环的所有内容结束的内容
<!--    int deleteMoreByArray(Integer[] eids);--><delete id="deleteMoreByArray">delete * from t_emp where eid in<foreach collection="eids" item="eid" separator="," open="(" close=")">#{eid}</foreach></delete>

1.5 sql标签

sql标签又成为SQL片段,它可以用来记录常用的sql执行语句。通过include标签来引用SQL片段。

    <sql id="emColumns">eid,emp_name,age,sex,email</sql><select id="getEmpByChoose" resultType="Emp">select <include refid="emColumns"></include> from t_emp      </select>

二、MyBatis的缓存

2.1 一级缓存

MyBatis的一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据就会从缓存中直接获取而不会从数据库中重新访问。一级缓存是默认开启的

一级缓存失效的四种情况:

  • 不同的SqlSession对应不同的一级缓存
  • 同一个SqlSession但是查询条件不同
  • 同一个SqlSessioni两次查询期间执行了任何一次增删改操作
  • 同一个SqlSession两次查询期间手动清空了缓存 

手动清空缓存:

sqlSession.clearCache();

2.2 二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSessioni查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

二级缓存开启的条件:

  1. 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
  2. 在映射文件中设置标签<cache />
  3. 二级缓存必须在SqlSession关闭或提交之后有效 sqlSession.close() | sqlSession.commit()
  4. 查询的数据所转换的实体类类型必须实现序列化的接口

实体类实现序列化接口

public class Emp implements Serializable 

二级缓存失效的情况:

两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。

二级缓存的相关配置

在二级缓存的开启条件中,我们发现<cache />标签是可以配置一些属性的,具体如下

eviction属性:缓存回收策略

  • LRU(Least Recently Used)-最近最少使用的:移除最长时间不被使用的对象。
  • FIFO(First in First out)-先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK-弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

默认的是LRU。

flushlnterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用增删改语句时刷新

size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是flse。

2.3 MyBatis缓存查询顺序

        首先先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。如果二级缓存没有命中,再查询一级缓存;如果一级缓存也没有命中,则查询数据库。注意在sqlSession关闭之后,一级缓存中的数据会写入二级缓存


三、MyBatis的逆向工程(MBG)

正向工程:先创建ava实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:

  • Java实体类
  • Mapper接口
  •  MapperB映射文件 

在使用逆向工程之前首先应该配置好项目依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.crj</groupId><artifactId>MyBatis_MBG</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><!--依赖MyBatis核心包--><dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!--junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.3</version></dependency><!--log4j日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies><!--控制Maven在构建过程中相关配置--><build><!--构建过程用到的插件--><plugins><!--具体插件--><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.0</version><!--插件的依赖--><dependencies><!--逆向工程的核心依赖--><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><!--数据库连接池c3p0--><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.8</version></dependency></dependencies></plugin></plugins></build>
</project>

逆向工程配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration><!--targetRuntime:执行生成的逆向工程的版本MyBatis3Simple:生成基本的CRUDMyBatis:生成带条件的CRUD--><!-- 是否去除自动生成的注释 true:是 : false:否 --><context id="DB2Tables" targetRuntime="MyBatis3Simple"><!-- 数据库连接 --><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/mybatis"userId="root"password="123456"></jdbcConnection><!--javaBean的生成策略生成model模型,对应的包路径,以及文件存放路径(targetProject),targetProject可以指定具体的路径也可以使用“MAVEN”来自动生成,这样生成的代码会在target/generatord-source目录下--><javaModelGenerator targetPackage="com.crj.mybatis.pojo" targetProject=".\src\main\java"><!--是否能够使用子包--><property name="enableSubPackages" value="true" /><!-- 从数据库返回的值被清理前后的空格  --><property name="trimStrings" value="true" /></javaModelGenerator><!--SQL映射文件的生成策略对应的mapper.xml文件--><sqlMapGenerator targetPackage="com.crj.mybatis.mapper" targetProject=".\src\main\resources"><property name="enableSubPackages" value="true" /></sqlMapGenerator><!-- 对应的Mapper接口类文件的生成策略 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.crj.mybatis.mapper" targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /></javaClientGenerator><!-- 逆向分析的表 --><table tableName="t_emp" domainObjectName="Emp"/><table tableName="t_dept" domainObjectName="Dept"/></context>
</generatorConfiguration>

测试类中我们这样来进行条件查询:

EmpExample example = new EmpExample();
//这里可以借助example.createCriteria().and开头的方法来设置查询条件
example.createCriteria().andEmpNameEqualTo("荔枝");
mapper.selectByExample(example);

总结

嘿哈!MyBatis的相关知识学习也就大致到这里啦,荔枝接下来会继续学习mall项目,希望九月份能遇见不一样的自己吧哈哈哈哈。最近看丙哥的文章嘿嘿,分享给大家一句话:习惯自律,享受孤独~~~

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

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

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

相关文章

BEVFusion复现 (Ubuntu RTX3090)

https://github.com/ADLab-AutoDrive/BEVFusion 1.环境安装 我的机器是RTX3090&#xff0c;CUDA11.1 1.创建虚拟环境 conda create -n bevfusion python3.8.3 2.安装PyTorch 和 torchvision pip install torch1.8.0cu111 torchvision0.9.0cu111 torchaudio0.8.0 -f https://…

maven学习总结

众所周知&#xff0c;maven的两大作用是项目构建和依赖管理&#xff0c;除此之外&#xff0c;基于多模块项目&#xff0c;maven常用的功能还有模块化管理。 项目构建 Maven是一个构建工具&#xff0c;可以根据项目中的配置文件&#xff08;pom.xml&#xff09;来自动执行项目…

2023年Java核心技术第十一篇(篇篇万字精讲)

目录 二十一 . Java并发包提供了哪些并发工具类 21.1 典型回答 21.1 .1 CountDownLatch 21.1 .2 CyclicBarrier 21.1 .2.1 例子&#xff1a; 21.1 .2.2 输出结果&#xff1a; 21.1.2.3 详细解释&#xff1a;屏障点 21.1.3 Semaphore 21.1.3.1 使用 Semaphore例子&#xff1…

ros::NodeHandle用途用法

在ROS(Robot Operating System)中,ros::NodeHandle 是一个核心类,用于与ROS系统进行交互。几乎所有的ROS节点功能,例如发布或订阅主题、调用或提供服务,都需要使用到 ros::NodeHandle。 用途: 与ROS系统交互:ros::NodeHandle 是节点与ROS计算图系统进行通讯的主要接口…

GCC和G++的区别

GCC和G是我们在学习C/C并且进行编译的过程中&#xff0c;必会的知识点&#xff0c;今天小雷雷针对这个聊几句&#xff0c;嗯哼哼~ &#x1f449;&#x1f449;&#x1f449;gcc和g都是C/C的编译器&#xff0c;但是它们之间存在一些区别 GCC和G的渊源 GCC&#xff08;GNU Comp…

【C语言进阶(10)】通讯录管理系统

文章目录 Ⅰ 系统功能介绍Ⅱ 系统前期准备⒈菜单功能⒉结构体设计⒊通讯录初始化 Ⅲ 系统功能实现⒈添加联系人⒉删除联系人⒊查找联系人⒋修改联系人⒌显示联系人⒍排序联系人⒎清空联系人 Ⅳ 完整代码展示⒈test.c⒉contact.h⒊contact.c Ⅰ 系统功能介绍 系统中需要实现的功…

matlab 计算点云协方差矩阵

目录 一、概述1、算法概述2、主要函数二、代码示例三、结果展示四、参数解析输入参数输出参数五、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述

java 可变参数

基本语法 可变参数的语法很简单&#xff0c;基本格式如下&#xff1a; 方法名(参数类型 ...)举例 public void printName(String... names) {int count names.length;for (int i 0; i < names.length; i) {System.out.println(names[i]);} }

气传导蓝牙耳机好不好?推荐几款不错的气传导耳机

​在众多的气传导耳机中&#xff0c;如何选择一款适合自己的气传导耳机呢&#xff1f;这需要考虑到自己的需求和预算&#xff0c;同时也需要了解不同品牌和型号的产品特点和优缺点。下面我来推荐几款非常不错的气传导耳机给大家参考&#xff0c;希望大家都能寻找到心仪那款。 …

【线性代数】矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇)

矩阵求导的本质与分子布局、分母布局的本质&#xff08;矩阵求导——本质篇&#xff09; 说在前面一. 函数与标量、向量、矩阵二. 矩阵求导的本质三. 矩阵求导结果的布局四. 分子布局、分母布局的本质五. 向量变元的实值标量函数 说在前面 我将严谨地说明矩阵求导的本质与分子布…

centos下配置SFTP且限制用户访问目录

一、SFTP使用场景 ftp是大多数网站的文件传输选择工具,但ftp并不是非常安全,并且在centos上搭建的vsftpd也非常的不稳定,偶尔会出现权限问题,例如500、或是账号密码不正确等等。 而SFTP是基于默认的22端口,是ssh内含的协议,只要启动了sshd就可以使用。 建议:更高的效率…

[ES]mac安装es、kibana、ik分词器

一、安装es和kibana 1、创建一个网络&#xff0c;网络内的框架(eskibana)互联 docker network create es-net 2、下载es和kibana docker pull elasticsearch:7.12.1 docker pull kibana:7.12.1 3、运行docker命令部署单点eskibana&#xff08;用来操作es&#xff09; doc…

leetcode分类刷题:字符串及单词翻转

1、本文此次总结的题型“leetcode分类刷题&#xff1a;字符串及单词翻转”较为简单&#xff0c;是双指针法在字符串及单词翻转类题型中的应用 2、如果单词翻转类题型加了O(1)空间复杂度的要求&#xff0c;算法思路会变得稍微复杂一点 344. 反转字符串 该题为字符串翻转的基础题…

ConsoleApplication17_2项目免杀(Fiber+VEH Hook Load)

加载方式FiberVEH Hook Load Fiber是纤程免杀&#xff0c;VEH是异常报错&#xff0c;hook使用detours来hook VirtualAlloc和sleep&#xff0c;通过异常报错调用实现主动hook 纤程Fiber的概念&#xff1a;纤程是比线程的更小的一个运行单位。可以把一个线程拆分成多个纤程&#…

InVEST模型+SolVES模型教程

详情点击公众号链接&#xff1a;基于当量因子法、InVEST、SolVES模型等多技术融合在生态系统服务功能社会价值评估中的应用及论文写作、拓展分析 前言 生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xf…

基于Ubuntu坏境下的Suricata坏境搭建

目录 Suricata环境安装 第一步、在 Ubuntu 端点安装 Suricata 1、加入Suricata源 2、更新安装包 3、下载SuricataSuricata 第二步、下载并提取新兴威胁 Suricata 规则集 1、在tmp文件夹下载 Suricata 规则集 如果发现未安装curl&#xff0c;使用apt安装即可&#xff1a…

打造高权重店铺的秘密,详解Shopee平台权重评估机制(测评补单)

很多虾皮卖家经常提到的"权重"是指商品或店铺在Shopee平台上的重要性程度。权重评估了商品或店铺是否符合用户需求&#xff0c;并且能否促进订单转化率&#xff0c;为平台带来收益。说白了权重就是给商品和店铺打分的机制&#xff0c;得分越高&#xff0c;权重越高&a…

简单shell脚本的编写

文章目录 简单使用shell脚本参数判断整数的比较运算符字符串的比较运算shell脚本流程控制shell脚本循环for循环批量添加用户批量ping IP地址检测同一局域网&#xff0c;多台主机存活情况检测同一局域网&#xff0c;多台主机存活情况多线程检测主机存活情况 while循环case选择语…

Python中处理Excel文件的常见问题与技巧

在数据分析和办公自动化领域&#xff0c;Excel是一种广泛使用的工具。本文将介绍如何利用Python来处理Excel文件时可能遇到的常见问题&#xff0c;并分享一些实用技巧。 1. 安装必要库 - 使用pip或conda安装openpyxl、pandas等第三方库&#xff1b; – 确保所选版本兼容性以及…

Java之SpringCloud Alibaba【五】【微服务 Sentinel整合openfeign进行降级】

一、Sentinel整合openfeign 1、复制一下order-openfeign项目&#xff08;创建order-openfeign-sentinel&#xff09; 然后在stock-nacos当中编写对应的接口 RequestMapping("/reduct2")public String reduct2(){int a 1/0;System.out.println("扣减库存"…