邯郸市瑞荣网络科技有限公司,系统优化有何作用,wordpress4.9中文版,工业设计考研比较好的学校我 | 在这里 #x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 #x1f3e0; 工作 | 广州 ⭐ Java 全栈开发#xff08;软件工程师#xff09; #x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 #x1f3f7;️ 标签 | 男 自律狂人 目标明确 责任心强 ✈️公… 我 | 在这里 ️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 工作 | 广州 ⭐ Java 全栈开发软件工程师 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 ️ 标签 | 男 自律狂人 目标明确 责任心强 ✈️公众号 | 热爱技术的小郑 邮箱 | 2977429967qq.com ✈️ GitHub项目仓库 开源项目 实战Demo 为何而写 好记性不如烂笔头记录学习的相关知识 、项目 BUG 解决 复盘总结加深记忆方便自己查看 分享知识咱就是这么乐于助人、专注填坑20年、哈哈哈哈 目标描述 没有伞的孩子、只能用力奔跑。向着架构师的方向努力、做一个有始有终的人。 所有源码公布开源在GitHub 上Mybatsi 案例源码传送门 1、Mybatis简介
1.1 什么是Mybatis
如何获得Mybatis ● maven仓库 dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.6/version/dependency● 中文文档https://mybatis.org/mybatis-3/zh/index.html ● Github:https://github.com/mybatis/mybatis-3
1.2 持久化
数据持久化 ● 持久化就是将程序的数据在持久状态和瞬时状态转化的过程 ● 内存断电即失 ● 数据库Jdbcio文件持久化 ● 生活方面例子冷藏罐头。 为什么需要持久化 ● 不想丢掉一些对象 ● 内存太贵
1.3 持久层
Dao层Service层Controller层… ● 完成持久化工作的代码块 ● 层界限十分明显
1.4 为什么需要Mybatis
● 帮助程序猿将数据存入到数据库中 ● 方便 ● 传统的JDBC代码太复杂简化–框架–自动化
2、第一个Mybatis程序
2.1 搭建环境
整体过程 ● 1、新建一个maven项目 ● 2、删除src目录 ● 3、pom中导入相关依赖可选 ● 4、新建一个module、目的方便项目扩展 ● 5、子项目中也可以导入相关依赖建议导入子项目方便区分不同的module dependencies!--mysql driver--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.9/version/dependency!--mybatis--dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.6/version/dependency!--junit--dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/version/dependency/dependencies
重点提示 需要加上如下代码。否则部分代码无法编译道target 目录下导致运行时报错 build!--**.xml写在src找不到问题解决方案 --resourcesresource!-- directory指定资源文件的位置 --directorysrc/main/java/directoryincludes!-- “**” 表示任意级目录 “*”表示任意任意文件 --!-- mvn resources:resources 对资源做出处理先于compile阶段 --include**/*.properties/includeinclude**/*.xml/include/includes!-- filtering开启过滤用指定的参数替换directory下的文件中的参数(eg. ${name}) --filteringfalse/filtering/resourceresourcedirectorysrc/main/resources/directory/resource/resources/build2.2 创建模块
● 编写mybatis的核心配置文件 这里的mappers 以及起别名 可以后期编写实体类、mapper的相关代码后再写 ?xml version1.0 encodingUTF-8 ? environments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver valuecom.mysql.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/spring_test?serverTimezoneUTCamp;useUnicodetrueamp;characterEncodingUTF-8amp;useSSLfalse/property nameusername valueroot/property namepassword valueroot//dataSource/environment
/environments!--加载映射配置文件--
mappersmapper resourcecom/zyz/mybatis/mapper/StudentMapper.xml/
/mappers● 编写mybatis 的相关工具类
package com.zyz.mybatis.entity;/*** BelongsProject: SpringDemo1* BelongsPackage: com.zyz.SpringDemo2.entity* Author: zhengyuzhu* CreateTime: 2023-11-16 22:33* Description: TODO* Version: 1.0*/
public class Student {private int stuNo;private String stuName;private int cardID;private int classID;public Student() {}public Student(int stuNo, String stuName, int cardID, int classID) {this.stuNo stuNo;this.stuName stuName;this.cardID cardID;this.classID classID;}public int getStuNo() {return stuNo;}public void setStuNo(int stuNo) {this.stuNo stuNo;}public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName stuName;}public int getCardID() {return cardID;}public void setCardID(int cardID) {this.cardID cardID;}public int getClassID() {return classID;}public void setClassID(int classID) {this.classID classID;}Overridepublic String toString() {return Student{ stuNo stuNo , stuName stuName \ , cardID cardID , classID classID };}
}2.3 编写代码
实体类 Student
package com.zyz.mybatis.entity;/*** BelongsProject: SpringDemo1* BelongsPackage: com.zyz.SpringDemo2.entity* Author: zhengyuzhu* CreateTime: 2023-11-16 22:33* Description: TODO* Version: 1.0*/
public class Student {private int stuNo;private String stuName;private int cardID;private int classID;public Student() {}public Student(int stuNo, String stuName, int cardID, int classID) {this.stuNo stuNo;this.stuName stuName;this.cardID cardID;this.classID classID;}public int getStuNo() {return stuNo;}public void setStuNo(int stuNo) {this.stuNo stuNo;}public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName stuName;}public int getCardID() {return cardID;}public void setCardID(int cardID) {this.cardID cardID;}public int getClassID() {return classID;}public void setClassID(int classID) {this.classID classID;}Overridepublic String toString() {return Student{ stuNo stuNo , stuName stuName \ , cardID cardID , classID classID };}
}mapper接口 StudentMapper 及 xml配置文件 StudentMapper.xml /*** author zyz* version 1.0* data 2023/11/16 22:33* Description:*/
public interface StudentMapper {/*** description: 查询全部* author: zhengyuzhu* date: 2023/11/16 22:34* return: java.util.Listcom.zyz.SpringDemo2.entity.Student**/ListStudent queryAll();/*** description: 新增学生* author: zhengyuzhu* date: 2023/11/16 22:34* param: student**/void addStudent(Student student);
}StudentMapper.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.zyz.mybatis.mapper.StudentMapper!--查询全部--select idqueryAll resultTypeStudentselect * from student/select!--新增学生--insert idaddStudent parameterTypeStudentinsert into student (stuno,stuname,cardid,classid)values (#{stuNo},#{stuName},#{cardID},#{classID})/insert
/mapper2.4 测试单元
/*** description: 基本测试* author: zhengyuzhu* date: 2023/11/20 22:21**/
Test
public void test01(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);ListStudent userList studentMapper.queryAll();for (Student student : userList) {System.out.println(student);}//关闭SqlSessionsqlSession.close();/*** 输出如下 :** Student{stuNo1, stuName张三, cardID1115, classID1}* Student{stuNo2, stuName李四, cardID1116, classID2}* Student{stuNo3, stuName王五, cardID1117, classID3}***/}3、测试增删改查CURD
提示我们的实体类或者数据库中的表字段或者参数过多我们应当考虑使用Map具体案例参考 3.3 修改。修改用户信息的时候使用了两种方式一种是通过对象。另外一种是通过map 。有关参数的赋值以及sql语句的字段 获取。都有说明
3.1 添加
mapper 和 xml 配置文件 /*** description: 新增学生* author: zhengyuzhu* date: 2023/11/16 22:34* param: student** return*/Integer addStudent(Student student);!--新增学生--insert idaddStudent parameterTypeStudentinsert into student (stuno, stuname, cardid, classid)values (#{stuNo}, #{stuName}, #{cardID}, #{classID})/insert
测试单元 /*** description: 添加对象* author: zhengyuzhu* date: 2023/11/21 21:06**/Testpublic void test04(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student student new Student();student.setStuNo(9);student.setStuName(武松);student.setClassID(8);student.setCardID(8);studentMapper.addStudent(student);sqlSession.commit();//将数据保存到数据库Student studentRs studentMapper.queryStudentById(9);System.out.println(studentRs);//关闭SqlSessionsqlSession.close();/*** 输出如下 :* Student{stuNo9, stuName武松, cardID8, classID8}***/}3.2 删除
mapper 和 xml 配置文件 /*** description:删除学生 通过 学号* author: zhengyuzhu* date: 2023/11/20 22:45* param: stuNo* return: java.lang.Integer**/Integer deleteStudentById(Integer stuNo);delete iddeleteStudentByIddeletefrom studentwhere stuNo #{stuNo}/delete测试单元 /*** description: 删除对象* author: zhengyuzhu* date: 2023/11/21 21:07**/Testpublic void test05(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();StudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);studentMapper.deleteStudentById(9);sqlSession.commit();//将数据保存到数据库Student studentRs studentMapper.queryStudentById(9);System.out.println(studentRs);//关闭SqlSessionsqlSession.close();/*** 输出如下 :* null***/}3.3 修改
mapper 和 xml 配置文件
一个是通过对象的方式修改一个是通过 map /** * description: 修改学生信息* author: zhengyuzhu* date: 2023/11/20 22:45* param: student* return: java.lang.Integer**/Integer updateStudent(Student student);/*** description: 通过Map 修改学生信息* author: zhengyuzhu* date: 2023/11/21 21:08* param: studentMap* return: java.lang.Integer**/Integer updateStudentMap(HashMapString,Object studentMap);update idupdateStudent parameterTypeStudentupdate studentset stuNo #{stuNo},stuName #{stuName},cardid #{cardID},classid #{classID}where stuNo #{stuNo}/updateupdate idupdateStudentMap parameterTypemapupdate studentset stuNo #{stuNo},stuName #{stuName},cardid #{cardid},classid #{classid}where stuNo #{stuNo}/update测试单元 /*** description: 修改对象信息 通过Map* author: zhengyuzhu* date: 2023/11/20 23:02**/Testpublic void test02(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);HashMapString, Object stuMap new HashMap();stuMap.put(stuNo,1);stuMap.put(stuName,李白);stuMap.put(cardid,6);stuMap.put(classid,6);Integer rs studentMapper.updateStudentMap(stuMap);Student student studentMapper.queryStudentById(1);System.out.println(student);//关闭SqlSessionsqlSession.close();/*** 输出如下 :** Student{stuNo1, stuName张三, cardID1115, classID1}* Student{stuNo2, stuName李四, cardID1116, classID2}* Student{stuNo3, stuName王五, cardID1117, classID3}***/}/*** description: 修改对象信息 通过 Student 对象* author: zhengyuzhu* date: 2023/11/20 23:02**/Testpublic void test03(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student studentBefore studentMapper.queryStudentById(0);System.out.println(修改前的学生信息 : studentBefore);Student student new Student();student.setStuNo(0);student.setStuName(麻子嘞);student.setClassID(6);student.setCardID(6);studentMapper.updateStudent(student);sqlSession.commit();//将数据保存到数据库Student studentAfter studentMapper.queryStudentById(0);System.out.println(修改后的学生信息 : studentAfter);//关闭SqlSessionsqlSession.close();/*** 输出如下 :** 修改前的学生信息 : Student{stuNo0, stuName李四, cardID8, classID8}* 修改后的学生信息 : Student{stuNo0, stuName麻子嘞, cardID6, classID6}***/}3.4 查询
mapper 和 xml 配置文件 /*** description: 查询全部* author: zhengyuzhu* date: 2023/11/16 22:34* return: java.util.Listcom.zyz.SpringDemo2.entity.Student**/ListStudent queryAll();/*** description:删除学生 通过 学号* author: zhengyuzhu* date: 2023/11/20 22:45* param: stuNo* return: java.lang.Integer**/Integer deleteStudentById(Integer stuNo);!--查询全部--select idqueryAll resultTypeStudentselect *from student/selectselect idqueryStudentById resultTypecom.zyz.mybatis.entity.Studentselect *from studentwhere stuNo #{stuNo}/select测试单元 /*** description: 基本测试* author: zhengyuzhu* date: 2023/11/20 22:21**/Testpublic void test01(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);ListStudent userList studentMapper.queryAll();for (Student student : userList) {System.out.println(student);}//关闭SqlSessionsqlSession.close();/*** 输出如下 :** Student{stuNo1, stuName张三, cardID1115, classID1}* Student{stuNo2, stuName李四, cardID1116, classID2}* Student{stuNo3, stuName王五, cardID1117, classID3}***/}3.5 模糊查询
● 1、java代码执行的时候传递通配符% %
/*** description: 模糊查询* author: zhengyuzhu* date: 2023/11/21 21:39* param: like* return: java.util.Listcom.zyz.mybatis.entity.Student**/
ListStudent getStudentLike(String value);● 2、在sql拼接中使用通配符
!--模糊查询--
select idgetStudentLike resultTypecom.zyz.mybatis.entity.Studentselect * from student where stuname like %#{value}%
/select测试单元
/*** description: 模糊查询* author: zhengyuzhu* date: 2023/11/21 21:41**/
Test
public void test06(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);ListStudent userList studentMapper.getStudentLike(%李%);for (Student student : userList) {System.out.println(student);}//关闭SqlSessionsqlSession.close();/*** 输出如下 :** Student{stuNo2, stuName李四, cardID1116, classID2}* Student{stuNo8, stuName李老头, cardID8, classID8}***/}4、配置解析
可以参考官网的更加详细的说明这里对常用的属性进行说明 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下 ● configuration配置 ○ properties属性 ○ settings设置 ○ typeAliases类型别名 ○ typeHandlers类型处理器 ○ objectFactory对象工厂 ○ plugins插件 ○ environments环境配置 ■ environment环境变量 ● transactionManager事务管理器 ● dataSource数据源 ○ databaseIdProvider数据库厂商标识 ○ mappers映射器
4.1 属性
我们可以通过properties属性来实现引用配置文件 这些属性都是可外部配置且可动态替换的既可以在典型的Java属性文件中配置亦可通过properties元素的子元素来传递。【db.properties】 编写一个配置文件
db.properties
jdbc.drivercom.mysql.jdbc.Driver
jdbc.urljdbc:mysql://localhost:3306/spring_test?serverTimezoneUTCamp;useUnicodetrueamp;characterEncodingUTF-8amp;useSSLfalse
jdbc.usernameroot
jdbc.passwordroot在核心配置文件中映入 !--引入外部配置文件这些属性可以在外部进行配置并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性也可以在 properties 元素的子元素中设置。例如--properties resourcedb.propertiesproperty nameusername valueroot/property namepassword valueroot//propertiesdataSource typePOOLED!--设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。driver 和 url 属性将会由 db.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。--property namedriver value${jdbc.driver}/property nameurl value${jdbc.url}/property nameusername value${username}/property namepassword value${password}//dataSource4.2 设置
设置 参考官网介绍 这里掠过 settings设置
4.3 类型别名
● 类型别名是为Java类型设置一个短的名字。 ● 存在的意义仅在于用来减少类完全限定名的冗余。
第一种实体类较少的情况。单独起别名
!--可以给实体类起别名--
typeAliasestypeAlias typecom.zyz.mybatis.entity.Student aliasstudent /
/typeAliases第二种当实体类很多的时候可以使用package的形式会自动的将该包下的所有类定义了别名别名就是其自身且不区分大小
typeAliasespackage namecom.zyz.mybatis.entity /
/typeAliases第一种可以DIY别名第二种则不行如果非要改需要在实体上增加注解
Alias(author)
public class Author {...
}4.4类型处理器typeHandlers
MyBatis 在设置预处理语句PreparedStatement中的参数或从结果集中取出一个值时 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。 类型处理器 参考官网介绍 这里掠过 typeHandlers类型处理器
4.5 对象工厂
每次 MyBatis 创建结果对象的新实例时它都会使用一个对象工厂ObjectFactory实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类要么通过默认无参构造方法要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为可以通过创建自己的对象工厂来实现 对象工厂 参考官网介绍 这里掠过 objectFactory对象工厂
4.6 插件plugins
具体使用参考官网略 plugins插件
4.7 环境配置
○ environments环境配置 ■ environment环境变量 ● transactionManager事务管理器 ● dataSource数据源
MyBatis 可以配置成适应多种环境这种机制有助于将 SQL 映射应用于多种数据库之中 现实情况下有多种理由需要这么做。例如开发、测试和生产环境需要有不同的配置或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。 不过要记住尽管可以配置多个环境但每个 SqlSessionFactory 实例只能选择一种环境。 environments 元素定义了如何配置环境。
environments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBCproperty name... value...//transactionManagerdataSource typePOOLEDproperty namedriver value${driver}/property nameurl value${url}/property nameusername value${username}/property namepassword value${password}//dataSource/environment
/environments注意一些关键点: ● 默认使用的环境 ID比如default“development”。 ● 每个 environment 元素定义的环境 ID比如id“development”。 ● 事务管理器的配置比如type“JDBC”。 ● 数据源的配置比如type“POOLED”。 默认环境和环境 ID 顾名思义。 环境可以随意命名但务必保证默认的环境 ID 要匹配其中一个环境 ID。
4.7.1 environment (环境变量)
注意一些关键点: ● 默认使用的环境 ID比如default“development”。 ● 每个 environment 元素定义的环境 ID比如id“development”。 ● 事务管理器的配置比如type“JDBC”。 ● 数据源的配置比如type“POOLED”。 默认环境和环境 ID 顾名思义。 环境可以随意命名但务必保证默认的环境 ID 要匹配其中一个环境 ID。
4.7.2 transactionManager事务管理器
如果你正在使用 Spring MyBatis则没有必要配置事务管理器因为 Spring 模块会使用自带的管理器来覆盖前面的配置。 这两种事务管理器类型都不需要设置任何属性。它们其实是类型别名换句话说你可以用 TransactionFactory 接口实现类的全限定名或类型别名代替它们。 在 MyBatis 中有两种类型的事务管理器也就是 type“[JDBC|MANAGED]” ● 1、JDBC – 这个配置直接使用了 JDBC 的提交和回滚功能它依赖从数据源获得的连接来管理事务作用域。默认情况下为了与某些驱动程序兼容它在关闭连接时启用自动提交。然而对于某些驱动程序来说启用自动提交不仅是不必要的而且是一个代价高昂的操作。因此从 3.5.10 版本开始你可以通过将 “skipSetAutoCommitOnClose” 属性设置为 “true” 来跳过这个步骤例如
● MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接而是让容器来管理事务的整个生命周期比如 JEE 应用服务器的上下文。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为
4.7.3 dataSource数据源
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的但如果要启用延迟加载特性就必须配置数据源。 有三种内建的数据源类型也就是 type“[UNPOOLED|POOLED|JNDI]” ● 1、UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢但对那些数据库连接可用性要求不高的简单应用程序来说是一个很好的选择。 性能表现则依赖于使用的数据库对某些数据库来说使用连接池并不重要这个配置就很适合这种情形。 ● 2、POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行能使并发 Web 应用快速响应请求。 ● 3、JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用容器可以集中或在外部配置数据源然后放置一个 JNDI 上下文的数据源引用
4.8 数据库厂商标识
具体参考官网这里掠过 databaseIdProvider数据库厂商标识
4.9 映射器
既然 MyBatis 的行为已经由上述元素配置完了我们现在就要来定义 SQL 映射语句了。 但首先我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面Java 并没有提供一个很好的解决方案所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 注意点 ● 接口和它的Mapper配置文件必须同名 ● 接口和它的Mapper配置文件必须在同一个包下!
四种方式 ● 1、第一种使用相对于类路径的资源引用
mappersmapper resourceorg/mybatis/builder/AuthorMapper.xml/mapper resourceorg/mybatis/builder/BlogMapper.xml/mapper resourceorg/mybatis/builder/PostMapper.xml/
/mappers● 2、第二种使用完全限定资源定位符URL
mappersmapper urlfile:///var/mappers/AuthorMapper.xml/mapper urlfile:///var/mappers/BlogMapper.xml/mapper urlfile:///var/mappers/PostMapper.xml/
/mappers● 3、第三种使用映射器接口实现类的完全限定类名
mappersmapper classorg.mybatis.builder.AuthorMapper/mapper classorg.mybatis.builder.BlogMapper/mapper classorg.mybatis.builder.PostMapper/
/mappers● 4、第四种将包内的映射器接口全部注册为映射器 【使用的最多】
mapperspackage nameorg.mybatis.builder/
/mappers4.10 完整的配置文件实战
4.10.1 db.properties
jdbc.drivercom.mysql.jdbc.Driver
jdbc.urljdbc:mysql://localhost:3306/spring_test?serverTimezoneUTCamp;useUnicodetrueamp;characterEncodingUTF-8amp;useSSLfalse
jdbc.usernameroot
jdbc.passwordroot4.10.2 mybatis-config.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd
!--configuration core file--configuration!--引入外部配置文件这些属性可以在外部进行配置并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性也可以在 properties 元素的子元素中设置。例如--properties resourcedb.propertiesproperty nameusername valueroot/property namepassword valueroot//properties!--1、可以给实体类起别名typeAliasestypeAlias typecom.zyz.mybatis.entity.Student aliasstudent //typeAliases2、 批量设置别名会自动的将该包下的所有类定义了别名别名就是其自身且不区分大小--typeAliasespackage namecom.zyz.mybatis.entity //typeAliases!--MyBatis 可以配置成适应多种环境这种机制有助于将 SQL 映射应用于多种数据库之中 现实情况下有多种理由需要这么做。例如开发、测试和生产环境需要有不同的配置或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。不过要记住尽管可以配置多个环境但每个 SqlSessionFactory 实例只能选择一种环境注意一些关键点:默认使用的环境 ID比如defaultdevelopment。每个 environment 元素定义的环境 ID比如iddevelopment。事务管理器的配置比如typeJDBC。数据源的配置比如typePOOLED。默认环境和环境 ID 顾名思义。 环境可以随意命名但务必保证默认的环境 ID 要匹配其中一个环境 ID。--environments defaultdevelopmentenvironment iddevelopment!--JDBC – 这个配置直接使用了 JDBC 的提交和回滚功能它依赖从数据源获得的连接来管理事务作用域。默认情况下为了与某些驱动程序兼容它在关闭连接时启用自动提交。--transactionManager typeJDBC/!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的但如果要启用延迟加载特性就必须配置数据源。POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来避免了创建新的连接实例时所必需的初始化和认证时间。这种处理方式很流行能使并发 Web 应用快速响应请求。--dataSource typePOOLED!--设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。driver 和 url 属性将会由 db.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。--property namedriver value${jdbc.driver}/property nameurl value${jdbc.url}/property nameusername value${username}/property namepassword value${password}//dataSource/environment/environments!--加载映射配置文件既然 MyBatis 的行为已经由上述元素配置完了我们现在就要来定义 SQL 映射语句了。但首先我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面Java 并没有提供一个很好的解决方案所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。你可以使用相对于1、类路径的资源引用2、完全限定资源定位符包括 file:/// 形式的 URL3、类名4、包名--!-- 1、使用相对于类路径的资源引用 --mappersmapper resourcecom/zyz/mybatis/mapper/StudentMapper.xml//mappers!--2、使用完全限定资源定位符URLmappersmapper urlfile:///var/mappers/AuthorMapper.xml/mapper urlfile:///var/mappers/BlogMapper.xml/mapper urlfile:///var/mappers/PostMapper.xml//mappers--!--3、使用映射器接口实现类的完全限定类名mappersmapper classorg.mybatis.builder.AuthorMapper/mapper classorg.mybatis.builder.BlogMapper/mapper classorg.mybatis.builder.PostMapper//mappers--!--4、将包内的映射器接口全部注册为映射器mapperspackage nameorg.mybatis.builder//mappers--
/configuration4.10.3 项目结构 5、解决属性名和字段名不一致的问题
数据库 和 实体类对应关系如下
5.1 通过字段别名解决
2、通过给字段起别名解决
select idqueryGoodsById resultTypecom.zyz.mybatis.entity.Goodsselect id,name as goods_Name,amount as goods_Amount,price as goods_Pricefrom goodswhere id #{id}
/select5.2 通过结果集映射(resultMap)
3、通过结果集映射
select idqueryGoodsById resultMapGoodsMapselect *from goodswhere id #{id}
/select!-- 结果集映射 --
resultMap idGoodsMap typeGoods!--column数据库中的字段property实体类中的属性--result columnid propertyid /result columnname propertygoods_Name /result columnamount propertygoods_Amount /result columnprice propertygoods_Price /
/resultMap测试单元 /*** description: 测试查询商品信息 数据库字段 和 实体类字段不一致问题* author: zhengyuzhu* date: 2023/11/22 9:19**/Testpublic void testDemo1(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperGoodsMapper goodsMapper sqlSession.getMapper(GoodsMapper.class);Goods goods goodsMapper.queryGoodsById(1001);System.out.println(goods);//关闭SqlSessionsqlSession.close();/*** 输出如下 :* 实体类字段 数据库字段* id id* goods_Name name* goods_Amount amount* goods_Price price** Goods{id1001, goods_Namenull, goods_Amountnull, goods_Pricenull}**** 第一种方式字段起别名* select id,name as goods_Name,amount as goods_Amount,price as goods_Price** Goods{id1001, goods_Name茶杯, goods_Amount10, goods_Price13.6}*** 第二种方式结果集映射* 具体实现查看 GoodsMapper.xml 文件注释描述** Goods{id1001, goods_Name茶杯, goods_Amount10, goods_Price13.6}***/}6、日志
Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一 ● SLF4J ● Apache Commons Logging ● Log4j 2 ● Log4j3.5.9起废弃 ● JDK logging MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。
6.1 Log4j 的使用
什么是Log4j
● Log4j是Apache的一个开源项目通过使用Log4j我们可以控制日志信息输送的目的地是控制台、文件、GUI组件 ● 我们也可以控制每一条日志的输出格式 ● 通过定义每一条日志信息的级别我们能够更加细致地控制日志的生成过程。 ● 可以通过一个配置文件来灵活地进行配置而不需要修改应用的代码。
具体使用过程如下 1、先在pom.xml文件中导入log4j的依赖包
!-- Log4j 配置 --
dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version
/dependency2、在resources文件夹下建立log4j.properties文件进行配置 这里将 文件输出的位置 放在根目录 ./log/zyz.log
#将等级为DEBUG的日志信息输出到console和file这两个目的地console和file的定义在下面的代码
log4j.rootLogger DEBUG,console ,file#控制台输出的相关设置
log4j.appender.console org.apache.log4j.ConsoleAppender
log4j.appender.console.Target System.out
log4j.appender.console.Threshold DEBUG
log4j.appender.console.layout org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern [%c]-%m%n#文件输出的相关设置
log4j.appender.file org.apache.log4j.RollingFileAppender
log4j.appender.file.File ./log/zyz.log
log4j.appender.file.MaxFileSize 10mb
log4j.appender.file.Threshold DEBUG
log4j.appender.file.layout org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern [%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别
log4j.logger.org.mybatisDEBUG
log4j.logger.java.sqlDEBUG
log4j.logger.java.sql.StatementDEBUG
log4j.logger.java.sql.ResultSetDEBUG
log4j.logger.java.sql.PreparedStatementDEBUG3、在mybatis-config.xml核心配置文件中配置log4j为日志的实现
settingssetting namelogImpl valueLOG4J/
/settings4、Log4j的使用直接测试运行 在被测试的类中添加 这段信息
static Logger logger Logger.getLogger(TestGoods.class);
import com.zyz.mybatis.entity.Goods;
import com.zyz.mybatis.mapper.GoodsMapper;
import com.zyz.mybatis.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;/*** BelongsProject: Mybatis* BelongsPackage: PACKAGE_NAME* Author: zhengyuzhu* CreateTime: 2023-11-22 09:19* Description: TODO* Version: 1.0*/
public class TestGoods {static Logger logger Logger.getLogger(TestGoods.class);/*** description: 测试日志打印* author: zhengyuzhu* date: 2023/11/22 10:03**/Testpublic void testDemo2(){logger.info(INFO 日志测试);logger.debug(DEBUG 日志测试);logger.error(ERROR 日志测试);}
}输出结果入下
7、分页
思考为什么要分页 ● 减少数据的处理量
7.1 使用Limit分页
语法SELECT * from user limit startIndex,pageSize SELECT * from user limit 3 #[0,n]
1、接口
/*** description: 使用 limit 分页查询数据* author: zhengyuzhu* date: 2023/11/22 10:56* param: map* return: java.util.Listcom.zyz.mybatis.entity.Goods**/
ListGoods queryGoodsLimit(MapString,Object map);2、GoodsMapper.xml 文件
!--分页查询数据--
select idqueryGoodsLimit resultMapGoodsMapselect *from goods limit #{startIndex},#{pageSize}
/select!-- 结果集映射 --
resultMap idGoodsMap typeGoods!--column数据库中的字段property实体类中的属性--result columnid propertyid /result columnname propertygoods_Name /result columnamount propertygoods_Amount /result columnprice propertygoods_Price /
/resultMap3、测试单元
/*** description: limit 分页查询数据* author: zhengyuzhu* date: 2023/11/22 10:59**/
Test
public void testDemo3(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperGoodsMapper goodsMapper sqlSession.getMapper(GoodsMapper.class);HashMapString, Object goodsMap new HashMapString, Object();goodsMap.put(startIndex,0);goodsMap.put(pageSize,3);ListGoods goodsList goodsMapper.queryGoodsLimit(goodsMap);for(Goods goods : goodsList){logger.info(goods);}//关闭SqlSessionsqlSession.close();/*** 输出如下 :** [com.zyz.mybatis.mapper.GoodsMapper.queryGoodsLimit]- Preparing: select * from goods limit ?,?* [com.zyz.mybatis.mapper.GoodsMapper.queryGoodsLimit]- Parameters: 0(Integer), 3(Integer)* [com.zyz.mybatis.mapper.GoodsMapper.queryGoodsLimit]- Total: 3* [TestGoods]-Goods{id1001, goods_Name茶杯, goods_Amount10, goods_Price13.6}* [TestGoods]-Goods{id1002, goods_Name茶壶, goods_Amount10, goods_Price15.9}* [TestGoods]-Goods{id1003, goods_Name保温杯, goods_Amount10, goods_Price23.6}***/
}7.2 RowBounds分页
1.接口
/*** description: 使用 RowBounds 分页* author: zhengyuzhu* date: 2023/11/22 11:12* return: java.util.Listcom.zyz.mybatis.entity.Goods**/
ListGoods queryGoodsByRowBounds();2 .GoodsMapper.xml 文件
!--使用 RowBounds 分页--
select idqueryGoodsByRowBounds resultMapGoodsMapselect * from goods
/select!-- 结果集映射 --
resultMap idGoodsMap typeGoods!--column数据库中的字段property实体类中的属性--result columnid propertyid /result columnname propertygoods_Name /result columnamount propertygoods_Amount /result columnprice propertygoods_Price /
/resultMap3.测试单元
/*** description: 2、使用 RowBounds 分页* author: zhengyuzhu* date: 2023/11/22 11:14**/
Test
public void testDemo4(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();// RowBounds 实现RowBounds rowBounds new RowBounds(0, 2);ListGoods goodsList sqlSession.selectList(com.zyz.mybatis.mapper.GoodsMapper.queryGoodsByRowBounds,null,rowBounds);for(Goods goods : goodsList){logger.info(goods);}//关闭SqlSessionsqlSession.close();/*** 输出如下 :** [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection77a57272]* [com.zyz.mybatis.mapper.GoodsMapper.queryGoodsByRowBounds]- Preparing: select * from goods* [com.zyz.mybatis.mapper.GoodsMapper.queryGoodsByRowBounds]- Parameters:* [TestGoods]-Goods{id1001, goods_Name茶杯, goods_Amount10, goods_Price13.6}* [TestGoods]-Goods{id1002, goods_Name茶壶, goods_Amount10, goods_Price15.9}***/
}7.3 分页插件
官网介绍链接https://pagehelper.github.io/
使用分页插件的流程 ● 1、在maven中引入PageHelper和jsqlparser ● 2、mybatis-config.xml中增加plugin配置 ● 3、代码中使用PageHelper.startPage() 自动分页
1、首先在maven中引入PageHelper和jsqlparser
!--分页插件--
dependencygroupIdcom.github.pagehelper/groupIdartifactIdpagehelper/artifactIdversion5.1.4/version
/dependency
dependencygroupIdcom.github.jsqlparser/groupIdartifactIdjsqlparser/artifactIdversion1.4/version
/dependency说明 1jsqlparser的版本需要是2.0及以上的版本因为5.1.10之前的PageHelper并没有对jsqlparser版本作要求但是5.1.10及以后的PageHelper采用了新的API所以jsqlparser的版本需要是2.0及以上的版本才可以【我这里退回 1.4 可以正常使用】 2PageHelper执行原理PageHelper在原有的要执行的SQL基础上进行分析自动生成分页以及【select count(*) from…】这样的语句因为涉及到原始SQL的分析与解析所以需要引入jsqlparser这个SQL解析器组件啦
2、mybatis-config.xml中增加plugin配置 参数详解Mybatis-PageHelper 官网官网文档 plugins插件是mybatis的一个特色通过插件可以扩展mybatis的能力 2interceptor属性代表拦截器需要配置PageHelper的核心类 3helperDialect配置项和reasonable配置项在PageHelper的官网文档中有详细说明
plugins!-- com.github.pagehelper为PageHelper类所在包名 --plugin interceptorcom.github.pagehelper.PageInterceptor!--使用下面的方式配置参数helperDialect分页插件会自动检测当前的数据库链接自动选择合适的分页方式。你可以配置helperDialect属性来指定分页插件使用哪种方言 配置时可以使用下面的缩写值oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derbyreasonable分页合理化参数默认值为false。当该参数设置为 true 时pageNum0 时会查询第一页 pageNumpages超过总数时会查询最后一页。默认false 时直接根据参数进行查询。更多参数配置参考官网--property namehelperDialect valuemysql/property namereasonable valuetrue//plugin
/plugins3、测试单元 /*** description: 3、使用分页插件* author: zhengyuzhu* date: 2023/11/22 13:43**/Testpublic void testDemo5(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();// PageHelper.startPage()对即将到来的下一次查询进行分页处理// 比如下面就是第1页每页2条数据PageHelper.startPage(1, 2);GoodsMapper goodsMapper sqlSession.getMapper(GoodsMapper.class);ListGoods goodsList goodsMapper.queryGoodByPlugin();//用PageInfo对结果进行包装PageInfo page new PageInfo(goodsList);System.out.println(总页数page.getPages());System.out.println(总记录数page.getTotal());System.out.println(开始行号page.getStartRow());System.out.println(结束行号page.getEndRow());System.out.println(当前页码page.getPageNum());ListGoods goodsListRs page.getList();for(Goods goods : goodsListRs){logger.info(goods);}//关闭SqlSessionsqlSession.close();/*** 输出如下 :*[com.zyz.mybatis.mapper.GoodsMapper.queryGoodByPlugin_COUNT]- Preparing: SELECT count(0) FROM goods[com.zyz.mybatis.mapper.GoodsMapper.queryGoodByPlugin_COUNT]- Parameters: [com.zyz.mybatis.mapper.GoodsMapper.queryGoodByPlugin_COUNT]- Total: 1[com.zyz.mybatis.mapper.GoodsMapper.queryGoodByPlugin]- Preparing: select * from goods LIMIT ?[com.zyz.mybatis.mapper.GoodsMapper.queryGoodByPlugin]- Parameters: 2(Integer)[com.zyz.mybatis.mapper.GoodsMapper.queryGoodByPlugin]- Total: 2总页数2总记录数4开始行号1结束行号2当前页码1[TestGoods]-Goods{id1001, goods_Name茶杯, goods_Amount10, goods_Price13.6}[TestGoods]-Goods{id1002, goods_Name茶壶, goods_Amount10, goods_Price15.9}**/}8、使用注解开发
8.1 面向接口编程
● 之前学过面向对象编程也学习过接口但在真正的开发中很多时候会选择面向接口编程。 ● 根本原因解耦可拓展提高复用分层开发中上层不用管具体的实现大家都遵守共同的标准使得开发变得容易规范性更好 ● 在一个面向对象的系统中系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下各个对象内部是如何实现自己的对系统设计人员来讲就不那么重要了 ● 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信大到各模块之间的交互在系统设计之初都是要着重考虑的这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
8.2 注解开发
8.2.1 基本测试
注解在StudentMapper接口上实现不需要 StudentMapper.xml文件 /*** description: 查询用户* author: zhengyuzhu* date: 2023/11/22 14:40* return: java.util.Listcom.zyz.mybatis.entity.User**/Select(select * from user)ListUser getUsers();需要在mybatis-config.xml核心配置文件中绑定接口
mappersmapper resourcecom/zyz/mybatis/mapper/StudentMapper.xml/mapper resourcecom/zyz/mybatis/mapper/GoodsMapper.xml/mapper classcom.zyz.mybatis.mapper.UserMapper/
/mappers单元测试
/*** description: 注解开发 查询* author: zhengyuzhu* date: 2023/11/22 14:41**/Testpublic void testDemo1(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);ListUser users mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUsers]- Preparing: select * from user* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Parameters:* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Total: 6* User{id1, name张三, passwordnull}* User{id2, name李四, passwordnull}* User{id3, name王五, passwordnull}* User{id4, name麻子, passwordnull}* User{id5, name李白, passwordnull}* User{id6, name小明, passwordnull}****/}8.2.2 测试增删改查
当数据表字段名和POJO字段名不一致时需要进行映射
/*** description: 查询用户* author: zhengyuzhu* date: 2023/11/22 14:40* return: java.util.Listcom.zyz.mybatis.entity.User**/
Select(select * from user)
Results(value {Result(idtrue,column id,property id),Result(column name,property name),Result(column pwd,property password)
})
ListUser getUsers();测试单元 /*** description: 注解开发 查询* author: zhengyuzhu* date: 2023/11/22 14:41**/Testpublic void testDemo1(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);ListUser users mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUsers]- Preparing: select * from user* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Parameters:* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Total: 6* User{id1, name张三, passwordnull}* User{id2, name李四, passwordnull}* User{id3, name王五, passwordnull}* User{id4, name麻子, passwordnull}* User{id5, name李白, passwordnull}* User{id6, name小明, passwordnull}* * * 采用结果集映射后* * [com.zyz.mybatis.mapper.UserMapper.getUsers]- Preparing: select * from user* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Parameters: * [com.zyz.mybatis.mapper.UserMapper.getUsers]- Total: 7* User{id1, name张三, password123}* User{id2, name李四, password456}* User{id3, name王五, password789}* User{id4, name麻子, password321}* User{id5, name李白, password654}* User{id6, name小明, password987}* User{id7, name小红, password666}****/}其他接口如何重复使用上面的那个映射呢如下
测试单元 /*** description: 查询 通过ID* author: zhengyuzhu* date: 2023/11/22 15:15**/Testpublic void testDemo2(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.getUserById(1);System.out.println(user);sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* User{id1, name张三, passwordnull}* * 复用结果集映射* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* User{id1, name张三, password123}***/}8.2.2 查询
如果实体类字段 和 数据库字段不一致 需要进行接口 结果集映射 Results(id UserMap,value {Result(idtrue,column id,property id),Result(column name,property name),Result(column pwd,property password)})这里添加一个 id 可以达到复用的效果。 其它接口使用结果集的时候可以直接用 ResultMap(value (“UserMap”)) 接口 /*** description: 查询用户* author: zhengyuzhu* date: 2023/11/22 14:40* return: java.util.Listcom.zyz.mybatis.entity.User**/Select(select * from user)Results(id UserMap,value {Result(idtrue,column id,property id),Result(column name,property name),Result(column pwd,property password)})ListUser getUsers();/*** description: 查询用户 通过 用户ID 方法存在多个参数所有参数前面必须加上Param(id)注解* author: zhengyuzhu* date: 2023/11/22 15:12* param: id* return: com.zyz.mybatis.entity.User**/Select(select * from user where id#{id})ResultMap(value (UserMap))User getUserById(Param(id) int id);测试单元
/*** description: 注解开发 查询* author: zhengyuzhu* date: 2023/11/22 14:41**/
Test
public void testDemo1(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);ListUser users mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUsers]- Preparing: select * from user* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Parameters:* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Total: 6* User{id1, name张三, passwordnull}* User{id2, name李四, passwordnull}* User{id3, name王五, passwordnull}* User{id4, name麻子, passwordnull}* User{id5, name李白, passwordnull}* User{id6, name小明, passwordnull}*** 采用结果集映射后** [com.zyz.mybatis.mapper.UserMapper.getUsers]- Preparing: select * from user* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Parameters:* [com.zyz.mybatis.mapper.UserMapper.getUsers]- Total: 7* User{id1, name张三, password123}* User{id2, name李四, password456}* User{id3, name王五, password789}* User{id4, name麻子, password321}* User{id5, name李白, password654}* User{id6, name小明, password987}* User{id7, name小红, password666}****/
}/*** description: 查询 通过ID* author: zhengyuzhu* date: 2023/11/22 15:15**/
Test
public void testDemo2(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.getUserById(1);//查询System.out.println(user);sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* User{id1, name张三, passwordnull}** 复用结果集映射* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* User{id1, name张三, password123}***/
}8.2.3 添加
接口
/*** description: 添加用户* author: zhengyuzhu* date: 2023/11/22 15:11* param: user* return: int**/
Insert(insert into user (id,name,pwd) values(#{id},#{name},#{password}))
int addUser(User user);测试单元 /*** description: 添加用户* author: zhengyuzhu* date: 2023/11/22 15:15**/Testpublic void testDemo3(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user new User();user.setId(8);user.setName(小青);user.setPassword(888);mapper.addUser(user);//添加User userRs mapper.getUserById(8);System.out.println(新添加用户 : userRs);sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.addUser]- Preparing: insert into user (id,name,pwd) values(?,?,?)* [com.zyz.mybatis.mapper.UserMapper.addUser]- Parameters: 8(Integer), 小青(String), 888(String)* [com.zyz.mybatis.mapper.UserMapper.addUser]- Updates: 1* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* 新添加用户 : User{id8, name小青, password888}***/}8.2.4 修改
接口
/*** description: 修改用户* author: zhengyuzhu* date: 2023/11/22 15:11* param: user* return: int**/
Update(update user set name#{name},pwd#{password} where id#{id})
int updateUser(User user);测试单元 /*** description: 修改用户* author: zhengyuzhu* date: 2023/11/22 15:15**/Testpublic void testDemo4(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User userRs mapper.getUserById(8);System.out.println(未修改前用户信息 : userRs);User user new User();user.setId(8);user.setName(小紫);user.setPassword(999);mapper.updateUser(user);//修改User userRss mapper.getUserById(8);System.out.println(修改后用户信息 : userRss);sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* 未修改前用户信息 : User{id8, name小青, password888}* [com.zyz.mybatis.mapper.UserMapper.updateUser]- Preparing: update user set name?,pwd? where id?* [com.zyz.mybatis.mapper.UserMapper.updateUser]- Parameters: 小紫(String), 999(String), 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.updateUser]- Updates: 1* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* 修改后用户信息 : User{id8, name小紫, password999}***/}8.2.5 删除
接口
/*** description:删除用户 可以通过Param() 给传递的参数 修改别名* author: zhengyuzhu* date: 2023/11/22 15:11* param: id* return: int**/
Delete(delete from user where id #{uid})
int deleteUser(Param(uid) int id);测试单元 /*** description: 删除用户* author: zhengyuzhu* date: 2023/11/22 15:15**/Testpublic void testDemo5(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User userRs mapper.getUserById(8);System.out.println(删除前用户信息 : userRs);mapper.deleteUser(8);//删除User userRss mapper.getUserById(8);System.out.println(删除后用户信息 : userRss);sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 1* 删除前用户信息 : User{id8, name小紫, password999}* [com.zyz.mybatis.mapper.UserMapper.deleteUser]- Preparing: delete from user where id ?* [com.zyz.mybatis.mapper.UserMapper.deleteUser]- Parameters: 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.deleteUser]- Updates: 1* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Preparing: select * from user where id?* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Parameters: 8(Integer)* [com.zyz.mybatis.mapper.UserMapper.getUserById]- Total: 0* 删除后用户信息 : null***/}9、Lombok偷懒的话可以使用
使用步骤
在IDEA中安装Lombok插件在项目pom.xml文件中导入Lombok的jar包 !-- https://mvnrepository.com/artifact/org.projectlombok/lombok --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.10/version/dependency在实体类上加注解即可
Data
AllArgsConstructor
NoArgsConstructorGetter and Setter
FieldNameConstants
ToString
EqualsAndHashCode
AllArgsConstructor, RequiredArgsConstructor and NoArgsConstructor
Log, Log4j, Log4j2, Slf4j, XSlf4j, CommonsLog, JBossLog, Flogger, CustomLog
Data
Builder
SuperBuilder
Singular
Delegate
Value
Accessors
Wither
With
SneakyThrows说明
Data:无参构造、get、set、toString、hashCode、equals
AllArgsConstructor
NoArgsConstructor
EqualsAndHashCode
ToString
Getter and Setter10、多对一处理
多对一 ● 多个学生对应一个老师 ● 对于学生而言关联–多个学生关联一个老师【多对一】 ● 对于老师而言集合–一个老师有很多个学生【一对多】
SQL 语句
CREATE TABLE tb_teacher (id INT(10) NOT NULL,name VARCHAR(30) DEFAULT NULL,PRIMARY KEY (id)
)ENGINE INNODB DEFAULT CHARSETutf8INSERT INTO tb_teacher(id,name) VALUES (1,玉小刚);CREATE TABLE tb_student (id INT(10) NOT NULL,name VARCHAR(30) DEFAULT NULL,tid INT(10) DEFAULT NULL,PRIMARY KEY (id),KEY fktid(tid),CONSTRAINT fktid FOREIGN KEY (tid) REFERENCES teacher (id)
)ENGINE INNODB DEFAULT CHARSETutf8INSERT INTO tb_student(id,name,tid) VALUES (1,唐三,1);
INSERT INTO tb_student(id,name,tid) VALUES (2,小舞,1);
INSERT INTO tb_student(id,name,tid) VALUES (3,戴沐白,1);
INSERT INTO tb_student(id,name,tid) VALUES (4,朱朱清,1);
INSERT INTO tb_student(id,name,tid) VALUES (5,奥斯卡,1);
INSERT INTO tb_student(id,name,tid) VALUES (6,宁荣荣,1);
INSERT INTO tb_student(id,name,tid) VALUES (7,马红俊,1);
INSERT INTO tb_student(id,name,tid) VALUES (8,白尘香,1);测试环境搭建
导入Lombok新建实体类TeacherStudentmybatis核心配置文件修改建立Mapper接口建立Mapper.XML文件在核心配置文件中绑定注册我们的Mapper接口或者文件【方式很多,随心选】测试查询是否能够成功
1、导入Lombok dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.10/version/dependency2、实体类TeacherStudent
Data //getset
NoArgsConstructor //无参构造
AllArgsConstructor //有参构造
public class Student {private Integer id;private String name;private Teacher teacher;}Data //getset
NoArgsConstructor //无参构造
AllArgsConstructor //有参构造
public class Teacher {private Integer id;private String name;}3、mybatis 配置文件
typeAliasespackage namecom.zyz.mybatis.entity /package namecom.zyz.mybatis.vo /
/typeAliasesmappersmapper resourcecom/zyz/mybatis/mapper/StudentMapper.xml/mapper resourcecom/zyz/mybatis/mapper/TeacherMapper.xml/
/mappers4、mapper 接口
public interface StudentMapper {/*** description: 查询学生* author: zhengyuzhu* date: 2023/11/22 22:27* return: java.util.Listcom.zyz.mybatis.entity.Student**/ListStudent getStudent();/*** description: 查询学生* author: zhengyuzhu* date: 2023/11/22 22:27* return: java.util.Listcom.zyz.mybatis.entity.Student**/ListStudent getStudent2();}5、mapper.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.zyz.mybatis.mapper.StudentMapper!--1、按照结果集嵌套处理这里重点说一下 这个结果集映射。如果对查询出来的数据字段 起了 别名。则映射的时候 要用这个别名。--resultMap idStudentMap typeStudent!--这里的column是与查询结果的字段名对应字段重命名了则对应命名后的字段--result propertyid columnsid/result propertyname columnsname/!--复杂的属性需要单独处理 对象association 集合collection--association propertyteacher javaTypeTeacherresult propertyname columntname/result propertyid columntid//association/resultMap!--查询学生--select idgetStudent resultMapStudentMapselect s.id sid,s.name sname,t.name tname,s.tid tidfrom tb_student sjoin tb_teacher ton s.tid t.id/select!--2、 按照查询嵌套处理--select idgetStudent2 resultMapStudentMap2select * from tb_student;/selectselect idgetTeacher resultTypeTeacherselect * from tb_teacher where id #{tid};/select!--这里将学生和对应老师分开查询将查询结果组合--resultMap idStudentMap2 typeStudentresult propertyid columnid/result propertyname columnname/association propertyteacher columntid javaTypeTeacher selectgetTeacher//resultMap
/mapper6、测试单元
/*** description: 1、按照结果集嵌套处理 多对一* author: zhengyuzhu* date: 2023/11/22 23:07**/
Test
public void testDemo1(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();StudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);ListStudent studentList studentMapper.getStudent();for(Student student : studentList){System.out.println(student);}sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.StudentMapper.getStudent]- Preparing: select s.id sid,s.name sname,t.name tname,s.tid tid from tb_student s join tb_teacher t on s.tid t.id* [com.zyz.mybatis.mapper.StudentMapper.getStudent]- Parameters:* [com.zyz.mybatis.mapper.StudentMapper.getStudent]- Total: 8* Student{id1, name唐三, teacherTeacher{id1, name玉小刚}}* Student{id2, name小舞, teacherTeacher{id1, name玉小刚}}* Student{id3, name戴沐白, teacherTeacher{id1, name玉小刚}}* Student{id4, name朱朱清, teacherTeacher{id1, name玉小刚}}* Student{id5, name奥斯卡, teacherTeacher{id1, name玉小刚}}* Student{id6, name宁荣荣, teacherTeacher{id1, name玉小刚}}* Student{id7, name马红俊, teacherTeacher{id1, name玉小刚}}* Student{id8, name白尘香, teacherTeacher{id1, name玉小刚}}***/
}/*** description: 2、 按照查询嵌套处理 多对一* author: zhengyuzhu* date: 2023/11/22 23:07**/
Test
public void testDemo2(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();StudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);ListStudent studentList studentMapper.getStudent2();for(Student student : studentList){System.out.println(student);}sqlSession.close();/*** 输出如下** [com.zyz.mybatis.mapper.StudentMapper.getStudent2]- Preparing: select * from tb_student;* [com.zyz.mybatis.mapper.StudentMapper.getStudent2]- Parameters:* [com.zyz.mybatis.mapper.StudentMapper.getTeacher]- Preparing: select * from tb_teacher where id ?;* [com.zyz.mybatis.mapper.StudentMapper.getTeacher]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.getTeacher]- Total: 1* [com.zyz.mybatis.mapper.StudentMapper.getStudent2]- Total: 8* Student{id1, name唐三, teacherTeacher{id1, name玉小刚}}* Student{id2, name小舞, teacherTeacher{id1, name玉小刚}}* Student{id3, name戴沐白, teacherTeacher{id1, name玉小刚}}* Student{id4, name朱朱清, teacherTeacher{id1, name玉小刚}}* Student{id5, name奥斯卡, teacherTeacher{id1, name玉小刚}}* Student{id6, name宁荣荣, teacherTeacher{id1, name玉小刚}}* Student{id7, name马红俊, teacherTeacher{id1, name玉小刚}}* Student{id8, name白尘香, teacherTeacher{id1, name玉小刚}}***/
}11、一对多处理
具体搭建过程同 多对一处理
1、实体类TeacherTStudentT 同一个环境测试实体类的字段有所不同。通过起别名的方式完善。
Data //getset
NoArgsConstructor //无参构造
AllArgsConstructor //有参构造
public class StudentT {private Integer id;private String name;private Integer tid;}Data //getset
NoArgsConstructor //无参构造
AllArgsConstructor //有参构造
public class TeacherT {private Integer id;private String name;private ListStudentT studentTs;}2、mybatis 核心配置文件 typeAliasespackage namecom.zyz.mybatis.entity /package namecom.zyz.mybatis.vo //typeAliasesmappersmapper resourcecom/zyz/mybatis/mapper/StudentMapper.xml/mapper resourcecom/zyz/mybatis/mapper/TeacherMapper.xml//mappers3、mapper 接口
public interface TeacherMapper {/*** description: 1、按照结果嵌套处理 多对一* author: zhengyuzhu* date: 2023/11/22 23:50 * return: com.zyz.mybatis.vo.Teacher**/TeacherT getTeacherById(Integer id);/*** description: 2、按照查询嵌套处理 一对多* author: zhengyuzhu* date: 2023/11/23 0:12* param: id* return: com.zyz.mybatis.vo.TeacherT**/TeacherT getTeacher2(Integer id);}4、mapper.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.zyz.mybatis.mapper.TeacherMapper!--1、 按结果嵌套查询--select idgetTeacherById resultMapTeacherByIdselect t.id id, t.name tname, s.id sid,s.name sname,s.tid tidfrom tb_teacher tjoin tb_student son t.id s.tid;/selectresultMap idTeacherById typeTeacherTresult propertyid columnid/result propertyname columntname/!--获取ListStudent中的泛型使用 ofType--collection propertystudentTs ofTypeStudentT javaTypejava.util.Listresult propertyid columnsid/result propertyname columnsname/result propertytid columntid//collection/resultMap!--2、按照查询嵌套处理--select idgetTeacher2 resultMapTeacherStudent2select * from tb_teacher where id #{tid}/selectresultMap idTeacherStudent2 typeTeacherTresult propertyid columnid/collection propertystudentTs javaTypejava.util.List ofTypeStudentT selectgetStudentByTeacherId columnid//resultMapselect idgetStudentByTeacherId resultTypeStudentTselect * from tb_student where tid #{tid}/select/mapper5、测试单元 /*** description: 1、 按结果嵌套查询 一对多* author: zhengyuzhu* date: 2023/11/22 23:07**/Testpublic void testDemo3(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();TeacherMapper teacherMapper sqlSession.getMapper(TeacherMapper.class);TeacherT teacher teacherMapper.getTeacherById(1);System.out.println(teacher);sqlSession.close();/*** 输出如下*[org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1486566962.[com.zyz.mybatis.mapper.TeacherMapper.getTeacherById]- Preparing: select t.id id, t.name tname, s.id sid,s.name sname,s.tid tid from tb_teacher t join tb_student s on t.id s.tid;[com.zyz.mybatis.mapper.TeacherMapper.getTeacherById]- Parameters:[com.zyz.mybatis.mapper.TeacherMapper.getTeacherById]- Total: 8TeacherT(id1, name玉小刚, studentTs[StudentT(id1, name唐三, tid1),StudentT(id2, name小舞, tid1),StudentT(id3, name戴沐白, tid1),StudentT(id4, name朱朱清, tid1),StudentT(id5, name奥斯卡, tid1),StudentT(id6, name宁荣荣, tid1),StudentT(id7, name马红俊, tid1),StudentT(id8, name白尘香, tid1)])[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection589b3632]***/}/*** description: 2、 按照查询嵌套处理 一对多* author: zhengyuzhu* date: 2023/11/22 23:07**/Testpublic void testDemo4(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();TeacherMapper teacherMapper sqlSession.getMapper(TeacherMapper.class);TeacherT teacher teacherMapper.getTeacher2(1);System.out.println(teacher);sqlSession.close();/*** 输出如下*[org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1486566962.[com.zyz.mybatis.mapper.TeacherMapper.getTeacher2]- Preparing: select * from tb_teacher where id ?[com.zyz.mybatis.mapper.TeacherMapper.getTeacher2]- Parameters: 1(Integer)[com.zyz.mybatis.mapper.TeacherMapper.getStudentByTeacherId]- Preparing: select * from tb_student where tid ?[com.zyz.mybatis.mapper.TeacherMapper.getStudentByTeacherId]- Parameters: 1(Integer)[com.zyz.mybatis.mapper.TeacherMapper.getStudentByTeacherId]- Total: 8[com.zyz.mybatis.mapper.TeacherMapper.getTeacher2]- Total: 1TeacherT(id1, name玉小刚, studentTs[StudentT(id1, name唐三, tid1),StudentT(id2, name小舞, tid1),StudentT(id3, name戴沐白, tid1),StudentT(id4, name朱朱清, tid1),StudentT(id5, name奥斯卡, tid1),StudentT(id6, name宁荣荣, tid1),StudentT(id7, name马红俊, tid1),StudentT(id8, name白尘香, tid1)])[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection589b3632]***/}12、动态SQL
所谓的动态SQL本质还是SQL语句只是我们可以在SQL层面去执行一个逻辑代码 什么是动态SQL动态SQL就是 指根据不同的条件生成不同的SQL语句 查询搜索的时候用的多
12.1 搭建环境
大致过程 ● 1、创建数据表 ● 2、新建实体类 ● 3、编写实体类对应Mapper接口 ● 4、和Mapper.XML文件 ● 5、修改mybatis 核心配置文件 ● 6、测试单元
1、创建数据表
CREATE TABLE blog (id int(10) NOT NULL COMMENT 博客id,title varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 博客标题,author varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 博客作者,create_time varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 创建时间,views int(30) NOT NULL COMMENT 浏览量
) ENGINE InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT Dynamic;2、创建 Blog 实体类
Data //getset
NoArgsConstructor //无参构造
AllArgsConstructor //有参构造
public class Blog {private String id;private String title;private String author;private Date createTime; //属性名和字段名不一致private int views;
}3、编写实体类对应Mapper接口
/*** author zyz* version 1.0* data 2023/11/23 11:18* Description:*/
public interface BlogMapper {/*** description: IF的使用 查询博客* author: zhengyuzhu* date: 2023/11/23 11:27* param: map* return: com.zyz.mybatis.entity.Blog**/Blog queryBlogIF(HashMapString,Object map);/*** description: choose (when, otherwise)的使用 查询博客* author: zhengyuzhu* date: 2023/11/23 11:30* param: map * return: com.zyz.mybatis.entity.Blog**/Blog queryBlogChoose(HashMapString,Object map);/*** description: trim (where, set)的使用 查询* author: zhengyuzhu* date: 2023/11/23 11:34* param: map * return: com.zyz.mybatis.entity.Blog**/Blog queryBlogIFTwo(HashMapString,Object map);/*** description: trim (where, set)的使用 修改* author: zhengyuzhu* date: 2023/11/23 11:35* param: map **/void updateBlog(HashMapString,Object map);/*** description: Foreach 的使用* author: zhengyuzhu* date: 2023/11/23 14:02* param: map * return: java.util.Listcom.zyz.mybatis.entity.Blog**/ListBlog queryBlogForeach(HashMapString,Object map);/*** description: IF的使用 使用代码片段* author: zhengyuzhu* date: 2023/11/23 11:27* param: map* return: com.zyz.mybatis.entity.Blog**/Blog queryBlogIFThree(HashMapString,Object map);}4、修改mybatis 核心配置文件 !-- 1、使用映射器 --mappersmapper resourcecom/zyz/mybatis/mapper/BlogMapper.xml//mappers具体的动态SQL 编写以及具体的 测试单元分成如下小节
12.2 IF
mapper.xml 文件 由于 实体类 和 数据库 字段不一致这里进行了映射 !-- 结果集映射 --resultMap idBlogMap typeBlog!--column数据库中的字段property实体类中的属性--result columnid propertyid /result columntitle propertytitle /result columnauthor propertyauthor /result columncreate_time propertycreateTime /result columnviews propertyviews //resultMap!--IF的使用 查询博客--select idqueryBlogIF parameterTypemap resultMapBlogMapselect * from blog where 11if testtitle ! nulland title #{title}/ifif testauthor ! nulland author #{author}/if/select测试单元
/*** description: IF 测试* author: zhengyuzhu* date: 2023/11/23 12:46**/
Test
public void testDemo1(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();BlogMapper blogMapper sqlSession.getMapper(BlogMapper.class);HashMapString, Object blogMap new HashMap();blogMap.put(title,张麻子娶亲);blogMap.put(author,张老头);Blog blog blogMapper.queryBlogIF(blogMap);//查询System.out.println(blog);sqlSession.close();/***** blogMap.put(title,张麻子娶亲);* blogMap.put(author,张老头);** 查询条件两个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 846947180.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Preparing: select * from blog where 11 and title ? and author ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Parameters: 张麻子娶亲(String), 张老头(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection327b636c]*** blogMap.put(title,张麻子娶亲);* 查询条件一个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1172131546.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Preparing: select * from blog where 11 and title ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Parameters: 张麻子娶亲(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection45dd4eda]******/
}12.3 choose (when, otherwise)
mapper.xml 文件 这里也进行了结果集映射如上
!--choose (when, otherwise)的使用 查询博客--
select idqueryBlogChoose parameterTypemap resultMapBlogMapselect * from blogwherechoosewhen testtitle ! nulltitle #{title}/whenwhen testauthor ! nulland author #{author}/whenotherwiseand views #{views}/otherwise/choose/where
/select测试单元 /*** description: choose 测试 when otherwise* author: zhengyuzhu* date: 2023/11/23 13:34**/Testpublic void testDemo2(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();BlogMapper blogMapper sqlSession.getMapper(BlogMapper.class);HashMapString, Object blogMap new HashMap();// blogMap.put(title,张麻子娶亲);// blogMap.put(author,张老头);blogMap.put(views,30);Blog blog blogMapper.queryBlogChoose(blogMap);System.out.println(blog);sqlSession.close();/**** 1、多个参数不会拼接哪个有值 用哪个** blogMap.put(title,张麻子娶亲);* blogMap.put(author,张老头);** 查询条件两个 但是拼接的时候 第一个有值就不会在拼接接下来的数据** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 846947180.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Preparing: select * from blog WHERE title ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Parameters: 张麻子娶亲(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection327b636c]*** blogMap.put(author,张老头);* 2、查询条件一个输出如下*[org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1172131546.[com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Preparing: select * from blog WHERE author ?[com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Parameters: 张老头(String)[com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Total: 1Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection45dd4eda]**** 3、查询条件 一个 都不满足情况 otherwise* blogMap.put(views,30);** [com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Preparing: select * from blog WHERE views ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Parameters: 30(Integer)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogChoose]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection45dd4eda]***/}12.4 trim (where, set)
mapper.xml 文件 这里也进行了结果集映射如上 !--trim (where, set)的使用 查询--select idqueryBlogIFTwo parameterTypemap resultMapBlogMapselect * from blogwhereif testtitle ! nulland title #{title}/ifif testauthor ! nulland author #{author}/if/where/select!--trim (where, set)的使用 修改--update idupdateBlog parameterTypemapupdate blogsetif testtitle ! nulltitle #{title},/ifif testauthor ! nullauthor #{author}/if/setwhere id #{id}/update测试单元
/*** description: trim (where, set)的使用 查询* author: zhengyuzhu* date: 2023/11/23 13:36**/
Test
public void testDemo3(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();BlogMapper blogMapper sqlSession.getMapper(BlogMapper.class);HashMapString, Object blogMap new HashMap();blogMap.put(title,张麻子娶亲);blogMap.put(author,张老头);Blog blog blogMapper.queryBlogIFTwo(blogMap);//查询System.out.println(blog);sqlSession.close();/***** blogMap.put(title,张麻子娶亲);* blogMap.put(author,张老头);* 查询条件两个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 846947180.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Preparing: select * from blog WHERE title ? and author ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Parameters: 张麻子娶亲(String), 张老头(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection327b636c]*** blogMap.put(title,张麻子娶亲);* 查询条件一个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1172131546.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Preparing: select * from blog where 11 and title ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Parameters: 张麻子娶亲(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection45dd4eda]******/
}/*** description: trim (where, set)的使用 修改* author: zhengyuzhu* date: 2023/11/23 13:36**/
Test
public void testDemo4(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();BlogMapper blogMapper sqlSession.getMapper(BlogMapper.class);HashMapString, Object blogMap new HashMap();blogMap.put(title,张麻子娶亲);blogMap.put(author,张老头);Blog blog blogMapper.queryBlogIFTwo(blogMap);//查询System.out.println(修改前的数据: blog);HashMapString, Object blogMapTwo new HashMap();blogMapTwo.put(id,1);blogMapTwo.put(title,如何学号java ?);blogMapTwo.put(author,小明);Blog blog1 new Blog();blog1.setAuthor(如何学号java ?);blog1.setAuthor(小明);blogMapper.updateBlog(blogMapTwo);//修改HashMapString, Object blogMap3 new HashMap();blogMap3.put(title,如何学号java ?);Blog blog2 blogMapper.queryBlogIFTwo(blogMap3);//查询System.out.println(修改后的数据: blog2);sqlSession.close();/***** blogMapTwo.put(id,1);* blogMapTwo.put(title,如何学号java ?);* blogMapTwo.put(author,小明);* 查询条件两个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 846947180.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Preparing: select * from blog WHERE title ? and author ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Parameters: 张麻子娶亲(String), 张老头(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Total: 1* 修改前的数据:Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [com.zyz.mybatis.mapper.BlogMapper.updateBlog]- Preparing: update blog SET title ?, author ? where id ?* [com.zyz.mybatis.mapper.BlogMapper.updateBlog]- Parameters: 如何学号java ?(String), 小明(String), 1(Integer)* [com.zyz.mybatis.mapper.BlogMapper.updateBlog]- Updates: 1* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Preparing: select * from blog WHERE title ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Parameters: 如何学号java ?(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIFTwo]- Total: 1* 修改后的数据:Blog(id1, title如何学号java ?, author小明, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection327b636c]*****/
}12.5 foreach
更详细的资料参考mybatis之foreach用法 foreach元素的属性主要有itemindexcollectionopenseparatorclose。 ● item集合中元素迭代时的别名该参数为必选。 ● index在list和数组中,index是元素的序号在map中index是元素的key该参数可选 ● openforeach代码的开始符号一般是(和close)“合用。常用在in(),values()时。该参数可选 ● separator元素之间的分隔符例如在in()的时候separator”,“会自动在元素中间用“,“隔开避免手动输入逗号导致sql错误如in(1,2,)这样。该参数可选。 ● close: foreach代码的关闭符号一般是)和open”(合用。常用在in(),values()时。该参数可选。 ● collection: 要做foreach的对象作为入参时List对象默认用list代替作为键数组对象有array代替作为键Map对象没有默认的键。当然在作为入参时可以使用Param(“keyName”)来设置键设置keyName后list,array将会失效。 除了入参这种情况外还有一种作为参数对象的某个字段的时候。举个例子如果User有属性List ids。入参是User对象那么这个collection “ids”.如果User有属性Ids ids;其中Ids是个对象Ids有个属性List id;入参是User对象那么collection “ids.id” 在使用foreach的时候最关键的也是最容易出错的就是collection属性该属性是必须指定的但是在不同情况下该属性的值是不一样的主要有一下3种情况 ● 如果传入的是单参数且参数类型是一个List的时候collection属性值为list . ● 如果传入的是单参数且参数类型是一个array数组的时候collection的属性值为array . ● 如果传入的参数是多个的时候我们就需要把它们封装成一个Map了当然单参数也可以封装成map实际上如果你在传入参数的时候在MyBatis里面也是会把它封装成一个Map的map的key就是参数名所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key. 针对最后一条我们来看一下官方说法 注意 你可以将一个 List 实例或者数组作为参数对象传给 MyBatis当你这么做的时候MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以“list”作为键而数组实例的键将是“array”。 所以不管是多参数还是单参数的list,array类型都可以封装为map进行传递。如果传递的是一个List则mybatis会封装为一个list为keylist值为object的map如果是array则封装成一个array为keyarray的值为object的map如果自己封装呢则colloection里放的是自己封装的map里的key值。
mapper.xml 文件 这里也进行了结果集映射 !--foreach元素的属性主要有itemindexcollectionopenseparatorclose。● item集合中元素迭代时的别名该参数为必选。● index在list和数组中,index是元素的序号在map中index是元素的key该参数可选● openforeach代码的开始符号一般是(和close)合用。常用在in(),values()时。该参数可选● separator元素之间的分隔符例如在in()的时候separator,会自动在元素中间用“,“隔开避免手动输入逗号导致sql错误如in(1,2,)这样。该参数可选。● close: foreach代码的关闭符号一般是)和open(合用。常用在in(),values()时。该参数可选。● collection: 要做foreach的对象作为入参时List对象默认用list代替作为键数组对象有array代替作为键Map对象没有默认的键。当然在作为入参时可以使用Param(keyName)来设置键设置keyName后list,array将会失效。 除了入参这种情况外还有一种作为参数对象的某个字段的时候。举个例子如果User有属性List ids。入参是User对象那么这个collection ids.如果User有属性Ids ids;其中Ids是个对象Ids有个属性List id;入参是User对象那么collection ids.idselect * from blog where 11 and (id1 or id2 or id3)我们现在传递一个万能的map这map中可以存在一个集合--select idqueryBlogForeach parameterTypemap resultMapBlogMapselect * from blogwhereforeach collectionids itemid openand ( close) separatororid #{id}/foreach/where/select测试单元 /*** description: Foreach 的使用* author: zhengyuzhu* date: 2023/11/23 14:03**/Testpublic void testDemo5(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();BlogMapper blogMapper sqlSession.getMapper(BlogMapper.class);ArrayListObject idList new ArrayList();idList.add(1);idList.add(2);idList.add(3);HashMapString, Object blogMap new HashMap();blogMap.put(ids,idList);ListBlog blogList blogMapper.queryBlogForeach(blogMap);//查询for(Blog blog : blogList){System.out.println(blog);}sqlSession.close();/***** 查询条件两个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 360062456.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogForeach]- Preparing: select * from blog WHERE ( id ? or id ? or id ? )* [com.zyz.mybatis.mapper.BlogMapper.queryBlogForeach]- Parameters: 1(Integer), 2(Integer), 3(Integer)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogForeach]- Total: 3* Blog(id1, title如何学号java ?, author小明, createTime2023-11-23 00:00:00, views30)* Blog(id2, title张麻子学java, author李老头, createTime2023-11-22 00:00:00, views560)* Blog(id3, title张麻子学数据库, author米老头, createTime2023-11-22 00:00:00, views760)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection15761df8]*****/}12.5 代码片段复用
有的时候我们可以能会将一些功能的部分抽取出来方便复用
使用SQL标签抽取公共的部分 sql idif-title-authorif testtitle ! nulltitle #{title}/ifif testauthor ! nulland author #{author}/if/sql在需要使用的地方使用Include标签引用即可 这里有对结果集进行映射
!--复用 SQL代码片段的方式--
select idqueryBlogIFThree parameterTypemap resultMapBlogMapselect * from blogwhereinclude refidif-title-author/include/where
/select测试单元 /*** description: IF 的使用 复用代码片段* author: zhengyuzhu* date: 2023/11/23 14:33 **/Testpublic void testDemo6(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();BlogMapper blogMapper sqlSession.getMapper(BlogMapper.class);HashMapString, Object blogMap new HashMap();blogMap.put(title,张麻子娶亲);blogMap.put(author,张老头);Blog blog blogMapper.queryBlogIF(blogMap);//查询System.out.println(blog);sqlSession.close();/***** blogMap.put(title,张麻子娶亲);* blogMap.put(author,张老头);** 查询条件两个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 846947180.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Preparing: select * from blog where 11 and title ? and author ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Parameters: 张麻子娶亲(String), 张老头(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection327b636c]*** blogMap.put(title,张麻子娶亲);* 查询条件一个输出如下** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1172131546.* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Preparing: select * from blog where 11 and title ?* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Parameters: 张麻子娶亲(String)* [com.zyz.mybatis.mapper.BlogMapper.queryBlogIF]- Total: 1* Blog(id1, title张麻子娶亲, author张老头, createTime2023-11-23 00:00:00, views30)* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection45dd4eda]******/}13、缓存
13.1 简介
1、什么是缓存[Cache] ● 存在内存中的临时数据。 ● 将用户经常查询的数据放在缓存内存中用户去查询数据就不用从磁盘上关系型数据库查询文件查询从缓存中查询从而提高查询效率解决了高并发系统的性能问题。 为什么使用缓存 ● 减少和数据库的交互次数减少系统开销提高系统效率。 什么样的数据能使用缓存 ● 经常查询并且不经常改变的数据。【可以使用缓存】
资料参考mybatis一级缓存二级缓存 MYSQL缓存一级缓存和二级缓存
13.2 Mybatis缓存
● Mybatis包含一个非常强大的查询缓存特性它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。 ● Mybatis系统中默认定义了两级缓存一级缓存和二级缓存 1、默认情况下只有一级缓存开启。SqlSession级别的缓存也称为本地缓存 2、二级缓存需要手动开启和配置它是基于namespace级别的缓存。 3、为了提高扩展性Mybatis定义了缓存接口Cache我们可以通过实现Cache接口来自 定义二级缓存。
13.2.1 一级缓存
13.2.1.1 原理说明
Mybatis对缓存提供支持但是在没有配置的默认情况下它只开启一级缓存一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下我们使用同一个SqlSession对象调用一个Mapper方法往往只执行一次SQL因为使用SelSession第一次查询后MyBatis会将其放在缓存中以后再查询的时候如果没有声明需要刷新并且缓存没有超时的情况下SqlSession都会取出当前缓存的数据而不会再次发送SQL到数据库。
为什么要使用一级缓存不用多说也知道个大概。但是还有几个问题我们要注意一下。 1、一级缓存的生命周期有多长 a、MyBatis在开启一个数据库会话时会 创建一个新的SqlSession对象SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象当会话结束时SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。 b、如果SqlSession调用了close()方法会释放掉一级缓存PerpetualCache对象一级缓存将不可用。 c、如果SqlSession调用了clearCache()会清空PerpetualCache对象中的数据但是该对象仍可使用。 d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) 都会清空PerpetualCache对象的数据但是该对象可以继续使用 2、怎么判断某两次查询是完全相同的查询 mybatis认为对于两次查询如果以下条件都完全一样那么就认为它们是完全相同的两次查询。 2.1 传入的statementId 2.2 查询时要求的结果集中的结果范围 2.3. 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串boundSql.getSql() 2.4 传递给java.sql.Statement要设置的参数值
13.2.1.2 缓存成功
测试步骤
开启日志测试在一个Session中查询两次相同记录查看日志输出 /*** description: 测试缓存 同一个session 连续查询两次* author: zhengyuzhu* date: 2023/11/23 15:02**/Testpublic void test07(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student student studentMapper.queryStudentById(1);System.out.println(student);System.out.println(-----------------);Student student1 studentMapper.queryStudentById(1);System.out.println(student1);//关闭SqlSessionsqlSession.close();/*** 只进行了一次查询 输出如下 :** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 341748265.* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* Student{stuNo1, stuName张三, cardID1115, classID1}* -----------------* Student{stuNo1, stuName张三, cardID1115, classID1}* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]***/}13.2.1.3 缓存失效的情况
一级缓存失效的情况
查询不同的东西增删改操作可能会改变原来的数据所以必定会刷新缓存查询不同的Mapper.xml手动清理缓存 /*** description: 测试缓存失效的情况 1、进行不同的数据查询* author: zhengyuzhu* date: 2023/11/23 15:02**/Testpublic void test08(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student student studentMapper.queryStudentById(1);System.out.println(student);System.out.println(-----------------);Student student1 studentMapper.queryStudentById(2);System.out.println(student1);//关闭SqlSessionsqlSession.close();/*** 1、查询不同的数据的时候缓存会失效** [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection* [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 341748265.* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* Student{stuNo1, stuName张三, cardID1115, classID1}* -----------------* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 2(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* Student{stuNo2, stuName李四, cardID1116, classID2}* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]***/}/*** description: 测试缓存失效的情况 2、进行了删除或者修改操作* author: zhengyuzhu* date: 2023/11/23 15:02**/Testpublic void test09(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student student1 studentMapper.queryStudentById(1);System.out.println(修改前数据 student1);System.out.println(-----------------);Student student new Student();student.setStuNo(1);student.setStuName(张麻子666);student.setClassID(8);student.setCardID(8);studentMapper.updateStudent(student); //修改System.out.println(-----------------);Student student2 studentMapper.queryStudentById(1);System.out.println(修改后数据 student2);//关闭SqlSessionsqlSession.close();/*** 1、查询相同的数据但是中间进行了修改操作** [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection* [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 341748265.* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* 修改前数据Student{stuNo1, stuName张三, cardID1115, classID1}* -----------------* [com.zyz.mybatis.mapper.StudentMapper.updateStudent]- Preparing: update student set stuNo ?, stuName ?, cardid ?, classid ? where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.updateStudent]- Parameters: 1(Integer), 张麻子666(String), 8(Integer), 8(Integer), 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.updateStudent]- Updates: 1* -----------------* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* 修改后数据Student{stuNo1, stuName张麻子666, cardID8, classID8}* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Rolling back JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]***/}手动清理缓存 sqlSession.clearCache(); //手动清除缓存 /*** description: 手动清除缓存 缓存失效。查询两次* author: zhengyuzhu* date: 2023/11/23 15:21**/
Test
public void test10(){//第一步获得SqlSession对象SqlSession sqlSession MybatisUtils.getSqlSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student student studentMapper.queryStudentById(1);System.out.println(student);System.out.println(-----------------);sqlSession.clearCache(); //手动清除缓存Student student1 studentMapper.queryStudentById(1);System.out.println(student1);//关闭SqlSessionsqlSession.close();/*** 1、同一个连接连续两次查询。第二次查询拿缓存数据** [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 341748265.* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* Student{stuNo1, stuName张三, cardID1115, classID1}* -----------------* Student{stuNo1, stuName张三, cardID1115, classID1}* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]**** 2、手动清除缓存** [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection* [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 341748265.* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* Student{stuNo1, stuName张三, cardID1115, classID1}* -----------------* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* Student{stuNo1, stuName张三, cardID1115, classID1}* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection145eaa29]***/}扩展
Testpublic void test01() throws IOException {SqlSessionFactory sqlSessionFactory getSqlSessionFactory();SqlSession session sqlSessionFactory.openSession();EmployeeMapper mapper session.getMapper(EmployeeMapper.class);try {Employee map mapper.getEmployeeById(1);session.clearCache();Employee map2 mapper.getEmployeeById(1);System.out.println(map map2);session.commit();} finally {session.close();}}输出结果为false. 因为手动清清除缓存缓存失效
13.2.2 二级缓存
13.2.2.1 原理说明
MyBatis的二级缓存是Application级别的缓存它可以提高对数据库查询的效率以提高应用的性能。
SqlSessionFactory层面上的二级缓存默认是不开启的二级缓存的开席需要进行配置实现二级缓存的时候MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口配置方法很简单只需要在映射XML文件配置就可以开启缓存了如果我们配置了二级缓存就意味着 ● 映射语句文件中的所有select语句将会被缓存。 ● 映射语句文件中的所欲insert、update和delete语句会刷新缓存。 ● 缓存会使用默认的Least Recently UsedLRU最近最少使用的算法来收回。 ● 根据时间表比如No Flush Interval,CNFI没有刷新间隔缓存不会以任何时间顺序来刷新。 ● 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用 ● 缓存会被视为是read/write(可读/可写)的缓存意味着对象检索不是共享的而且可以安全的被调用者修改不干扰其他调用者或线程所做的潜在修改。
13.2.2.1 详细说明
详细说明 二级缓存全局缓存基于namespace级别的缓存。一个namespace对应一个二级缓存。 工作机制1.一个会话查询一条数据这个数据会被放在当前会话的一级缓存中。 2,如果会话被关闭了一级缓存中的数据会被保存带二级缓存。新的会话查询信息就会参照二级缓存。 3.sqlSession Employeeemployee sqlSession DepartmentMapperDepartment 不同的namespace查出的数据会放在自己对应的缓存中。 效果查出的数据首先放在一级缓存中只有一级缓存被关闭或者提交以后一级缓存数据才会转移到二级缓存 使用步骤 1.开启全局缓存配置。 2.因为是namespace级别需要搭配每个xxxMapper.xml中配置二级缓存
cache flushInterval60000 size512 readOnlytrue evictionFIFO type /
eviction缓存的回收策略
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval缓存刷新间隔。缓存多久清空一次默认不清空。设置一个毫秒值。
readOnly是否只读。truemybatis认为所有从缓存中获取数据的操作都是只读操作不会修改数据。
mybatis为了加快获取速度直接就会将数据在缓存中的引用交给用户。不安全速度快。falsemybatis觉得获取的数据可能被修改。mybatis会利用序列化和反序列化的技术克隆一份新的数据给用户。安全速度快。
size缓存放多少元素。
type指定自定义缓存全类名。实现cache接口即可。
3.pojo需要实现序列换接口。
和缓存相关的配置/属性
1.cacheEnabled如果是false,关闭二级缓存不关闭一级缓存。
2.每个select标签都有userCachetrue属性对一级缓存没有影响。设置为false,二级缓存失效。
3.每个增删改标签都有flushCachetrue属性一级缓存和二级缓存都会被清空。
4.在查询标签中flushCachefalse属性如果设置为true,查完会清空一级二级缓存都会被清空都不会用缓存。
5.sqlSession.clearn()跟session有关只会清除一级缓存。
6.localCacheScopesettingssetting namelocalCacheScope valueSESSION//settings本地缓存作用域。一级缓存SESSION当前会话的所有数据保存到回话缓存中。STATEMENT禁用一级缓存。
缓存首先一进来去查二级缓存二级缓存没有去找一级缓存一级缓存没有去找数据库。二级缓存-----一级缓存--------数据库。 自定义缓存 implements Cache,重写接口中的保存等方法比如说保存到redis.
13.2.2.2 测试案例
步骤
在mybatis-config.xml开启全局缓存 settingssetting namecacheEnabled valuetrue//settings在要使用二级缓存的Mapper中开启 !--在当前Mapper.xml中使用二级缓存--cache/
也可以自定义参数!--开启本mapper的namespace下的二级缓存--!--eviction:代表的是缓存回收策略目前MyBatis提供以下策略。(1) LRU,最近最少使用的一处最长时间不用的对象(2) FIFO,先进先出按对象进入缓存的顺序来移除他们(3) SOFT,软引用移除基于垃圾回收器状态和软引用规则的对象(4) WEAK,弱引用更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU移除最长时间不用的对形象flushInterval:刷新间隔时间单位为毫秒这里配置的是100秒刷新如果你不配置它那么当SQL被执行的时候才会去刷新缓存。size:引用数目一个正整数代表缓存最多可以存储多少个对象不宜设置过大。设置过大会导致内存溢出。这里配置的是1024个对象readOnly:只读意味着缓存数据只能读取而不能修改这样设置的好处是我们可以快速读取缓存缺点是我们没有办法修改缓存他的默认值是false不允许我们修改--cache evictionLRU flushInterval100000 readOnlytrue size1024/!--在当前Mapper.xml中使用二级缓存1、默认:cache/2、自定义参数 cache evictionFIFO flushInterval60000 size512 readOnlytrue/--测试
问题如果没有自定义参数则会报错我们需要将实体类序列化 Cause: java.io.NotSerializableException: com.zyz.mybatis.entity.Student 小结 ● 只要开启了二级缓存在同一个Mapper下就有效 ● 所有的数据都会先放在一级缓存中 ● 只有当会话提交或者关闭的时候才会提交到二级缓存中
单元测试 一定要提交或者关闭 /*** description: 二级缓存 创建两个sqlSession* author: zhengyuzhu* date: 2023/11/23 15:51**/Testpublic void test11(){SqlSessionFactory sqlSessionFactory null;try {//使用Mybatis第一步获取sqlSessionFactory对象String resource mybatis-config.xml;InputStream inputStream Resources.getResourceAsStream(resource);sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream);} catch (Exception e) {e.printStackTrace();}//第一步获得SqlSession对象SqlSession sqlSession sqlSessionFactory.openSession();//方式一getMapperStudentMapper studentMapper sqlSession.getMapper(StudentMapper.class);Student student1 studentMapper.queryStudentById(1);System.out.println(第1次查询 student1);Student student2 studentMapper.queryStudentById(1);System.out.println(第2次查询 student2);// 效果查出的数据首先放在一级缓存中只有一级缓存被关闭或者提交以后// 一级缓存数据才会转移到二级缓存sqlSession.commit();System.out.println(二级缓存观测点);SqlSession sqlSession2 sqlSessionFactory.openSession();StudentMapper studentMapper2 sqlSession2.getMapper(StudentMapper.class);Student student3 studentMapper2.queryStudentById(1);System.out.println(第一次执行: student3);Student student4 studentMapper2.queryStudentById(1);System.out.println(第2次执行: student4);sqlSession2.commit();System.out.println(四个对象是否相同 ((student1 student2) (student3 student4) (student1 student4)));//关闭SqlSessionsqlSession.close();sqlSession2.close();/*** 二级缓存开启** [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection* [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 921760190.* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection36f0f1be]* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Preparing: select * from student where stuNo ?* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Parameters: 1(Integer)* [com.zyz.mybatis.mapper.StudentMapper.queryStudentById]- Total: 1* 第1次查询Student{stuNo1, stuName张三, cardID1115, classID1}* [com.zyz.mybatis.mapper.StudentMapper]-Cache Hit Ratio [com.zyz.mybatis.mapper.StudentMapper]: 0.0* 第2次查询Student{stuNo1, stuName张三, cardID1115, classID1}* 二级缓存观测点* [com.zyz.mybatis.mapper.StudentMapper]-Cache Hit Ratio [com.zyz.mybatis.mapper.StudentMapper]: 0.3333333333333333* 第一次执行:Student{stuNo1, stuName张三, cardID1115, classID1}* [com.zyz.mybatis.mapper.StudentMapper]-Cache Hit Ratio [com.zyz.mybatis.mapper.StudentMapper]: 0.5* 第2次执行:Student{stuNo1, stuName张三, cardID1115, classID1}* 四个对象是否相同true* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection36f0f1be]* [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection36f0f1be]**/}