Mybatis之动态sql、缓存、分页、配置数据源

SQL动态查询

if标签

当传递某个DTO时,需要根据某个属性是否存在而动态增加条件时,就可以使用if标签

xml 复制代码
<select id="getUser" resultType="user">
    select id, name, age, sex from user where 1=1
    <if test="userDto.name != null and userDto.name !=''">
        AND name = #{userDto.name}
    </if>
    <if test="userDto.age != null">
         AND age = #{userDto.age}
    </if>
</select>

如果test中的条件判断通过,则会将if标签中的内容拼接到前面的sql语句中,否则就不做处理

!warning

if标签中的test检测语句和if标签中的sql语句中不能出现<符号表示小于

因为<符号在xml文件中代表的是标签的开始

如果是test中,可以使用!进行反转; 如果在if标签中的sql语句,需要使用CDATA标签进行包裹,比如

xml 复制代码
<if test="userDto.age != null and !userDto.age >20">
         <![CDATA[
                AND age <= #{userDto.age}
            ]]>
    </if>

where标签

类似于上一段代码,书写 where 1=1 这样的语句时不规范的,所以就可以使用where标签代替

xml 复制代码
<select id="getUser" resultType="user">
    select id, name, age, sex from user
    <where>
        <if test="userDto.name != null and userDto.name !=''">
            AND name = #{userDto.name}
        </if>
        <if test="userDto.age != null">
            AND age = #{userDto.age}
        </if>
    </where>
</select>

如果if中的条件成立,则sql语句将会是select id, name, age, sex from user where name =? and age = ?

如果都不成立,则时期类语句是select id, name, age, sex from user

使用where标签时,会自动将第一个条件的 AND 或者 OR 替换掉

sql标签

如果在多个查询中存在校相同的sql片段,则可以使用sql标签抽取出来

xml 复制代码
<sql id="columns" >
    id, name, age, sex
</sql>

<select id="getUser" resultType="user">
    select
    <include refid="columns"/>
    from user
</select>

在需要使用要这个sql片段的地方使用inclued标签进行引用

set标签

set标签使用在更新操作中,对应sql语句中的set

xml 复制代码
<update id="updateUser">
    update user
    <set>
        <if test="userDto.name != null and userDto.name !=''">
            name = #{userDto.name},
        </if>
        <if test="userDto.age != null">
            age = #{userDto.age},
        </if>
    </set>
</update>

set标签还具有省略sql语句嘴鸥一个后缀的功能,对应的sql为 update user set name = ?, age = ?

trim标签

Mybatis提供了trim标签来代替where和set标签

xml 复制代码
<select id="getUser" resultType="user">
    select id, name, age, sex from user
    <trim prefix="where" prefixOverrides="AND">
        <if test="userDto.name != null and userDto.name !=''">
            AND name = #{userDto.name}
        </if>
        <if test="userDto.age != null">
            AND age = #{userDto.age}
        </if>
    </trim>
</select>

trim 标签有四个属性 prefix(前缀) prefixOverrides(被替代的前缀) suffix(后缀) suffixOverrides(被替代的后缀)

比如上面的sql语句, 对应的是 select id, name, age, sex from user where name =? and age = ?

被替代的前缀是 AND,替换为了前缀 where,同理还可以用在set标签中替换最后一个逗号

foreach标签

循环标签通常用于插入、删除、更新和查询操作

xml 复制代码
<insert id="saveUser">
    insert into user(name, age)
    values
    <foreach collection="userList" item="user" separator=",">
        (#{user.name}, #{user.age})
    </foreach>
</insert>
<!------------------------------------------------------------------------------------>
<select id="getUsers" resultType="user">
    select * from user where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</select>

foreach提供了六个标签,分别是

  • collection(传入的集合/数组)
  • itme(集合/数组中的元素)
  • separator(元素之间的分割符)
  • open(开始符号)
  • close(结束符号)
  • index(元素下标,不经常使用)

第一句对应的sql是 insert into user(name, age) values(?,?),(?,?)...

第二局对应的sql是 select* from user where id in (?,?,?,?...)

Mybatis缓存

缓存就是存储在内存中的临时数据,将用户经常查询的数据放在缓存(内存)中,用户再次查询数据的时候就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,能够提高查询效率,解决了高并发系统的性能问题

优势:减少和数据库的交互次数,减少系统开销,提高系统效率

使用场景:经常查询并且不经常改变的数据

Mybatis提供了两级缓存:一级缓存和二级缓存

  • 一级缓存是Sqlsession级别的缓存(本地缓存),默认开启,同一个SqlSession执行同构查询的时候,结果放入一级缓存
  • 二级缓存是SqlSessionFactory级别的缓存,需要手动开启,同一个SqlSessionFactory构建的SqlSession执行同构查询,如果SqlSession关闭,查询结果保存在二级缓存中

全局缓存配置

xml 复制代码
<!-- config.xml -->
<settings>
    <!-- 开启二级缓存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>

Mapper中的配置

readOnly:只读

flushInterval:刷新时间,单位为毫秒

size:缓存的数据条目

eviction:缓存淘汰策略

​ LRU:最近最少使用回收,移除最长时间不被使用

​ FIFO:先进先出,按照缓存进入的顺序进行移除

​ SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象

​ WEAK:弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象

xml 复制代码
<cache flushInterval="300000" readOnly="true" size="10000" eviction="LRU"/>

标签中的设置

设置属性useCache="true"

xml 复制代码
<select id="getUsersInclude" resultMap="map2" useCache="true">
。。。。。
</select>

当开启二级缓存之后,在控制台可以看到Cache Hit Ratio [cn.cnmd.mapper.UserMapper]: 0.5,代表缓存命中率
缓存命中率 = 缓存中查询数 总查询数 缓存命中率 = \frac{缓存中查询数}{总查询数} 缓存命中率=总查询数缓存中查询数

分页插件Page-Helper

maven配置

xml 复制代码
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.1</version>
</dependency>

插件配置

xml 复制代码
<plugins>
    <plugin interceptor="com.github.pagehelper.PageHelper"/>
</plugins>

代码

java 复制代码
SqlSession session = MybatisUtil.getSession();

PersonMapper mapper = session.getMapper(PersonMapper.class);

PageHelper.startPage(1, 5);//这一步必须在调用方法之前进行

List<Person> person = mapper.getPerson();

PageInfo<Person> pageInfo = new PageInfo<>(person);//查询出的数据必须封装在PageInfo对象中

System.out.println("总条数:" + pageInfo.getTotal());
System.out.println("总页数:" + pageInfo.getPages());

pageInfo.getList().forEach(System.out::println);// 当前页数据展示

结果

复制代码
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1f59a598]
==>  Preparing: SELECT count(0) FROM rbac.simple_table
==> Parameters: 
<==    Columns: count(0)
<==        Row: 32
<==      Total: 1
==>  Preparing: SELECT * from rbac.simple_table LIMIT ?
==> Parameters: 5(Integer)
<==    Columns: id, name, age, gender
<==        Row: 1, 张三, 25, 男
<==        Row: 2, 李四, 30, 女
<==        Row: 3, 王五, 22, 男
<==        Row: 4, 赵六, 28, 女
<==        Row: 5, 孙七, 35, 男
<==      Total: 5
总条数:32
总页数:7
Person(id=1, name=张三, age=25, gender=男)
Person(id=2, name=李四, age=30, gender=女)
Person(id=3, name=王五, age=22, gender=男)
Person(id=4, name=赵六, age=28, gender=女)
Person(id=5, name=孙七, age=35, gender=男)

配置数据源 Druid

maven配置

xml 复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.20</version>
</dependency>

创建 DruidDataSourceFactory, 并继承 PooledDataSourceFactory,并替换数据源

java 复制代码
public class DruidDataSourceFactory extends PooledDataSourceFactory {
    public DruidDataSourceFactory() {
        this.dataSource = new DruidDataSource();//替换数据源
    }
}
xml 复制代码
<dataSource type="cn.cnmd.dataSource.DruidDataSourceFactory">
    <!--1.3配置连接池需要的参数-->
    <!--修改为druid数据源时,一定要把driver修改为 driverClassName才能生效-->
    <property name="driverClassName" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</dataSource>

控制台出现字样说明配置成功

七月 10, 2024 5:43:47 下午 com.alibaba.druid.pool.DruidDataSource info

信息: {dataSource-1} inited

Row: 3, 王五, 22, 男

<== Row: 4, 赵六, 28, 女

<== Row: 5, 孙七, 35, 男

<== Total: 5

总条数:32

总页数:7

Person(id=1, name=张三, age=25, gender=男)

Person(id=2, name=李四, age=30, gender=女)

Person(id=3, name=王五, age=22, gender=男)

Person(id=4, name=赵六, age=28, gender=女)

Person(id=5, name=孙七, age=35, gender=男)

复制代码
# 配置数据源 Druid

### maven配置

```xml
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.20</version>
</dependency>

创建 DruidDataSourceFactory, 并继承 PooledDataSourceFactory,并替换数据源

java 复制代码
public class DruidDataSourceFactory extends PooledDataSourceFactory {
    public DruidDataSourceFactory() {
        this.dataSource = new DruidDataSource();//替换数据源
    }
}
xml 复制代码
<dataSource type="cn.cnmd.dataSource.DruidDataSourceFactory">
    <!--1.3配置连接池需要的参数-->
    <!--修改为druid数据源时,一定要把driver修改为 driverClassName才能生效-->
    <property name="driverClassName" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</dataSource>

控制台出现字样说明配置成功

七月 10, 2024 5:43:47 下午 com.alibaba.druid.pool.DruidDataSource info

信息: {dataSource-1} inited

相关推荐
Chasing__Dreams26 分钟前
Redis--基础知识点--26--过期删除策略 与 淘汰策略
数据库·redis·缓存
源远流长jerry1 小时前
MySQL的缓存策略
数据库·mysql·缓存
芯眼1 小时前
STM32启动文件详解(重点)
java·开发语言·c++·stm32·单片机·mybatis
lqlj22334 小时前
Spark SQL 读取 CSV 文件,并将数据写入 MySQL 数据库
数据库·sql·spark
遗憾皆是温柔4 小时前
MyBatis—动态 SQL
java·数据库·ide·sql·mybatis
未来之窗软件服务5 小时前
Cacti 未经身份验证SQL注入漏洞
android·数据库·sql·服务器安全
hudawei9965 小时前
flutter缓存网络视频到本地,可离线观看
flutter·缓存·音视频
小哈里5 小时前
【pypi镜像源】使用devpi实现python镜像源代理(缓存加速,私有仓库,版本控制)
开发语言·python·缓存·镜像源·pypi
CircleMouse5 小时前
基于 RedisTemplate 的分页缓存设计
java·开发语言·后端·spring·缓存
_星辰大海乀6 小时前
表的设计、聚合函数
java·数据结构·数据库·sql·mysql·数据库开发