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 + '\'' +'}';}
}
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();}
查询结果
这里如果把where后面的条件empName置为空,那么再用测试类查询,就是错误的。
同理,如果我们继续蹬鼻子上脸,把后面age和gender都置为空,那么就剩下一个select * from t_emp where的空壳
如何解决这些问题呢,我们来看下,有如下方法
在DynamicSQLMapper.xml中加入恒成立的条件
继续查询上面那个都是空字段的情况,看结果不报错,查询正确
修改DynamicSQLMapper.xml中的sql子句变为
直接用测试类查询
验证了结论:
若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放在条件后还可以吗
更改一下测试类查看结果
@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标签来解决
trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
修改DynamicSQLMapper.xml
运行测试类查看结果
并且测试一下,条件为空,也可以自动去掉where
测试一下,where条件为空,只填充and
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条件。例如:
可以看出多个选择条件都可以成立,但是第一个执行后,就不会再跑其它的了。
比较重要的标签,用于批量添加和批量删除。
在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();}
插入结果
在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条已经删除了
用另一种批量删除的方式,更改DynamicSQLMapper.xml
deletefrom t_empwhere emp_id in#{empId}
先重新执行一下批量插入的方法。
再删除一下,看一下这种方式是否能删除成功。
删除结果
修改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();}
执行结果
总结
foreach标签的属性
collection:设置要循环的数组或者集合
item:用一个字符串表示数组或者集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么开始
close:循环的所有内容以什么结束
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中的字段会在查询的时候调用
MyBatis的一级缓存是默认开启的,创建一个工程就可以直接使用。
创建新的Module
GroupId:com.atguigu.mybatis
Name:mybatis-cache
配置相关信息和参数见前面几章,这里就不赘述了,创建完后工程是这样的:
在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级别的。
使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存。
- 同一个SqlSession但是查询条件不同。
- 同一个SqlSession两次查询期间执行了任何一次增删改操作。
- 同一个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();}
查看结果
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
二级缓存开启的条件:
< a >.在核心配置文件中,设置全局配置属性cacheEnabled=“true” ,该属性,默认为true,不需要设置。
< b >.在mapper映射文件中设置标签
< c >.二级缓存必须在SqlSession关闭或提交之后有效
sqlSession1.close();
< d >.查询的数据所转换的实体类类型必须实现序列化的接口
public class Emp implements Serializable {}
学习了上面的知识点之后,我们一起来看下二级缓存。
在核心配置文件中添加语句(可以省略)
在CacheMapper.xml中新加语句
添加缓存开启语句
在测试类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();}
查询结果
这第二次查询还是查询了数据库,说明增删改,清空了二级缓存,需要重新查询数据库。
在mapper配置文件中添加的cache标签可以设置一些属性:
①eviction属性:缓存回收策略,默认的是 LRU。
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
②flushInterval属性:刷新间隔,单位毫秒。
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 ③size属性:引用数目,正整数。
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
④readOnly属性:只读, true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
从大范围到小范围即(sqlSessionFactory 二级缓存→ SqlSession一级缓存)
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
在pom.xml中添加依赖
org.mybatis.caches mybatis-ehcache 1.2.1 ch.qos.logback logback-classic 1.2.3
简单讲述
jar包名称 | 作用 |
---|---|
mybatis-ehcache | Mybatis和EHCache的整合包 |
ehcache | EHCache核心包 |
slf4j-api | SLF4J日志门面包 |
logback-classic | 支持SLF4J门面接口的一个具体实现 |
在CacheMapper.xml中设置
存在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();}
查询结果
缓存位置
属性名 | 是否必须 | 作用 |
---|---|---|
maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 |
maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 |
eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 |
overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 |
timeToIdleSeconds | 否 | 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大 |
timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 |
diskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 |
diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每隔120s, 相应的线程会进行一次EhCache中数据的清理工作 |
memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU (最近最少使用),可选的有LFU (最不常使用)和FIFO (先进先出) |
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类
Mapper接口
Mapper映射文件
注意:逆向工程只能针对单表操作,多表不支持
新创建一个Module
GroupId:com.atguigu.mybatis
Name:mybatis-mbg
在pom.xml中添加依赖
这里要注意mysql的版本,配置成和自己安装的一致即可。
org.mybatis mybatis 3.5.7 junit junit 4.12 test log4j log4j 1.2.17 mysql mysql-connector-java 5.1.20 org.mybatis.generator mybatis-generator-maven-plugin 1.3.0 org.mybatis.generator mybatis-generator-core 1.3.2 mysql mysql-connector-java 5.1.20
添加打包方式
jar
文件名必须是:generatorConfig.xml
这里创建的是MyBatis3Simple: 清新简洁版
配置完依赖多了插件
双击插件
最后创建成功即可
看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
删除逆向工程创建的包和类
重新运行插件
运行结果,查看
创建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()方法
执行结果
在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();}
查询结果
如果我们在员工是张三的基础上,加入查询条件:年龄大于等于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怎么办呢,比如我们需要查询叫张三,年龄大于等于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的值不会替换修改
在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();}
修改结果
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 下一页 末页
在pom.xml中添加依赖
com.github.pagehelper pagehelper 5.2.0
在MyBatis的核心配置文件中配置插件
在mybatis-config.xml中配置
这里的全类名如果不太好找可以使用IDEA自带的全类名搜索:快捷键Ctrl+Shift+a
在搜索栏点选class然后搜索PageInterceptor
拷贝全类名即可
新建测试类PageTest.java来测试分页功能
去sqlyog中将表t_emp截断,重新插入一些数据,30条
< 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是继承自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
查询结果:
< 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]