mybatis基础操作(三)

动态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”.

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视图【MySQL】

文章目录 概念操作视图创建视图查询视图更新视图删除视图 视图规则和限制 概念 MySQL 中的视图&#xff08;View&#xff09;是一个虚拟表&#xff0c;其内容由查询定义。视图本身不包含数据&#xff0c;这些数据是从一个或多个实际表中派生出来的&#xff0c;通过执行视图定义…

简单了解TCP/IP四层模型

什么是计算机网络&#xff1f; 计算机网络我们可以理解为一个巨大的城市地图&#xff0c;我们想从A地前往B地&#xff0c;其中要走的路、要避开的问题都交给计算机网络解决&#xff0c;直到我们可以正常的到达目的地&#xff0c;那么我们会把其中的过程抽象成一个网络模型&…

练习01-登录注册(简单)

一、用户登录/注册实现 综合前面学的知识来实现简单的注册登录功能 1.准备工作 注册登录页面 数据库&#xff0c;数据表 mybatis 坐标引入&#xff0c;MySQL驱动 配置 映射文件 用户实体类 Servlet代码 2.页面 不想手写的可以看博主IT黄大大【带源码】 【炫酷登录界…

吴恩达机器学习-可选实验室:可选实验:使用逻辑回归进行分类(Classification using Logistic Regression)

在本实验中&#xff0c;您将对比回归和分类。 import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_common import dlc, plot_data from plt_one_addpt_onclick import plt_one_addpt_onclick plt.style.use(./deeplearning.mplstyle)jupy…

机器学习——PPO补充

On-policy vs Off-policy 今天跟环境互动&#xff0c;并学习是on-policy 只是在旁边看&#xff0c;就是Off-policy 从p中选q个重要的&#xff0c;需要加一个weight p(x)/q(x) p和q不能相差太多 采样数太少导致分布差很多&#xff0c;导致weight发生变化 On-Policy -&g…

STM32F103 CubeMX ADC 驱动 PS2游戏摇杆控制杆传感器模块

STM32F103 CubeMX ADC 驱动 PS2游戏摇杆控制杆传感器模块 1. 工程配置1.1 配置debug口1.2 配置时钟1.3 配置ADC1.4 配置串口1.5 配置时钟1.6 生成工程 2. 代码编写2.1 串口代码2.2 ADC读取数据的代码 1. 工程配置 1.1 配置debug口 1.2 配置时钟 1.3 配置ADC 1.4 配置串口 1.5 …

小迪安全37WEB 攻防-通用漏洞XSS 跨站权限维持钓鱼捆绑浏览器漏洞

#XSS跨站系列内容:1. XSS跨站-原理&分类&手法 XSS跨站-探针&利用&审计XSS跨站另类攻击手法利用 XSS跨站-防御修复&绕过策略 #知识点&#xff1a; 1、XSS 跨站-另类攻击手法分类 2、XSS 跨站-权限维持&钓鱼&浏览器等 1、原理 指攻击者利用…

JavaWeb-Maven基础

Maven是专门用于管理和构建Java项目的工具&#xff0c;是 Apache 下的一个纯 Java 开发的开源项目&#xff0c;基于项目对象模型&#xff08;POM&#xff09;概念。先来学习一下Maven基础&#xff0c;等后面学完开发框架后再学Maven高级&#xff0c;这次的内容如下 一、概述 …

leetcode 热题 100_搜索二维矩阵

题解一&#xff1a; 二叉搜索树&#xff1a;从矩阵右上角观察&#xff0c;结构类似二叉搜索树&#xff0c;因此可以用类似的解法来做。具体做法是双指针从右上角开始&#xff0c;向左下角逐步搜索&#xff0c;如果当前值比目标值大&#xff0c;则向下移动&#xff0c;如果当前值…

体系班第十三节

1判断完全二叉树递归做法 有四种情况&#xff1a;1 左树完全&#xff0c;右数满&#xff0c;且左高为右高加一 2左满 &#xff0c;右满&#xff0c;左高为右高加一 3左满&#xff0c;右完全&#xff0c;左右高相等 4左右均满且高相等 #include<iostream> #include&l…

封装方法3

上一篇处理了单元格返回值改写 这一篇处理剩余普通方法返回值改写 已经给了Object的返回值&#xff0c;需要回调 //返回结果是22个单元格的值&#xff0c;怎么给调用方 Object value getCellValue(cell);没有给调用方的情况 value值内容是什么 处理ecxel-22个单元值的返回结…

重启 explorer 进程的正确做法(二)

重启资源管理器进程的方法不唯一&#xff0c;但长期以来大家对实施方法用的不到位。 在上一篇中我认为&#xff1a;“我们往往使用 TerminateProcess 并传入 PID 和特殊结束代码 1 或者 taskkill /f /im 等方法重启资源管理器( explorer.exe )&#xff0c;其实这是不正确的。我…

神经网络实战前言

应用广泛 从人脸识别到网约车&#xff0c;在生活中无处不在 未来可期 无人驾驶技术便利出行医疗健康改善民生 产业革命 第四次工业革命——人工智能 机器学习概念 机器学习不等价与人工智能20世纪50年代&#xff0c;人工智能是说机器模仿人类行为的能力 符号人工智能 …

DevOps本地搭建笔记(个人开发适用)

需求和背景 win11 wsl2 armbian(玩客云矿渣&#xff09;&#xff0c;构建个人cicd流水线&#xff0c;提高迭代效率。 具体步骤 基础设施准备 硬件准备&#xff1a;一台笔记本&#xff0c;用于开发和构建部署&#xff0c;一台服务器&#xff0c;用于日常服务运行。 笔记本…

C#,蛇梯问题(Snake and Ladder Problem)的算法与源代码

1 蛇梯问题 Snake and Ladder Problem 给定一个蛇梯板&#xff0c;找出从源单元格或第一个单元格到达目标单元格或最后一个单元格所需的最小掷骰次数。基本上&#xff0c;玩家可以完全控制掷骰子的结果&#xff0c;并希望找出到达最后一个单元格所需的最小掷骰次数。 如果玩…

【大厂AI课学习笔记NO.76】人工智能人才金字塔

人工智能领域&#xff0c;分为源头创新人才、产业研发人才、应用开发人才和实用技能人才。 人工智能领域的人才结构呈现多样化特点&#xff0c;主要可以分为源头创新人才、产业研发人才、应用开发人才和实用技能人才四大类。这四大类人才在人工智能领域的发展中各自扮演着不可或…

Day30:安全开发-JS应用NodeJS指南原型链污染Express框架功能实现审计

目录 环境搭建-NodeJS-解析安装&库安装 功能实现-NodeJS-数据库&文件&执行 安全问题-NodeJS-注入&RCE&原型链 案例分析-NodeJS-CTF题目&源码审计 开发指南-NodeJS-安全SecGuide项目 思维导图 JS知识点&#xff1a; 功能&#xff1a;登录验证&…

常见排序算法(C/C++)--- 动画演示

本篇将介绍一些常见的排序算法&#xff0c;如插入排序&#xff1a;直接插入排序、希尔排序&#xff1b;选择排序&#xff1a;选择排序、堆排序&#xff1b;交换排序&#xff1a;快速排序、冒泡排序&#xff1b;以及最后的归并排序。 对于以上的排序算法&#xff0c;我们总结了每…

VScode的列选

可以用来优化代码排布&#xff0c;让变量整齐成为一排 一、批量复制&#xff1a; 在1处左键单击&#xff0c;然后摁住SHIFTALT键的同时&#xff0c;左键单击2处&#xff0c;即可复制一整块的内容 如果所示 就可以复制了 二、批量输入 在1处左键单击&#xff0c;然后摁住SHI…

Day32:安全开发-JavaEE应用Servlet路由技术JDBCMybatis数据库生命周期

目录 JavaEE-HTTP-Servlet&路由&周期 JavaEE-数据库-JDBC&Mybatis&库 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用等. 框架…