mybatis基础操作(三)

news2024/11/16 9:43:11

动态sql

通过动态sql实现多条件查询,这里以查询为例,实现动态sql的书写。

创建members表

创建表并插入数据:

create table members (
	member_id int (11),
	member_nick varchar (60),
	member_gender char (15),
	member_age int (11),
	member_city varchar (90)
); 
insert into members (member_id, member_nick, member_gender, member_age, member_city) values('1','reading','W','99','wuhan');
insert into members (member_id, member_nick, member_gender, member_age, member_city) values('2','running','W','32','changsha');
insert into members (member_id, member_nick, member_gender, member_age, member_city) values('3','talking','W','26','changsha');
insert into members (member_id, member_nick, member_gender, member_age, member_city) values('4','song','W','22','beijing');
insert into members (member_id, member_nick, member_gender, member_age, member_city) values('5','running','F','28','beijing');
commit;

创建对应的members类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Members implements Serializable {
    private int memberId;
    private String memberNick;
    private String memberGender;
    private int memberAge;
    private String memberCity;
}

创建对应的dao类

public interface MembersDao {
    public List<Members> queryMemberUsingWhere(HashMap<String, Object> parms);

    public List<Members> queryMemberUsingTrim(HashMap<String, Object> parms);

    public List<Members> queryMemberByCity(List<String> cities);

    public List<Members> queryMemberByNick(String keyword);

    public Members queryMemberById(int id);

    public int updateMember(@Param("id") int id, @Param("age") int age);
}

创建xml文件

编写MembersDao的map文件:

<?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.kingyal.dao.MembersDao">
    <!--    -->
<!--    <cache readOnly="true" size=""></cache>-->
    <resultMap id="MemberMapper" type="Members">
        <id column="member_id" property="memberId"></id>
        <result column="member_nick" property="memberNick"></result>
        <result column="member_gender" property="memberGender"></result>
        <result column="member_age" property="memberAge"></result>
        <result column="member_city" property="memberCity"></result>
    </resultMap>
    <select id="queryMemberUsingWhere" resultMap="MemberMapper">
        select member_id,member_nick,member_gender,member_age,member_city
        from members
        <!--where 自动识别and -->
        <where>
            <!--gender 为参数对象的属性或者是map中的key值 -->
            <if test="gender != null">
                and member_gender = #{gender}
            </if>
            <!-- &gt; 表示大于 -->
            <if test="minAge != null">
                and member_age &gt;= #{minAge}
            </if>
            <!-- &lt; 表示小于 -->
            <if test="maxAge != null">
                and member_age &lt;= #{maxAge}
            </if>
            <if test="city != null">
                and member_city = #{city}
            </if>
        </where>
    </select>

    <select id="queryMemberUsingTrim" resultMap="MemberMapper">
        select member_id,member_nick,member_gender,member_age,member_city
        from members
        <!--trim: 起补充作用
            prefix:sql增加前缀
            prefixOverrides:如果第一个条件中有and或者or,将会去除掉
            suffix: sql增加后缀
            -->
        <trim prefix="where" prefixOverrides="and | or" suffix="order by member_age">
            <!--gender 为参数对象的属性或者是map中的key值 -->
            <if test="gender != null">
                and member_gender = #{gender}
            </if>
            <!-- &gt; 表示大于 -->
            <if test="minAge != null">
                and member_age &gt;= #{minAge}
            </if>
            <!-- &lt; 表示小于 -->
            <if test="maxAge != null">
                and member_age &lt;= #{maxAge}
            </if>
            <if test="city != null">
                and member_city = #{city}
            </if>
        </trim>
    </select>

    <select id="queryMemberByCity" resultMap="MemberMapper">
        select member_id,member_nick,member_gender,member_age,member_city
        from members
        where member_city in
        <!--
        collection:指定集合的类型,这里的list实际上是com.java.util.List,在mybatis中做了映射
        item:值的别名,在配置中需要用到
        seperator:每个值之间的分隔符
        open:以(开头
        close:以)开头
        最终达到以下效果:
            (changsah, beijing1)
        -->
        <foreach collection="list" item="cityName" separator="," open="(" close=")">
            #{cityName}
        </foreach>
    </select>
    <!--
        ${key}:表示获取参数,先获取参数的值拼接到sql中,再编译sql,会有sql注入问题,写法:where member_nick like '%${keyword}%'
        #{key}:表示获取参数,先编译sql,再将获取到的参数值拼接到sql中,写法:where member_nick like CONCAT('%',#{keyword},'%')
      -->
    <select id="queryMemberByNick" resultMap="MemberMapper">
        select member_id,member_nick,member_gender,member_age,member_city
        from members
        where member_nick like CONCAT('%',#{keyword},'%')
    </select>
    <select id="queryMemberById" resultMap="MemberMapper" useCache="true">
        select member_id,member_nick,member_gender,member_age,member_city
        from members
         where member_id=#{id}
    </select>

    <update id="updateMember" flushCache="true">
        update members set member_age=#{age} where member_id=#{id};
    </update>
</mapper>

将类名与实体进行映射:

在这里插入图片描述

将membersDao的map文件添加到mybatis配置中:
在这里插入图片描述

编写demo

public class MembersDaoTest {

    @Test
    public void queryMemberUsingWhere() {
        HashMap<String, Object> params = new HashMap<String, Object>();
        params.put("gender", "W");
        params.put("minAge", 20);
        params.put("maxAge", 40);
        params.put("city", "changsha");

        MembersDao membersDao = MybatisUtil.getMapper(MembersDao.class);
        List<Members> membersList = membersDao.queryMemberUsingWhere(params);
        for (Members m : membersList) {
            System.out.println(m);
        }
    }

    @Test
    public void queryMemberUsingTrim() {
        HashMap<String, Object> params = new HashMap<String, Object>();
        params.put("gender", "W");
        params.put("minAge", 20);
        params.put("maxAge", 40);
        params.put("city", "changsha");

        MembersDao membersDao = MybatisUtil.getMapper(MembersDao.class);
        List<Members> membersList = membersDao.queryMemberUsingTrim(params);
        for (Members m : membersList) {
            System.out.println(m);
        }
    }

    @Test
    public void queryMemberByCity() {
        List<String> cities = new ArrayList<String>();
        cities.add("changsha");
        cities.add("beijing");
        MembersDao membersDao = MybatisUtil.getMapper(MembersDao.class);
        List<Members> membersList = membersDao.queryMemberByCity(cities);
        for (Members m : membersList) {
            System.out.println(m);
        }
    }

    @Test
    public void queryMemberByNick() {
        MembersDao membersDao = MybatisUtil.getMapper(MembersDao.class);
        List<Members> membersList = membersDao.queryMemberByNick("r");
        for (Members m : membersList) {
            System.out.println(m);
        }
    }
}

mybatis日志记录

常见的日志记录组件有log4j,log4j2等,mybatis内部采用log4j组件。通过日志,可以查看sql执行情况。如下是配置方式。

引入pom文件

在这里插入图片描述

在resource目录下创建log4j.properties文件

在这里插入图片描述

如下是配置内容:

# 输出debug信息到控制台
log4j.rootLogger=DEBUG,stdout
# 日志级别
log4j.logger.org.mybatis.example.BlogMapper=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 日志的打印格式 %t:线程名称 %5p:日志级别 %n:换行 %msg:打印内容 %n:换行
log4j.appender.stdout.layout.ConversionPattern=[%t] %5p - {%msg} %n

mybatis启动时打印日志

在这里插入图片描述

配置第三方数据库连接池

在进行数据库操作时,mybatis支持基于数据库连接池的方式。mybatis的配置中,有一个dataSource标签:
在这里插入图片描述

如果type标签的属性值为POOLED,表示使用mybatis内置的连接池管理;如果想使用第三方的数据库连接池,需要进行自定义配置。

druid连接池的配置方式

引入pom文件
在这里插入图片描述

mybatis缓存

mybatis使用缓存机制,优化查询性能。第一次查询到的数据会放置在缓存中,第二次查询时会优先到缓存中查询,如果缓存中没有,就会到数据库查询,在数据库中查到后,同时存储到缓存中。

一级缓存

为sqlsession对象建立的缓存,每个sqlsession有单独的缓存,无需手动开启,可直接使用,多个sqlsession无法共享。如果sqlsession关闭或者清空缓存,就会重新从数据库获取数据。如果第一次查询完成后,对查询出的对象做修改,第二次查询会直接使用缓存,查询出的结果为修改后的值。如果第一次查询后,使用这个个sqlsession执行了update操作,此操作在更新数据库的同时,也会更新缓存,第二次查询出的结果为修改后的值。demo如下:

public void queryMemberByNickToTestFirstCache() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    MembersDao membersDao = sqlSession.getMapper(MembersDao.class);
    List<Members> membersList1 = membersDao.queryMemberByNick("reading");
    System.out.println(membersList1);
    System.out.println("~~~~~~~~~~~~~~~不会查询数据库,直接从缓存获取数据~~~~~~~~~~~~");
    MembersDao membersDao2 = sqlSession.getMapper(MembersDao.class);
    List<Members> membersList2 = membersDao2.queryMemberByNick("reading");
    System.out.println(membersList2);
}

public void queryMemberByNickToTestFirstCacheCelaning() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    MembersDao membersDao = sqlSession.getMapper(MembersDao.class);
    List<Members> membersList1 = membersDao.queryMemberByNick("reading");
    System.out.println(membersList1);
    // 清理缓存
    sqlSession.clearCache();
    System.out.println("~~~~~~~~~~~~~~~缓存被清空,再次查询会访问数据库~~~~~~~~~~~~");
    MembersDao membersDao2 = sqlSession.getMapper(MembersDao.class);
    List<Members> membersList2 = membersDao2.queryMemberByNick("reading");
    System.out.println(membersList2);
}

    public void queryMemberByIdToTestFirstCacheChangingAge() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        MembersDao membersDao = sqlSession.getMapper(MembersDao.class);
        Members members1 = membersDao.queryMemberById(1);
        System.out.println(members1);
        members1.setMemberAge(60);
        System.out.println("~~~~~~~~~~~~~~~没有清理缓存,第二次查询时,age变成了60~~~~~~~~~~~~");
        MembersDao membersDao2 = sqlSession.getMapper(MembersDao.class);
        Members members2 = membersDao2.queryMemberById(1);
        System.out.println(members2);
    }

    public void updateMemberToTestFirstCacheChangingAge() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        MembersDao membersDao1 = sqlSession.getMapper(MembersDao.class);
        Members members1 = membersDao1.queryMemberById(1);
        System.out.println(members1);
        //  做了更新操作
        membersDao1.updateMember(1, 99);
        sqlSession.commit();
        System.out.println("~~~~~~~~~~~~~~~在第一次查询后,使用代码更新了数据库,缓存也会被同步更新,第二次查询为99~~~~~~~~~~~~");
        MembersDao membersDao2 = sqlSession.getMapper(MembersDao.class);
        Members members2 = membersDao2.queryMemberById(1);
        System.out.println(members2);
    }

二级缓存

​ 二级缓存也称为sqlSessionFactory级缓存,通过同一个factory对象获取的SqlSession可以共享二级缓存,在应用服务器中,SqlSessionFactory是单例的,因此,我们二级缓存可以实现全局共享。特性如下:

​ 1. 二级缓存默认没有开启,需要在mybatis的配置文件中的settgng标签开启。
在这里插入图片描述
​ 2. 并在需要使用二级缓存的mapper文件中配置cache标签,表示使用二级缓存。
在这里插入图片描述

​ eviction策略:
在这里插入图片描述
​ flushInterval:刷新间隔,设置的值是一个以毫秒为单位的合理时间量,默认不设置,此时缓存仅仅会在调用语句时刷新。
​ size:引用数目,表示缓存的大小,设置时要注意缓存对象的大小和此时的可用内存,默认是1024。
​ readOnly:属性可以设置为true或者false,true表示只读,只读的缓存会给所有调用者返回缓存对象的相同实例。因为他们不能被修改。false表示可读写,可读写的缓存会通过序列化返回缓存对象的拷贝,速度上会慢一些,但是更安全,默认是false。
​ 3. 二级缓存只能缓存实现序列化接口的对象。
实例:

public void queryMemberByIdToTestSecondCacheChangingAge() {
    SqlSessionFactory factory= MybatisUtil.getSqlSessionFactory();
    SqlSession sqlSession = factory.openSession();
    MembersDao membersDao = sqlSession.getMapper(MembersDao.class);
    Members members1 = membersDao.queryMemberById(1);
    System.out.println(members1);
    sqlSession.commit();
    System.out.println("~~~~~~~~~~~~~commit之后,就会将当前sqlsession的查询结果缓存到二级缓存~~~~~~~~~~~~~~");
    SqlSession sqlSession2 = factory.openSession();
    MembersDao membersDao2 = sqlSession2.getMapper(MembersDao.class);
    Members members2 = membersDao2.queryMemberById(1);
    System.out.println(members2);
}

也可以在查询时使用二级缓存:

​ 1. 使用“flushCache”表示做更新操作时刷新缓存:
在这里插入图片描述
2. 使用“useCache”表示做查询操作时使用缓存
在这里插入图片描述

延迟加载

如果在mybatis开启了延迟加载,在执行子查询时(至少查询两次及以上),默认只执行第一次查询,当用到子查询的查询结果时,才会触发子查询的执行;如果无需用到子查询结果,则子查询不会执行。延迟加载的作用是减少对数据库的访问。配置如下,在子查询语句中配置fetchType为“true”.

在这里插入图片描述

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

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

相关文章

【探索程序员职业赛道:挑战与机遇】

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

微信小程序(五十三)修改用户头像与昵称

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.外界面个人资料基本模块 2.资料修改界面同步问题实现&#xff08;细节挺多&#xff0c;考虑了后期转服务器端的方便之处&#xff09; 源码&#xff1a; app.json {"window": {},"usingCompone…

什么是5G边缘计算网关?

随着5G技术的飞速发展和普及&#xff0c;边缘计算作为5G时代的关键技术之一&#xff0c;正日益受到业界的关注。而5G边缘计算网关&#xff0c;作为连接5G网络和边缘计算节点的桥梁&#xff0c;扮演着至关重要的角色。HiWoo Box&#xff0c;作为一款卓越的5G边缘计算网关&#x…

【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &a…

使用Spring的AOP

使用Spring的AOP 一、AOP 的常用注解1.切面类Aspect2.Pointcut3.前置通知Before4.后置通知AfterReturning5.环绕通知Around6.异常通知AfterThrowing7.最终通知After8.切面顺序Order9.启用自动代理EnableAspectJAutoProxy 二、AOP注解方式开发三、AOP 全注解开发四、基于XML配置…

RDD算子介绍(二)

1. coalesce 用于缩减分区&#xff0c;减少分区个数&#xff0c;减少任务调度成本。 val rdd : RDD[Int] sc.makeRDD(List(1, 2, 3, 4), 4) val newRDD rdd.coalesce(2) newRDD.saveAsTextFile("output") 分区数可以减少&#xff0c;但是减少后的分区里的数据分布…

Keepalived+LVS构建高可用集群

目录 一、Keepalive基础介绍 1. Keepalive与VRRP 2. VRRP相关技术 3. 工作原理 4. 模块 5. 架构 6. 安装 7. Keepalived 相关文件 7.1 配置组成 7.2 全局配置 7.3 VRRP实例配置&#xff08;lvs调度器&#xff09; 7.4 虚拟服务器与真实服务器配置 二、Keepalived…

【数据库】软件测试之MySQL数据库面试总结

有表如下&#xff1a; Student 学生表 SC 成绩表 Course 课程表 Teacher 老师表 每个学生可以学习多门课程&#xff0c;每一个课程都有得分&#xff0c;每一门课程都有老师来教&#xff0c;一个老师可以教多个学生 1、查询姓‘朱’的学生名单 select * from Student whe…

010Editor汉化版+下载+注册码+模板bug

项目场景&#xff1a; 这天我想使用我的不知名的一个破解版本的010Edit来查看一个EXE程序&#xff0c;并想使用模板功能&#xff0c;但是发现没有该模板还无法下载最新模板 问题描述 010Edit联网后需要注册码&#xff1a; 010 Editor 激活码生成器 使用方法 参照教程使用0…

面试题:分布式锁用了 Redis 的什么数据结构

在使用 Redis 实现分布式锁时&#xff0c;通常使用 Redis 的字符串&#xff08;String&#xff09;。Redis 的字符串是最基本的数据类型&#xff0c;一个键对应一个值&#xff0c;它能够存储任何形式的字符串&#xff0c;包括二进制数据。字符串类型的值最多可以是 512MB。 Re…

浅谈Maven

Maven能为我们解决什么问题 1&#xff1a;添加第三方jar包 按照最原始的做法&#xff0c;我们是手动复制jar包到项目WEB-INF/lib下&#xff0c;每个项目都会有一份&#xff0c;造成大量重复文件。而Maven将jar包放在本地仓库中统一管理&#xff0c;需要jar包只需要用坐标的方式…

使用Canvas绘制一个自适应长度的折线图

要求x轴根据数据长度自适应 y轴根据数据最大值取长度值 <template><div ref"cvsContainer" class"cvs-container"><canvas ref"cvs" class"canvas"></canvas></div> </template><script set…

188基于matlab的AR模型参数估计

基于matlab的AR模型参数估计&#xff0c;burg法和ule-Walker法估计信号&#xff0c;并输出估计误差。程序已调通&#xff0c;可直接运行。 188 AR模型参数估计 burg法和ule-Walker法 (xiaohongshu.com)

离散数学例题——6.树和特殊图

树 树的证明 森林 同构树非同构树 生成树 有向树 二叉树遍历 哈夫曼树 特殊图 欧拉图&#xff08;一次边&#xff09; Fleury算法求欧拉回路 欧拉通路&#xff08;一笔画&#xff09; 哈密顿图&#xff08;一次点&#xff09; 哈密顿图的充分条件 哈密顿图必要条件 二部图 二部…

人工智能OCR领域安全应用措施

引言 编写目的 随着新一轮科技革命和产业变革的深入发展&#xff0c;5G、大数据、云计算、深度学习等新技术日益成为推动社会进步的核心动力。人工智能&#xff08;AI&#xff09;作为这些新技术的集大成者&#xff0c;正迅速成为新型基础设施建设的战略性支柱&#xff0c;其广…

【详识C语言】自定义类型之三:联合

本章重点 联合 联合类型的定义 联合的特点 联合大小的计算 联合&#xff08;共用体&#xff09; 联合类型的定义 联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员&#xff0c;特征是这些成员公用同一块空间&#xff08;所以联合也叫共用体&#xff09;…

AI 辅助研发趋势

引言 随着人工智能技术的持续发展与突破&#xff0c;AI辅助研发正成为科技界和工业界瞩目的焦点。从医药研发到汽车设计&#xff0c;从软件开发到材料科学&#xff0c;AI正逐渐渗透到研发的各个环节&#xff0c;变革着传统的研发模式。在这一背景下&#xff0c;AI辅助研发不仅…

Linux学习——锁

目录 ​编辑 一&#xff0c;锁的概念 二&#xff0c;锁的操作 1&#xff0c;锁类型 pthread_mutex_t 2&#xff0c;初始化锁 3&#xff0c;上锁 4&#xff0c;解锁 5&#xff0c;销毁锁 三&#xff0c;线程安全问题演示 四&#xff0c;锁的原理 五&#xff0c;死锁 …

每日OJ题_牛客HJ73 计算日期到天数转换(IO型OJ)

目录 牛客HJ73 计算日期到天数转换 解析代码 牛客HJ73 计算日期到天数转换 计算日期到天数转换_牛客题霸_牛客网 解析代码 #include <iostream> using namespace std; int main() {int year 0, month 0, day 0, sum 0;cin >> year >> month >>…

【SpringBoot框架篇】36.整合Tess4J搭建提供图片文字识别的Web服务

文章目录 简介文件下载引入依赖main函数中使用基于Springboot搭建OCR Web服务配置traineddata路径枚举用到的语种类型定义接口响应的json数据格式封装OCR服务引擎编写web提供服务的接口启动服务并且测试html demo扩展 项目配套代码 简介 Tess4J是一个基于Tesseract OCR引擎的J…