MyBatis 简介
1. MyBatis历史
MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github。
iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。
2. 特性 => 半自动化持久层框架
- MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
- MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old JavaObjects,普通的Java对象)映射成数据库中的记录
- MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架
3. 其它持久化层技术
JDBC
1. SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
2. 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
3. 代码冗长,开发效率低
Hibernate 和 JPA (全自动框架)
1. 操作简便,开发效率高
2. 程序中的长难复杂 SQL 需要绕过框架
3. 内部自动生产的 SQL,不容易做特殊优化
4. 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
5. 反射操作太多,导致数据库性能下降
MyBatis
1. 轻量级,性能出色
2. SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
3. 开发效率稍逊于HIbernate,但是完全能够接受
框架搭建
1. 初始准备
-
MySQL
-
pojo -> User.java
package com.nuo.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @author nuo
* @version 1.0
* @description: TODO
* @date 2022/2/14 20:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private int id;
private String name;
private String pwd;
public User(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
}
2. 引入相关 jar
<dependencies>
<!--测试类使用-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--MyBatis jar-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!--MySQL8 jar-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<!--LomBok jar-->
<!--可用注解代替 Alt + Insert 自动生成getter/setter-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
3. 创建数据库的配置文件 Db.properties
MySQL 不同版本的注意事项
1. 驱动类driver-class-name
MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver
MySQL 8版本使用jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver
2. 连接地址url
MySQL 5版本的url:
jdbc:mysql://localhost:3306/mybatis
MySQL 8版本的url:
jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
username=root
password=123456
4. 创建MyBatis的核心配置文件 mybatis-config.xml
可去官网 v 一份过来,咳咳
官网链接 => MyBatis
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 核心配置文件-->
<configuration>
<!--MyBatis核心配置文件中,标签的顺序:
properties?,settings?,typeAliases?,typeHandlers?,
objectFactory?,objectWrapperFactory?,reflectorFactory?,
plugins?,environments?,databaseIdProvider?,mappers? -->
<!--引入外部配置文件-->
<properties resource="Db.properties"/>
<settings>
<!--数据库的 '_' 默认对应 Java 中的驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--别名的使用-->
<typeAliases>
<!--1.typeAlias-->
<typeAlias type="com.nuo.pojo.User" alias="user"/>
<!--2.package => 适用于 JavaBean ,会使用 Bean 的首字母小写的非限定类名来作为它的别名-->
<!--com.nuo.pojo.User => user-->
<!--<package name="com.nuo.pojo"/>-->
<!--3.使用注解-->
<!-- @Alias("user") 可覆盖 package 的默认别名-->
</typeAliases>
<!--default:默认环境-->
<environments default="development">
<environment id="development">
<!--事务管理器-->
<!--在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):-->
<!--JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。-->
<!--MANAGED – 被管理, 例如Spring-->
<transactionManager type="JDBC"/>
<!--数据源-->
<!--有三种内建的数据源类型(type="[ POOLED | UNPOOLED | JNDI ]")-->
<!--POOLED : 表示使用数据库连接池缓存数据库连接-->
<!--UNPOOLED: 表示不使用数据库连接池-->
<!--JNDI : 表示使用上下文中的数据源-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--映射器-->
<!--每一个 ...Mapper.xml 都要在 mybatis 核心文件中进行配置-->
<mappers>
<!-- 1.使用相对于类路径的资源引用 eg.-->
<mapper resource="com/nuo/dao/UserMapper.xml"/>
<!--<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>-->
<!--2.使用完全限定资源定位符(URL)eg.-->
<!--<mapper url="file:///var/mappers/AuthorMapper.xml"/>-->
<!--3.使用映射器接口实现类的完全限定类名 eg.-->
<!--要求 :-->
<!--1. 接口 和 .xml 必须同名-->
<!--2. 接口 和 .xml 必须在同一个包下-->
<!--<mapper class="org.mybatis.builder.AuthorMapper"/>-->
<!--<mapper class="com.nuo.dao.UserMapperTest"/>-->
<!--4.将包内的映射器接口实现全部注册为映射器 eg.-->
<!--要求 :-->
<!--1. 接口 和 .xml 必须同名-->
<!--2. 接口 和 .xml 必须在同一个包下-->
<!--<package name="org.mybatis.builder"/>-->
</mappers>
</configuration>
5. 创建 mapper 接口
UserMapper.java
public interface UserMapper {
// 添加一个 user
int addUser();
}
6. 创建MyBatis的映射文件
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace -> 绑定一个 Dao/Mapper 接口-->
<mapper namespace="com.nuo.dao.UserMapper">
<insert id="addUser">
insert into user (id, name, pwd)
values (1, 'nuo', '123456');
</insert>
</mapper>
7. 通过junit测试
public class UserMapperTest {
@Test
public void addUser() throws IOException {
//读取MyBatis的核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务
//SqlSession sqlSession = sqlSessionFactory.openSession();
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// int res = sqlSession.insert("com.nuo.dao.UserMapper.addUser") 不推荐
//通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int res = userMapper.addUser();
if (res > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
sqlSession.close();
}
}
8. Mybatis 执行流程
1.Resource 获取配置文件输入流
2.实例化 SqlSessionFactoryBuilder
3.build(inputStream) (解析配置文件) -> SqlSessionFactory
4.transactional 事务管理器
5.创建 executor 执行器
6.sqlSessionFactory.openSession() 获取 sqlSession
7.实现 CRUD (可能回滚事务 ------> 4)
8.查看是否执行成功 (失败 回滚事务 ------> 4)
9.提交事务
10.关闭资源
9. 加入log4j日志功能
日志的级别:
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
jar
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
log4j 的配置文件 => log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
CRUD
<insert></insert>
<delete></delete>
<update></update>
<select></select>
package com.nuo.dao;
import com.nuo.pojo.User;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper {
// 添加一个 user
int addUser(User user);
// 删除一个用户
int deleteUser(User user);
// 按照 id 批量删除 user
int deleteUsers(@Param("ids") String ids);
// 修改用户
int updateUser(User user);
// 根据 id 查询 用户
User getUserById(int id);
// 模糊查询
List<User> getUserListByLike(String value);
// 获取全部用户
List<User> getUserList();
// 测试使用 map
int addUserTestMap(Map<String, Object> map);
// 单条查询结果用 map 接收 k->v 字段->值
// {name=诺, id=1, pwd=123456}
//Map<String, Object> getUserByIdToMap(@Param("id") int id);
// 单条查询结果用 map 接收 k->v 对应字段的值->所有字段键值对
// {1={name=诺, id=1, pwd=123456}}
@MapKey("id")
Map<String, Object> getUserByIdToMap(@Param("id") int id);
// 多条查询结果用 map 接收
// [{name=诺, id=1, pwd=123456}, {name=nuo, id=2, pwd=123123}, {name=aaa, id=3, pwd=123123}, {name=test, id=5, pwd=aaaaaaa}, {name=nnnnn, id=6, pwd=123123}]
// List<Map<String, Object>> getUserListToMap();
// {1={name=诺, id=1, pwd=123456}, 2={name=nuo, id=2, pwd=123123}, 3={name=aaa, id=3, pwd=123123}, 5={name=test, id=5, pwd=aaaaaaa}, 6={name=nnnnn, id=6, pwd=123123}}
@MapKey("id")
Map<String, Object> getUserListToMap();
// MyBatis 动态设置表名需要使用${},而不能使用#{}
// 因为 ${} => 不带'' #{} => 含''
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace -> 绑定一个 Dao/Mapper 接口-->
<mapper namespace="com.nuo.dao.UserMapper">
<!--无法赋值给pojo-->
<!--<insert id="addUser" parameterType="com.nuo.pojo.User">-->
<!-- insert into user (id, name, pwd)-->
<!-- values (#{id}, #{name}, #{pwd});-->
<!--</insert>-->
<!--可以获取到自动递增的主键-->
<!--useGeneratedKeys:设置当前标签中的 sql 使用了自增主键-->
<!--keyProperty:将自增的主键的值赋给传输的映射文件中参数的某个属性,可以同时赋值给pojo-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id" parameterType="com.nuo.pojo.User">
insert into user (id, name, pwd)
values (null, #{name}, #{pwd});
</insert>
<insert id="addUserTestMap" parameterType="map">
insert into user (id, name, pwd)
values (#{userId}, #{userName}, #{userPwd});
</insert>
<delete id="deleteUser" parameterType="com.nuo.pojo.User">
delete
from user
where id = #{id};
</delete>
<!--按照 id 批量删除 user-->
<!--int deleteUsers(@Param("ids") String ids);-->
<delete id="deleteUsers">
delete
from user
where id in (${ids});
</delete>
<update id="updateUser" parameterType="com.nuo.pojo.User">
update user
set name=#{name},
pwd=#{pwd}
where id = #{id};
</update>
<select id="getUserById" parameterType="int" resultType="com.nuo.pojo.User">
select *
from user
where id = #{id};
</select>
<!--'$'会出现 sql 注入 => ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中,可能引发sql注入-->
<!--'#'不会 => #{}是预编译处理,MyBatis在处理#{}时,它会将sql中的#{}替换为'?',然后调用-->
<!--PreparedStatement的set方法来赋值,传入字符串后,会在值两边加上单引号,使用占位符的方式提高效率,可以防止sql注入。-->
<select id="getUserListByLike" parameterType="String" resultType="com.nuo.pojo.User">
<!--select *
from user u
where u.name like '%${value}%'
-->
<!--select *
from user u
where u.name like "%"#{value}"%"
-->
select *
from user u
where u.name like concat('%', #{value}, '%');
</select>
<select id="getUserList" resultType="com.nuo.pojo.User">
select *
from user;
</select>
<!--测试别名-->
<!--<select id="getUserList" resultType="user">-->
<!-- select *-->
<!-- from user;-->
<!--</select>-->
<select id="getUserByIdToMap" resultType="map">
select *
from user u
where u.id = #{id};
</select>
<select id="getUserListToMap" resultType="map">
select *
from user;
</select>
</mapper>
注意:
1. 查询的标签select必须设置属性 `resultType` 或 `resultMap`,用于设置实体类和数据库表的映射关系
1. resultType:自动映射,用于属性名和表中字段名一致的情况
2. resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
2. 常见的使用${}的情况:
1.当sql中表名是从参数中取的情况
2.批量删除的 where id in (ids)
3.order by排序语句中, 因为order by 后边必须跟字段名,这个字段名不能带引号,如果带引号会被识别会字符串,而不是字段。
自定义映射
0. demo
查询
1)一对多
集合 => collection
2)多对一
对象 => association
Student
package com.nuo.pojo;
import lombok.Data;
import org.apache.ibatis.type.Alias;
@Data
public class Student {
private int id;
private String name;
private Teacher teacher;
}
Teacher
package com.nuo.pojo;
import lombok.Data;
import org.apache.ibatis.type.Alias;
import java.util.List;
@Data
public class Teacher {
private int id;
private String name;
private List<Student> students;
}
1. 按照查询嵌套处理
思路
1.查询获取所有学生信息
2.根据查询出来学生的 tid ,寻找对应的老师 => 子查询
<select id="getStudentList1" resultMap="StudentMap1">
select *
from student;
</select>
<resultMap id="StudentMap1" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select *
from teacher
where id = #{id};
</select>
2. 按照结果嵌套处理
思路
多表查询
<select id="getStudentList2" resultMap="StudentMap2">
select s.id sid,s.name sname,s.tid,t.name tname
from student s,teacher t
where s.tid = t.id;
</select>
<resultMap id="StudentMap2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
javaType & ofType
javaType => pojo 中的属性类型
ofType => pojo 实体类 (泛型)
动态 SQL
1. if 的使用
<select id="queryBlogIf" parameterType="map" resultType="blog">
select *
from blog b
<where>
<if test="title != null">
title like concat('%',#{title},'%')
</if>
<if test="author != null">
and author like concat('%',#{author},'%')
</if>
</where>
</select>
【PS】:
1. 若 where 标签中的 if 条件都不满足,则where标签没有任何功能, 即不会添加 where 关键字
2. 若 where 标签中的 if 条件满足,则 where 标签会自动添加 where 关键字,并将条件最前方多余的 and 去掉
注意:where 标签不能去掉条件最后多余的 and
2. trim
trim 用于去掉或添加标签中的内容
常用属性:
prefix :在 trim 标签中的内容的前面添加某些内容
prefixOverrides:在 trim 标签中的内容的前面去掉某些内容
suffix :在 trim 标签中的内容的后面添加某些内容
suffixOverrides:在 trim 标签中的内容的后面去掉某些内容
<select id="getEmpListByMoreTJ" resultType="Emp">
select * from t_emp
<trim prefix="where" suffixOverrides="and">
<if test="ename != '' and ename != null">
ename = #{ename} and
</if>
<if test="age != '' and age != null">
age = #{age} and
</if>
<if test="sex != '' and sex != null">
sex = #{sex}
</if>
</trim>
</select>
3. choose(when,otherwise)
类似 Java 中的 switch
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select *
from blog b where
<choose>
<when test="title != null">
title like concat('%',#{title},'%')
</when>
<when test="author != null">
author like concat('%',#{author},'%')
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</select>
4. foreach (集合遍历) 【通常在构建 in 条件语句的时候使用】
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>
4. sql片段 (代码复用)
类似方法调用
=> 1.最好基于单表来定义 sql 片段
=> 2.不要存在 where 标签
<sql id="if-title-author">
<if test="title != null">
title like concat('%',#{title},'%')
</if>
<if test="author != null">
and author like concat('%',#{author},'%')
</if>
</sql>
<select id="queryBlogIf" parameterType="map" resultType="blog">
select *
from blog b
<where>
<include refid="if-title-author"/>
</where>
</select>
缓存
1. 一级缓存
生命周期 : SqlSession
0.关于 SqlSession
每个线程都应该有它自己的 SqlSession 实例
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession
实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比
如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域
中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次
都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
1.如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中
的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
2.当一个SqlSession结束后那么他里面的一级缓存也就不存在了,mybatis默认是开启一级缓存,不需要配置
3.可手动清空缓存
sqlSession.clearCache();
4.mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使
用[namespace:sql:参数]作为key,查询返回的语句作为value保存的。
eg.-1242243203:1146242777:winclpt.bean.userMapper.getUser:0:2147483647:select * from user where id=?:19
使一级缓存失效的四种情况:
1) 不同的SqlSession对应不同的一级缓存
2) 同一个SqlSession但是查询条件不同
3) 同一个SqlSession两次查询期间执行了任何一次增删改操作
4) 同一个SqlSession两次查询期间手动清空了缓存
2. 二级缓存 (全局缓存) => 基于 namespace
生命周期 : SqlSessionFactory
1) 步骤 :
1.mybatis-config.xml 中显示的开启全局缓存 (虽然它默认是开启的,显示开启可提高可读性)
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2....Mapper.xml 中配置 '<cache/>'
eg. <mapper namespace="com.nuo.dao.UserMapper">
<cache/>
<select>...</select>
</mapper>
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"/>
缓存的收回策略 刷新间隔 (ms) 是否只读 引用数目
默认 LRU 不清空 false 1024
eviction :缓存的收回策略
LRU (最近最少使用的) 移除最长时间不被使用的对象,这是默认值
FIFO (先进先出) 按对象进入缓存的顺序来移除它们
SOFT (软引用) 移除基于垃圾回收器状态和软引用规则的对象
WEAK (弱引用) 更积极地移除基于垃圾收集器状态和弱引用规则的对象
readOnly:是否只读
true:只读,设置为true后,mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据,因此为了加快获取速度, 一般会直接将数据在缓存中的引用交给用户,虽然速度快,但不安全。
false:非只读,设置为false后,mybatis认为获取的数据可能会被修改,因此会利用序列化和反序列化的技术克隆一份新的数据给你,虽然速度慢,但安全。
3.给 POJO 类实现序列化接口
public class User implements Serializable {...}
2)在开启二级缓存时,查出来的数据默认先存储在一级缓存中,当有 SqlSession关闭 时,它里面一级缓存中的数据就会被存
储到 Mapper 的二级缓存中,这样该Mapper中的其他会话执行了相同方法时,就会在二级缓存中找到匹配的数据,如果没有找到,才
会去数据库中查找。注意只有在该会话关闭时,它一级缓存中的数据才会被刷到二级缓存中。另外如果只是开启二级缓存的全局(config)
开关,而会话(student)没有开启二级缓存,查询时也不会在二级缓存中查询。
3. 查询顺序
二级缓存 ----> 一级缓存 ----> 数据库
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
4. 自定义缓存
EhCache
一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布
式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet
过滤器,支持REST和SOAP api等特点。
使用步骤
1.导包
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
2.配置
<cache type="org.mybatis.caches.ehcache.EhcacheCache(五种可选)"/>
3.创建 .xml 配置文件(可自定义)
配置说明 :
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="./tmpdir/Tmp_EhCache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
逆向工程
1. mybatis用于生成代码的配置文件 generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版)
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8"
userId="root"
password="xiaonuo123..">
<!--8.0须设置 , 否则 MySQL 内置表的字段也会出现在生成的代码中-->
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.nuo.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.nuo.mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.nuo.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="user" domainObjectName="User"/>
<!--<table tableName="t_dept" domainObjectName="Dept"/>-->
</context>
</generatorConfiguration>
2. pom.xml 中配置生成器
<!-- 控制Maven在构建过程中相关配置 -->
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<configuration>
<!-- 加载mybatis用于生成代码的配置文件,这个文件要在这个路径下 -->
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
分页插件
1. jar
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
2. mybatis-config.xml 中配置插件
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3. 相关参数
pageSize:每页显示的条数
pageNum:当前页的页码
index:当前页的起始索引,index=(pageNum-1)*pageSize
count:总记录数
totalPage:总页数
totalPage = count / pageSize;
4. 相关返回数据
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]