2022尚硅谷SSM框架跟学(三)MyBatis基础三
创始人
2024-05-08 23:48:09
0

2022尚硅谷SSM框架跟学 三 MyBatis基础三

      • 9.动态SQL
        • 9.1if
        • 9.2where
          • 方法一:加入恒成立的条件
          • 方法二:使用where标签
        • 9.3trim
        • 9.4choose、when、otherwise
        • 9.5foreach
          • 9.51批量添加
          • 9.52批量删除
            • 批量删除方式1
            • 批量删除方式2
            • 批量删除方式3
        • 9.6SQL片段
      • 10.MyBatis的缓存
        • 10.1MyBatis的一级缓存
        • 10.2MyBatis的二级缓存
        • 10.3二级缓存的相关配置
        • 10.4MyBatis缓存查询的顺序
        • 10.5整合第三方缓存EHCache
          • 10.5.1添加依赖
          • 10.5.2各jar包功能
          • 10.5.3创建EHCache的配置文件ehcache.xml
          • 10.5.4设置二级缓存的类型
          • 10.5.5加入logback日志
          • 10.5.6EHCache配置文件说明
      • 11.MyBatis的逆向工程
        • 11.1创建逆向工程的步骤
          • (1)添加依赖和插件
          • (2)创建MyBatis的核心配置文件
          • (3)创建逆向工程的配置文件
          • (4)执行MBG插件的generate目标
          • (5)效果
        • 11.2QBC查询
          • 测试根据主键查询
          • 测试无条件查询
          • 测试根据条件查询
          • 多条件查询
            • 多个and查询
            • 多个or查询
          • 选择性修改
          • 普通修改
      • 12分页插件
        • 12.1分页插件的使用步骤
          • (1)添加依赖
          • (2)配置分页插件
        • 12.2分页插件的使用

9.动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了
解决 拼接SQL语句字符串时的痛点问题。
实例:多个查询条件进行查询,设置了条件的话,就一定要出现在sql中,一定要注意默认值的设置和指定。null和" "(空字符串)

新创建一个Module,这里就不再写具体步骤了,可以参考前几章
配置坐标

GroupId:com.atguigu.mybatis
Name:mybatis-dynamicSQL

配置相关文件
配置相关文件
注意配置核心配置文件mybatis-config.xml的时候要设置setting
驼峰加载


配置pojo的实体类Emp

package com.atguigu.mybatis.pojo;/*** @ClassName: Emp* @Description:* @Author: wty* @Date: 2023/1/7*/public class Emp {private Integer empId;private String empName;private Integer age;private String gender;public Emp() {}public Emp(Integer empId, String empName, Integer age, String gender) {this.empId = empId;this.empName = empName;this.age = age;this.gender = gender;}public Integer getEmpId() {return empId;}public void setEmpId(Integer empId) {this.empId = empId;}public String getEmpName() {return empName;}public void setEmpName(String empName) {this.empName = empName;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}@Overridepublic String toString() {return "Emp{" +"empId=" + empId +", empName='" + empName + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';}
}

9.1if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行

在DynamicSQLMapper.java中添加方法

 /*** @param* @return java.util.List* @description //根据条件查询员工信息* @param: emp* @date 2023/1/7 12:03* @author wty**/List getEmpByCondition(Emp emp);

在DynamicSQLMapper.xml中添加sql

    

创建测试类com.atguigu.mybatis.test.DynamicMapperTest,增加方法

    @Testpublic void getEmpByConditionTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Emp emp = new Emp(1, "张三", 20, "男");List list = mapper.getEmpByCondition(emp);list.forEach(System.out::println);sqlSession.close();}

查询结果
查询结果

9.2where

这里如果把where后面的条件empName置为空,那么再用测试类查询,就是错误的。
报错
同理,如果我们继续蹬鼻子上脸,把后面age和gender都置为空,那么就剩下一个select * from t_emp where的空壳
继续报错
如何解决这些问题呢,我们来看下,有如下方法

方法一:加入恒成立的条件

在DynamicSQLMapper.xml中加入恒成立的条件

    

加入恒成立的条件
继续查询上面那个都是空字段的情况,看结果不报错,查询正确
查询结果

方法二:使用where标签

修改DynamicSQLMapper.xml中的sql子句变为
修改where标签


直接用测试类查询
查询结果
验证了结论:
若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字。

那我们修改一下测试类DynamicMapperTest.java的条件

 @Testpublic void getEmpByConditionTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Emp emp = new Emp(1, "", 20, "");List list = mapper.getEmpByCondition(emp);list.forEach(System.out::println);sqlSession.close();}

更改赋值条件
查询结果:
查询结果
验证了结论:
若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉。

where和if一般结合使用:
a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
b>若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
注意:where标签不能去掉条件最后多余的and

举个例子:如果and放在条件后还可以吗


将and放在后面
更改一下测试类查看结果

@Testpublic void getEmpByConditionTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Emp emp = new Emp(1, "张三", 20, "");List list = mapper.getEmpByCondition(emp);list.forEach(System.out::println);sqlSession.close();}

查看结果:发现报错
查看结果
这种情况我们就可以用以下的trim标签来解决

9.3trim

trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容

修改DynamicSQLMapper.xml
修改

    

运行测试类查看结果
查看测试结果
并且测试一下,条件为空,也可以自动去掉where
自动去掉了where
测试一下,where条件为空,只填充and
填充and

9.4choose、when、otherwise

choose、when、 otherwise相当于if…、else if…、else

在DynamicSQLMapper.java中添加方法

/*** @param* @return java.util.List* @description //使用choose查询员工信息* @param: emp* @date 2023/1/7 13:43* @author wty**/List getEmpByChoose(Emp emp);

修改DynamicSQLMapper.xml

 

在测试类DynamicMapperTest.java中添加方法

@Testpublic void getEmpByChooseTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Emp emp = new Emp(1, "", null, "");List list = mapper.getEmpByChoose(emp);list.forEach(System.out::println);sqlSession.close();}

查看结果
查询结果
要注意,choose,when,otherwise都是选择条件,三个条件一起用,只是会选择第一个进行,剩下的条件就不会跑了,所以不用写and条件。例如:
多个选择
可以看出多个选择条件都可以成立,但是第一个执行后,就不会再跑其它的了。

9.5foreach

比较重要的标签,用于批量添加和批量删除。

9.51批量添加

在DynamicSQLMapper.java中添加方法

 /*** @param* @return int* @description //员工的批量添加* @param: emps* @date 2023/1/7 14:03* @author wty**/int insertMoreEmp(@Param("emps") List emp);

修改DynamicSQLMapper.xml

insert into t_empvalues(null, #{emp.empName}, #{emp.age}, #{emp.gender}, null)

在测试类DynamicMapperTest.java中添加方法

 @Testpublic void insertMoreEmpTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);List list = new ArrayList<>();list.add(new Emp(null, "周七", 29, "男"));list.add(new Emp(null, "朱八", 22, "男"));list.add(new Emp(null, "李九", 23, "女"));int i = mapper.insertMoreEmp(list);System.out.println("插入:" + i + "条数据");sqlSession.close();}

插入结果
插入数据
插入结果

9.52批量删除
批量删除方式1

在DynamicSQLMapper.java中添加方法

    /*** @param* @return int* @description //批量删除* @param: empIds* @date 2023/1/7 14:39* @author wty**/int deleteMoreEmp(@Param("empIds") Integer[] empIds);

修改DynamicSQLMapper.xml

    deletefrom t_empwhere emp_id in(#{empId})

在测试类DynamicMapperTest.java中添加方法

  @Testpublic void deleteMoreEmp() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Integer empIds[] = {5, 6, 7};int i = mapper.deleteMoreEmp(empIds);System.out.println("删除:" + i + "条数据");sqlSession.close();}

查看删除结果:
删除结果
看到3条已经删除了
3条删除了

批量删除方式2

用另一种批量删除的方式,更改DynamicSQLMapper.xml

    deletefrom t_empwhere emp_id in#{empId}

先重新执行一下批量插入的方法。
插入数据

再删除一下,看一下这种方式是否能删除成功。
删除3条数据
删除结果
删除结果

批量删除方式3

修改DynamicSQLMapper.xml

deletefrom t_empwhereemp_id = #{empId}

执行测试类删除方法前,也先执行一下批量插入的方法
插入

执行测试类DynamicMapperTest.java

 @Testpublic void deleteMoreEmp() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Integer empIds[] = {11, 12, 13};int i = mapper.deleteMoreEmp(empIds);System.out.println("删除:" + i + "条数据");sqlSession.close();}

执行结果
结果1
成功删除
总结

foreach标签的属性
collection:设置要循环的数组或者集合
item:用一个字符串表示数组或者集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么开始
close:循环的所有内容以什么结束

9.6SQL片段

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入

在DynamicSQLMapper.java中添加方法

    /*** @param* @return java.util.List* @description //查询所有用户* @date 2023/1/7 15:10* @author wty**/List getAllEmp();

修改DynamicSQLMapper.xml

emp_id,emp_name,age,gender,dept_id

在测试类DynamicMapperTest.java中添加方法

 @Testpublic void getAllEmpTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);List list = mapper.getAllEmp();list.forEach(System.out::println);sqlSession.close();}

查询结果
查询结果
可以看到sql中的字段会在查询的时候调用

10.MyBatis的缓存

10.1MyBatis的一级缓存

MyBatis的一级缓存是默认开启的,创建一个工程就可以直接使用。
创建新的Module

GroupId:com.atguigu.mybatis
Name:mybatis-cache

配置相关信息和参数见前面几章,这里就不赘述了,创建完后工程是这样的:
Module
在CacheMapper.java中添加方法

    /*** @param* @return com.atguigu.mybatis.pojo.Emp* @description //根据员工Id查询员工信息* @param: empId* @date 2023/1/7 16:44* @author wty**/Emp getEmpById(@Param("empId") Integer empId);

在CacheMapper.xml中新加语句

emp_id,emp_name,age,gender,dept_id

在测试类CacheMapperTest.java中添加方法测试

  @Testpublic void getEmpByIdTest() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);Emp emp1 = mapper.getEmpById(4);System.out.println(emp1);Emp emp2 = mapper.getEmpById(4);System.out.println(emp2);sqlSession.close();}

查询结果如下:
查询结果

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

既然一级缓存是SqlSession级别的,那我们来看看是不是这样的。
修改CacheMapperTest.java

@Testpublic void getEmpByIdTest() {SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(4);System.out.println(emp1);Emp emp2 = mapper1.getEmpById(4);System.out.println(emp2);sqlSession1.close();SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);Emp emp3 = mapper2.getEmpById(4);System.out.println(emp3);sqlSession2.close();}

查看结果
结果
可以看到同一个Sqlsession的确再查询第二次时,会使用缓存,而不同的SqlSession查询相同sql的时候,会重新查询,这样就验证了一级缓存是SqlSession级别的。

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

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

针对情况(3)举个例子来理解
在CacheMapper.java中添加方法

 /*** @param* @return int* @description //添加员工信息* @param: emp* @date 2023/1/7 17:08* @author wty**/int insertEmp(Emp emp);

在CacheMapper.xml中新加语句

 insert into t_empvalues (null, #{empName}, #{age}, #{gender}, null)

在测试类CacheMapperTest.java中修改getEmpByIdTest方法测试

 @Testpublic void getEmpByIdTest() {SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(4);System.out.println(emp1);// 如果执行了任意的增删改,则会清空缓存,重新查询Emp emp = new Emp(null, "周七", 29, "男");int i = mapper1.insertEmp(emp);System.out.println("插入了" + i + "条");Emp emp2 = mapper1.getEmpById(4);System.out.println(emp2);sqlSession1.close();}

在2个查询之间进行一次新增操作
测试类
查询结果
结果
结果发现增删改之后,缓存清空,会查询数据库。

针对情况(3)举个例子来理解
修改CacheMapperTest.java中的getEmpByIdTest方法

sqlSession1.clearCache(); // 清理缓存

@Testpublic void getEmpByIdTest() {SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(4);System.out.println(emp1);sqlSession1.clearCache();Emp emp2 = mapper1.getEmpById(4);System.out.println(emp2);sqlSession1.close();}

查看结果
查询数据库

10.2MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
二级缓存开启的条件:
< a >.在核心配置文件中,设置全局配置属性cacheEnabled=“true” ,该属性,默认为true,不需要设置。

    

< b >.在mapper映射文件中设置标签


< c >.二级缓存必须在SqlSession关闭或提交之后有效

sqlSession1.close();

< d >.查询的数据所转换的实体类类型必须实现序列化的接口

public class Emp implements Serializable {}

学习了上面的知识点之后,我们一起来看下二级缓存。
在核心配置文件中添加语句(可以省略)
核心配置文件

        

在CacheMapper.xml中新加语句
添加缓存开启语句
Mapper配置文件
在测试类CacheMapperTest.java中添加方法测试

    @Testpublic void testCache() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);SqlSession sqlSession1 = sqlSessionFactory.openSession(true);CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(1);System.out.println("emp1 =" + emp1);SqlSession sqlSession2 = sqlSessionFactory.openSession(true);CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);Emp emp2 = mapper2.getEmpById(1);System.out.println("emp2 =" + emp2);}

查询结果
数据库
看到查询结果是去数据库查询了2次,说明二级缓存还没有生效,原来是sqlSession我们还没有关闭,那我们关闭一下。

@Testpublic void testCache() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);SqlSession sqlSession1 = sqlSessionFactory.openSession(true);CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(1);System.out.println("emp1 =" + emp1);SqlSession sqlSession2 = sqlSessionFactory.openSession(true);CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);Emp emp2 = mapper2.getEmpById(1);System.out.println("emp2 =" + emp2);sqlSession1.close();sqlSession2.close();}

执行测试类,发现报错。
报错

org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.atguigu.mybatis.pojo.Emp

自定义类Emp没有实现序列化,那我们将Emp进行实现
序列化

快捷产生序列化的版本号
序列化

package com.atguigu.mybatis.pojo;import java.io.Serializable;/*** @ClassName: Emp* @Description:* @Author: wty* @Date: 2023/1/7*/public class Emp implements Serializable {private static final long serialVersionUID = -936807110083368555L;private Integer empId;private String empName;private Integer age;private String gender;public Emp() {}public Emp(Integer empId, String empName, Integer age, String gender) {this.empId = empId;this.empName = empName;this.age = age;this.gender = gender;}public Integer getEmpId() {return empId;}public void setEmpId(Integer empId) {this.empId = empId;}public String getEmpName() {return empName;}public void setEmpName(String empName) {this.empName = empName;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}@Overridepublic String toString() {return "Emp{" +"empId=" + empId +", empName='" + empName + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';}
}

这里更改测试类中的方法

 @Testpublic void testCache() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);SqlSession sqlSession1 = sqlSessionFactory.openSession(true);CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(1);System.out.println("emp1 =" + emp1);sqlSession1.close();SqlSession sqlSession2 = sqlSessionFactory.openSession(true);CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);Emp emp2 = mapper2.getEmpById(1);System.out.println("emp2 =" + emp2);sqlSession2.close();}

查看运行结果
运行结果

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

这样便实现了MyBatis的二级缓存。
而如果想让二级缓存失效我们尝试用增删改放在两次查询的中间
修改CacheMapperTest.java

 @Testpublic void testCache() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);SqlSession sqlSession1 = sqlSessionFactory.openSession(true);CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(1);System.out.println("emp1 =" + emp1);// 二级缓存失效Emp emp = new Emp(null, "朱八", 26, "男");int i = mapper1.insertEmp(emp);System.out.println("插入了" + i + "条");sqlSession1.close();SqlSession sqlSession2 = sqlSessionFactory.openSession(true);CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);Emp emp2 = mapper2.getEmpById(1);System.out.println("emp2 =" + emp2);sqlSession2.close();}

查询结果
查询结果
这第二次查询还是查询了数据库,说明增删改,清空了二级缓存,需要重新查询数据库。

10.3二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:
①eviction属性:缓存回收策略,默认的是 LRU。
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
②flushInterval属性:刷新间隔,单位毫秒。
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 ③size属性:引用数目,正整数。
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
④readOnly属性:只读, true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

10.4MyBatis缓存查询的顺序

从大范围到小范围即(sqlSessionFactory 二级缓存→ SqlSession一级缓存)

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

10.5整合第三方缓存EHCache

10.5.1添加依赖

在pom.xml中添加依赖

org.mybatis.cachesmybatis-ehcache1.2.1ch.qos.logbacklogback-classic1.2.3

简单讲述
简单讲述

10.5.2各jar包功能
jar包名称作用
mybatis-ehcacheMybatis和EHCache的整合包
ehcacheEHCache核心包
slf4j-apiSLF4J日志门面包
logback-classic支持SLF4J门面接口的一个具体实现
10.5.3创建EHCache的配置文件ehcache.xml

创建配置文件




10.5.4设置二级缓存的类型

在CacheMapper.xml中设置
二级缓存


10.5.5加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml

添加包名


[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger][%msg]%n

修改CacheMapperTest.java

 @Testpublic void testCache() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);SqlSession sqlSession1 = sqlSessionFactory.openSession(true);CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);Emp emp1 = mapper1.getEmpById(1);System.out.println("emp1 =" + emp1);sqlSession1.close();SqlSession sqlSession2 = sqlSessionFactory.openSession(true);CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);Emp emp2 = mapper2.getEmpById(1);System.out.println("emp2 =" + emp2);sqlSession2.close();}

查询结果
查询结果
缓存位置
缓存位置

10.5.6EHCache配置文件说明
属性名是否必须作用
maxElementsInMemory在内存中缓存的element的最大数目
maxElementsOnDisk在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断
overflowToDisk设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
timeToIdleSeconds当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMBDiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskPersistent在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔,默认是120秒。每隔120s, 相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU (最近最少使用),可选的有LFU (最不常使用)和FIFO (先进先出)

11.MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类
Mapper接口
Mapper映射文件
注意:逆向工程只能针对单表操作,多表不支持

11.1创建逆向工程的步骤

新创建一个Module

GroupId:com.atguigu.mybatis
Name:mybatis-mbg

创建一个Module

(1)添加依赖和插件

在pom.xml中添加依赖
这里要注意mysql的版本,配置成和自己安装的一致即可。

org.mybatismybatis3.5.7junitjunit4.12testlog4jlog4j1.2.17mysqlmysql-connector-java5.1.20org.mybatis.generatormybatis-generator-maven-plugin1.3.0org.mybatis.generatormybatis-generator-core1.3.2mysqlmysql-connector-java5.1.20

添加打包方式
设置打包方式

jar
(2)创建MyBatis的核心配置文件

创建核心配置文件

(3)创建逆向工程的配置文件

文件名必须是:generatorConfig.xml

逆向工程
这里创建的是MyBatis3Simple: 清新简洁版



(4)执行MBG插件的generate目标

配置完依赖多了插件
插件
双击插件
双击
最后创建成功即可
创建成功

(5)效果

创建成功
看Mapper接口中有5个方法

package com.atguigu.mybatis.mapper;import com.atguigu.mybatis.pojo.Emp;
import java.util.List;public interface EmpMapper {/*** This method was generated by MyBatis Generator.* This method corresponds to the database table t_emp** @mbggenerated Sun Jan 08 13:28:24 CST 2023*/int deleteByPrimaryKey(Integer empId);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table t_emp** @mbggenerated Sun Jan 08 13:28:24 CST 2023*/int insert(Emp record);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table t_emp** @mbggenerated Sun Jan 08 13:28:24 CST 2023*/Emp selectByPrimaryKey(Integer empId);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table t_emp** @mbggenerated Sun Jan 08 13:28:24 CST 2023*/List selectAll();/*** This method was generated by MyBatis Generator.* This method corresponds to the database table t_emp** @mbggenerated Sun Jan 08 13:28:24 CST 2023*/int updateByPrimaryKey(Emp record);
}

下面创建一下MyBatis3: 奢华尊享版
更改generatorConfig.xml

    

创建尊享版
删除逆向工程创建的包和类
删除
重新运行插件
重新运行插件
运行结果,查看
运行结果

11.2QBC查询

创建MBGTest.java测试类
创建测试类
在MBGTest.java中添加方法

测试根据主键查询
 @Testpublic void testMBG() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);Emp emp = mapper.selectByPrimaryKey(1);System.out.println(emp);sqlSession.close();}

执行MBGTest.java结果
在这里插入图片描述
给Emp添加toString()方法
toString()方法
执行结果
执行结果

在MBGTest.java中添加方法——

测试无条件查询
@Testpublic void testMBG1() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);List list = mapper.selectByExample(null);list.forEach(System.out::println);sqlSession.close();}

条件为null的时候,相当于查询全部
查询结果

测试根据条件查询

这里需要创建EmpExample对象
方法
在MBGTest.java中添加方法
根据条件查询:一个叫张三的员工

 @Testpublic void testMBG2() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 根据条件查询:一个叫张三的员工EmpExample empExample = new EmpExample();empExample.createCriteria().andEmpNameEqualTo("张三");List list = mapper.selectByExample(empExample);list.forEach(System.out::println);sqlSession.close();}

查询结果
查询结果

多条件查询
多个and查询

如果我们在员工是张三的基础上,加入查询条件:年龄大于等于20岁,那我们只需要继续在后面拼接即可。
查询

 @Testpublic void testMBG2() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 根据条件查询:一个叫张三的员工EmpExample empExample = new EmpExample();empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);List list = mapper.selectByExample(empExample);list.forEach(System.out::println);sqlSession.close();}

查询结果
多条件

多个or查询

那如果掺杂了or怎么办呢,比如我们需要查询叫张三,年龄大于等于20岁,或者性别是女的员工
修改MBGTest.java类的方法
修改方法

@Testpublic void testMBG2() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 根据条件查询:一个叫张三的员工EmpExample empExample = new EmpExample();empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);empExample.or().andGenderEqualTo("女");List list = mapper.selectByExample(empExample);list.forEach(System.out::println);sqlSession.close();}

查询结果
查询结果

选择性修改

Emp.java添加有参构造
有参构造
在MBGTest.java中添加方法

    @Testpublic void testMBG4() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 根据选择性修改:Emp emp = new Emp(14, "小丽", null, "女");EmpExample empExample = new EmpExample();empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);int i = mapper.updateByPrimaryKeySelective(emp);System.out.println("更新了" + i + "条数据");sqlSession.close();}

因为是选择性修改,null的值不会替换修改
null没有修改

普通修改

在MBGTest.java中添加方法

@Testpublic void testMBG3() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 根据主键修改:Emp emp = new Emp(14, "小美", 26, "女");EmpExample empExample = new EmpExample();empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);int i = mapper.updateByPrimaryKey(emp);System.out.println("更新了" + i + "条数据");sqlSession.close();}

修改结果
修改结果
修改结果

12分页插件

limit index,pageSize
pageSize:每页显示的条数
pageNum:当前页的页码
index:当前页的起始索引,index=(pageNum-1)*pageSize
count:总记录数
totalPage:总页数
totalPage = count / pageSize;
if(count % pageSize != 0){
totalPage += 1;
}
pageSize=4,pageNum=1,index=0 limit 0,4
pageSize=4,pageNum=3,index=8 limit 8,4
pageSize=4,pageNum=6,index=20 limit 20,4
导航分页:
首页 上一页 2 3 4 5 6 下一页 末页

12.1分页插件的使用步骤

(1)添加依赖

在pom.xml中添加依赖

com.github.pagehelperpagehelper5.2.0

添加依赖

(2)配置分页插件

在MyBatis的核心配置文件中配置插件
在mybatis-config.xml中配置
配置拦截器

    

这里的全类名如果不太好找可以使用IDEA自带的全类名搜索:快捷键Ctrl+Shift+a
在搜索栏点选class然后搜索PageInterceptor
搜索
拷贝全类名即可
拷贝全类名
新建测试类PageTest.java来测试分页功能
测试类
去sqlyog中将表t_emp截断,重新插入一些数据,30条

12.2分页插件的使用

< a >在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能。

pageNum:当前页的页码
pageSize:每页显示的条数

在测试类PagTest.java中添加方法

 @Testpublic void testPage() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 分页查询// 开启分页功能PageHelper.startPage(1, 4);List list = mapper.selectByExample(null);list.forEach(System.out::println);sqlSession.close();}

查询结果:
查询结果
分析一下查询结果:
打印一下page值

    @Testpublic void testPage() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 分页查询// list前开启分页功能Page page = PageHelper.startPage(1, 4);List list = mapper.selectByExample(null);list.forEach(System.out::println);System.out.println(page);sqlSession.close();}
 

输出结果:
输出结果
注意Page是继承自ArrayList
在这里插入图片描述
这里可以处结论可以自定义接口返回值Page获取查询结果
自定义接口返回值

< b >在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据。

list:分页之后的数据
navigatePages:导航分页的页码数

修改PageTest.java中的方法

 /*** PageInfo{* pageNum=4, pageSize=4, size=4, 当前是第4页,此页中有4条数据* startRow=13, endRow=16,  当前页的数据是从第13行数据到16条数据* total=30, pages=8, 所有页一共30条数据,一共8页。符合30/4 = 7……2 则总页数是7 + 1 = 8* list=Page{count=true, pageNum=4, pageSize=4, startRow=12, endRow=16, total=30, pages=8, reasonable=false, pageSizeZero=false}[Emp{empId=13, empName='a', age=null, gender='null', deptId=null}, Emp{empId=14, empName='a', age=null, gender='null', deptId=null}, Emp{empId=15, empName='a', age=null, gender='null', deptId=null}, Emp{empId=16, empName='a', age=null, gender='null', deptId=null}],* prePage=3, nextPage=5, 当前页是第4页,所以上一页的页码是3,后一页的页码是5* isFirstPage=false, isLastPage=false, 是否是第一页,是否是最后一夜* hasPreviousPage=true, hasNextPage=true, 是否有上一页,是否有下一页* navigatePages=4, 当前页* navigateFirstPage=2,导航分页的初始页* navigateLastPage=5, 导航分页的最终页* navigatepageNums=[2, 3, 4, 5]}导航分页的页码*/@Testpublic void testPage1() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 分页查询Page page = PageHelper.startPage(4, 4);List list = mapper.selectByExample(null);// list后开启分页功能// navigatePages:导航分页的个数,比如设置4,导航分页就是2,3,4,5// 比如设置5,导航分页是2,3,4,5,6PageInfo pageInfo = new PageInfo<>(list, 5);list.forEach(System.out::println);System.out.println(pageInfo);sqlSession.close();}
 

查询结果:
查询结果
< c >分页相关数据

PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...