ssm-Mybatis-全部知识点-胜哥
SSM框架【Spring+SpringMVC+Mybatis】
第一章 框架
1.1 生活中“框架”
- 买楼房
- 手抓饼
- 使用笔记本电脑
1.2 程序中【框架】半成品
- Mybatis:持久化层框架【dao-JDBC】
- SpringMVC:表示层【表现层】,Servlet
- Spring:全能
第二章 Mybatis 简介
-
Mybatis是一个半自动化持久化层的ORM框架
-
ORM:Object Relation Mapping【对象 关系 映射】
- 将JavaBean【JavaPOJO】与数据库中表建立映射关系,优势:只要操作POJO就会直接影响表中数据
-
Mybatis与Hibernate【持久化层框架】
- Hibernate全自动持久化层框架
- Mybatis半自动持久化层框架
-
Mybatis与JDBC
- JDBC不足:Java与SQL代码耦合度较高
- Mybatis优势:将Java代码与SQL解耦
第三章 Mybatis之Helloworld
导入jar包
编写配置文件
使用核心类库
3.1 搭建Mybatis框架步骤
-
准备工作
- 建库建表建约束
- 建POJO【JavaBean】
-
搭建环境
-
导包
<dependencies> <!--导入MyBatis的jar包--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <!-- Mysql驱动包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <!-- <dependency>--> <!-- <groupId>mysql</groupId>--> <!-- <artifactId>mysql-connector-java</artifactId>--> <!-- <version>8.0.16</version>--> <!-- </dependency>--> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
-
编写核心配置文件【Mybatis常用设置】
-
位置:resources目录下
-
文件名:mybatis-config.xml
-
示例代码
<?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> <environments default="development"> <!-- 设置连接数据库环境--> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/db1216"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <!-- 设置映射文件路径--> <mapper resource="mapper/EmployeeMapper.xml"/> </mappers> </configuration>
-
-
新建接口【Mapper(Dao)】
import com.atguigu.ssm.pojo.Employee; /** * @author Chunsheng Zhang 尚硅谷 * @create 2022/3/2 10:34 */ public interface EmployeeMapper { /** * 通过id获取员工信息 */ public Employee selectEmpById(int id); }
-
编写映射文件【为Mapper编写SQL】
-
位置:resources/mapper目录下
-
映射文件三个一致
- 映射文件名与接口名一致
- 映射文件中namespace与接口的全类名一致
- 映射文件中sqlId与接口中方法名一致
-
示例代码
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.atguigu.ssm.mapper.EmployeeMapper"> <select id="selectEmpById" resultType="com.atguigu.ssm.pojo.Employee"> SELECT id, last_name lastName, email, salary FROM tbl_employee WHERE id = #{id} </select> </mapper>
-
-
测试【SqlSession】
-
先获取SqlSessionFactory
-
再通过SqlSessionFactory获取SqlSession
-
通过SqlSession获取代理对象【实现类】
-
测试
-
示例代码
import com.atguigu.ssm.mapper.EmployeeMapper; import com.atguigu.ssm.pojo.Employee; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.IOException; import java.io.InputStream; /** * @author Chunsheng Zhang 尚硅谷 * @create 2022/3/2 10:45 */ public class TestMybatisHW { @Test public void testHw() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //再通过SqlSessionFactory获取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); //通过SqlSession获取**代理对象【实现类】** EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class); System.out.println("mapper.getClass().getName() = " + mapper.getClass().getName()); Employee employee = mapper.selectEmpById(1); System.out.println("employee = " + employee); } }
-
-
3.2 添加Log4j支持【日志框架】
-
导入jar包
<!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
编写配置文件
<?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>
第四章 Mybatis核心配置文件
-
作用:MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
-
常用标签
-
根标签:configuration,所有的子标签均需要书写在根标签内部
-
子标签
-
properties
- 作用:
- 定义property属性值
- 引入外部属性文件
- 作用:
-
settings:这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
- mapUnderscoreToCamelCase:是否开启驼峰命名自动映射,默认值:false
- 如开启,会将表中字段a_bc与类中属性aBc自动映射
- mapUnderscoreToCamelCase:是否开启驼峰命名自动映射,默认值:false
-
typeAliases:为JavaBean【POJO】定义别名
- 逐个定义别名:typeAlias
- 统一定义别名,指定JavaBean的包名:package
-
Mybatis自定义别名列表
别名 全类名 string java.lang.String _int int int【integer】 Integer list List map Map _double double
-
environments:设置数据库连接环境
- 设置事务管理器:transactionManager
- 设置连接数据库数据源:dataSource
-
mappers:设置映射文件路径
- 基于类路径设置映射文件路径:<mapper resource="mapper/EmployeeMapper.xml"/>
-
-
-
示例代码
<?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> <!-- <properties >--> <!-- <property name="driver" value="com.mysql.jdbc.Driver"/>--> <!-- </properties>--> <properties resource="db.properties"></properties> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <!-- <typeAlias type="com.atguigu.ssm.pojo.Employee" alias="employee"></typeAlias>--> <package name="com.atguigu.ssm.pojo"/> </typeAliases> <environments default="development"> <!-- 设置连接数据库环境--> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${db.driver}"/> <property name="url" value="${db.url}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> </dataSource> </environment> </environments> <mappers> <!-- 设置映射文件路径--> <mapper resource="mapper/EmployeeMapper.xml"/> <!-- <package name="mapper"/>--> </mappers> </configuration>
第五章 Mybatis映射文件
5.1 映射文件概述
- MyBatis 的真正强大在于它的语句映射,如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。
5.2 映射文件中常用标签
-
根标签:mapper
- namespace:与接口全类名一致
-
子标签
- select:定义查询SQL语句
- insert:定义增加SQL语句
- delete:定义删除SQL语句
- update:定义修改SQL语句
- resultMap:设置SQL语句结果集类型【与resultType作用一致,resultType解决不了时,使用resultMap(多表连接查询时,使用resultMap)】
- sql:定义可重用SQL语句块
- cache:该命名空间的缓存配置。
- cache-ref:引用其它命名空间的缓存配置。
-
标签中属性
- id:SQL语句唯一标识
- resultType:设置查询语句结果集类型。注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
5.3 在程序中获取数据库自增值
<insert id="insertEmp" useGeneratedKeys="true" keyProperty="id">
INSERT INTO
tbl_employee(last_name,email,salary)
VALUES
(#{lastName},#{email},#{salary})
</insert>
day02_Mybatis总结
- 注意事项
- 映射文件中标签无顺序要求
- 核心配置文件中的标签有顺序要求【具体顺序,参考官网文档】
day03
5.4 获取数据库受影响行数
-
直接在方法中设置返回值类型为:int即可【支持boolean】
-
示例代码
/** * 添加员工信息 */ public int insertEmp(Employee employee); public boolean insertEmp(Employee employee);
第六章 Mybatis中参数传递问题
6.1 单个普通类型参数
- 可直接入参使用即可,无考虑参数名及参数类型等问题
6.2 多个普通类型参数
- mybatis底层封装Map结构,参数的key是arg0、arg1、...【或param1、param2、....】
6.3 命名参数
- mybatis底层封装Map结构,参数的key是@Param注解命名的【同时支持:param1,param2】
6.4 POJO【JavaBean】
- mybatis支持POJO直接入参的,参数的key是POJO中属性名
- mybatis获取POJO中参数,是通过getXXX()方法获取的
6.5 Map
- mybatis支持Map入参,参数的key是Map的key
6.6 Collection|List|Array
- mybatis也支持Collection、List、Array入参,Collection对应的key是collection,Array对应的key是array. 如果确定是List集合,key还可以是list。
6.7 源码解析命名参数底层原理
-
MapperMethod中execute()入口
-
MapperMethod中86行【导入源码后】,进入源码
-
ParamNameResolver中getNamedParams(),命名参数底层原理
else { final Map<String, Object> param = new ParamMap<>(); int i = 0; for (Map.Entry<Integer, String> entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); // add generic param names (param1, param2, ...) final String genericParamName = GENERIC_NAME_PREFIX + (i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; }
- 总结
- Mybatis底层封装Map,本质是ParamMap 继承 HashMap
- 总结
第七章 Mybatis中#与$区别【面试题】
- JDBC关键对象【DriverManager、Connection、PreparedStatement、ResultSet】
- Statement:底层传递SQL参数时,使用拼接SQL方式,存在SQL注入安全隐患
- PreparedStatement:底层传递SQL参数时,使用?【占位符】方式,相对安全
7.1 #与$概述
-
:Mybatis中#传递参数底层使用PreparedStatement对象,使用占位符方式,相对安全
- $:Mybatis中#传递参数底层使用Statement对象,字符串拼接方式,相对不安全
7.2 $使用场景
完整查询SQL:
select col,col2... from tbl1 where ? group by ? order by ? limit ?,?
-
示例代码
/** * 测试动态查询表中数据【表名动态化】 */ public List<Employee> selectEmpByOpr(@Param("tblName") String tblName);
<select id="selectEmpByOpr" resultType="employee"> SELECT id, last_name, email, salary FROM ${tblName} </select>
第八章 Mybatis常见四种查询结果
8.1 查询单行数据返回单个对象
/**
* 通过id获取员工信息
*/
public Employee selectEmpById(int id);
<select id="selectEmpByIdAndName" resultType="employee">
SELECT
id,
last_name,
email,
salary
FROM
tbl_employee
WHERE
id = #{param1}
AND
last_name=#{param2}
</select>
8.2 查询多行数据返回对象的集合
/** * 获取所有员工信息 */public List<Employee> selectAllEmps();
<!-- 定义SQL【获取所有员工信息】--><select id="selectAllEmps" resultType="employee"> SELECT id, last_name, email, salary FROM tbl_employee</select>
8.3 查询单行数据返回Map集合
-
将数据库表中的字段,作为key;数据作为value;所以建议Map的key使用String类型
/** * 测试查询单行数据,返回Map */public Map<String,Employee> selectEmpReturnMap(int id);
<select id="selectEmpReturnMap" resultType="map"> SELECT id, last_name, email, salary FROM tbl_employee WHERE id = #{id} </select>
8.4 查询多行数据返回Map集合
-
Map的key是对象的Id,Map的value是对象本身。
-
注意:必须使用@MapKey注解,设置对象的Id,如未设置会报如下错误:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 8
-
示例代码
/** * 测试查询多行数据,返回Map * key:id * value:Employee */ @MapKey("id") public Map<Integer,Employee> selectAllEmpReturnMap();
<select id="selectAllEmpReturnMap" resultType="map"> SELECT id, last_name, email, salary FROM tbl_employee </select>
第九章 Mybatis中自动映射及自定义映射【重点】
9.1 自动映射【resultType】与自定义映射【resultMap】概述
- 自动映射:将结果集中的字段与对象中的属性【Map中的key】自动映射
- 自定义映射:将结果集中的字段与对象中的属性【Map中的key】自定义映射
- 总结:
- resultType解决不了时,使用resultMap
- resultMap适用场景:多表连接查询时较多
9.2 使用自定义映射
-
级联映射
/** * 通过id获取员工信息及员工所属部门信息 */ public Employee selectEmpAndDeptByEmpId(int id);
<!-- 通过员工id获取员工信息及员工所属部门信息--> <resultMap id="empAndDeptResultMap" type="employee"> <!-- 自定义映射关系【主键】--> <id property="id" column="id"></id> <!-- 自定义映射关系【非主键】--> <result property="lastName" column="last_name"></result> <result property="email" column="email"></result> <result property="salary" column="salary"></result> <!--【级联映射】 自定义部门关联关系--> <result property="dept.deptId" column="dept_id"></result> <result property="dept.deptName" column="dept_name"></result> </resultMap> <select id="selectEmpAndDeptByEmpId" resultMap="empAndDeptResultMap"> SELECT e.id,e.`last_name`,e.`email`,e.`salary` , d.`dept_id`,d.`dept_name` FROM tbl_employee e,tbl_dept d WHERE e.`dept_id`=d.`dept_id` AND e.`id` = #{id} </select>
-
association【一对一或多对一】
/** * 通过id获取员工信息及员工所属部门信息【association】 */ public Employee selectEmpAndDeptByEmpIdAssociation(int id);
<resultMap id="empAndDeptResultMapAssociation" type="employee"> <!-- 自定义映射关系【主键】--> <id property="id" column="id"></id> <!-- 自定义映射关系【非主键】--> <result property="lastName" column="last_name"></result> <result property="email" column="email"></result> <result property="salary" column="salary"></result> <!-- association--> <association property="dept" javaType="com.atguigu.ssm.pojo.Dept"> <id property="deptId" column="dept_id"></id> <result property="deptName" column="dept_name"></result> </association> </resultMap> <select id="selectEmpAndDeptByEmpIdAssociation" resultMap="empAndDeptResultMapAssociation"> SELECT e.id,e.`last_name`,e.`email`,e.`salary` , d.`dept_id`,d.`dept_name` FROM tbl_employee e,tbl_dept d WHERE e.`dept_id`=d.`dept_id` AND e.`id` = #{id} </select>
9.3 ResultMap标签
- 属性
- id:设置ResultMap唯一标识
- type:设置ResultMap类型
- 子标签
- id:定义主键映射关系【对象中的属性与表中字段的映射关系】
- result:定义非主键映射关系
- association:定义一对一【或多对一】的映射关系
- collection:定义一对多的映射关系
- 属性
- property:定义映射属性
- ofType:定义映射属性类型【全类名】,如association使用javaType
- select:设置SQL语句Id的全路径【分步查询】
- column:设置SQL语句参数【分步查询】
- fetchType:局部设置延迟加载是否开启
- lazy:开启延迟加载
- eager:关闭延迟加载
- 属性
day03_总结
- Mybatis中参数传递问题
- 看源码:命名参数底层源码
-
与$区别【面试题】
- 自定义映射【级联映射&association映射】
day04
9.4 association自定义映射分步查询及延迟加载【一对一】
-
分步查询
- 为什么需要分步查询【分步查询优势】
- 分步查询时一般单表查询,比较多表连接查询,效率高。
- 为什么需要分步查询【分步查询优势】
-
延迟加载【懒加载】
-
概述:需要数据时加载,不需要时不加载
-
语法
-
全局配置
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认值:false
-
局部配置
fetchType="eager":关闭延迟加载
fetchType="lazy":开启延迟加载
<association property="dept" select="com.atguigu.ssm.mapper.DeptMapper.selectDeptById" column="dept_id" fetchType="eager"></association>
-
-
-
示例代码
- 员工信息
/** * 通过员工id获取员工信息及员工所属部门信息【association分步查询】 * * 1. 通过员工id获取员工信息 * * 2. 通过员工id,获取部门id,再通过部门id获取部门信息 * 为分步查询做准备 */ public Employee selectEmpAndDeptByEmpIdAssociationStep(int id);
<!-- association分步查询--> <resultMap id="empAndDeptAssociationStep" type="employee"> <!-- 自定义映射关系【主键】--> <id property="id" column="id"></id> <!-- 自定义映射关系【非主键】--> <result property="lastName" column="last_name"></result> <result property="email" column="email"></result> <result property="salary" column="salary"></result> <!-- 关联部门--> <association property="dept" select="com.atguigu.ssm.mapper.DeptMapper.selectDeptById" column="dept_id" fetchType="eager"> </association> </resultMap> <select id="selectEmpAndDeptByEmpIdAssociationStep" resultMap="empAndDeptAssociationStep"> SELECT id, last_name, email, salary, dept_id FROM tbl_employee WHERE id = #{id} </select>
- 部门信息
/** * 通过部门id获取部门信息 * 为分步查询做准备 */ public Dept selectDeptById(int deptId);
<select id="selectDeptById" resultType="dept"> select dept_id, dept_name from tbl_dept where dept_id = #{deptId} </select>
9.5 Collection自定义映射分步查询及延迟加载【一对多】
- 部门信息
/**
* 分步查询【通过部门id获取部门信息,及部门中所有员工信息】
* 1. 通过部门id获取部门信息
* 2. 通过部门id获取员工信息
*/
Dept selectDeptAndEmpByDeptIdStep(int deptId);
<resultMap id="deptAndEmpStep" type="dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
<collection property="employees"
select="com.atguigu.ssm.mapper.EmployeeMapper.selectEmpByDeptId"
column="dept_id"
fetchType="lazy">
</collection>
</resultMap>
<select id="selectDeptAndEmpByDeptIdStep" resultMap="deptAndEmpStep">
select
dept_id,
dept_name
from
tbl_dept
where
dept_id = #{deptId}
</select>
- 员工信息
/**
* 通过部门id获取员工信息
*/
List<Employee> selectEmpByDeptId(int deptId);
<select id="selectEmpByDeptId" resultType="employee">
SELECT
id,
last_name,
email,
salary,
dept_id
FROM
tbl_employee
WHERE
dept_id = #{deptId}
</select>
第十章 Mybatis中动态SQL【重点】
Thymeleaf:动态渲染数据【HTML】
动态SQL:指的是SQL可动态变化
10.1 if与where
-
if标签: if用于完成简单的判断.
-
where标签:用于解决SQL语句中where关键字以及条件前面的第一个and或者or的问题
-
trim标签:添加或删除前后指定字符
- prefix:添加前缀字符
- prefixOverrides:删除前缀字符
- suffix:添加后缀字符
- suffixOverrides:删除后缀字符
-
set标签:用于解决set关键字,及多出一个逗号【,】问题
-
choose标签:用于单条件分支结构【类似流程控制中if-else】
-
foreach标签:用于循环【类似流程控制中循环结构】
-
sql片段:用于提取可重复使用sql片段
10.2 示例代码总结
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ssm.mapper.EmployeeMapper">
<sql id="col_employee">
id,
last_name,
email,
salary,
dept_id
</sql>
<sql id="select_employee">
SELECT
id,
last_name,
email,
salary,
dept_id
FROM
tbl_employee
</sql>
<select id="selectEmpByEmp" resultType="employee">
<include refid="select_employee"></include>
<!-- SSS -->
-- SFDSF
<where>
<if test="id != null">
<!-- id = #{id} -->
id = #{id}
</if>
<if test="lastName != null">
AND last_name = #{lastName}
</if>
<if test="email != null">
AND email = #{email}
</if>
<if test="salary != null">
AND salary = #{salary}
</if>
</where>
</select>
<select id="selectEmpByEmpTrim" resultType="employee">
<include refid="select_employee"></include>
<trim prefix="where" suffixOverrides="and">
<if test="id != null">
id = #{id} AND
</if>
<if test="lastName != null">
last_name = #{lastName} AND
</if>
<if test="email != null">
email = #{email} AND
</if>
<if test="salary != null">
salary = #{salary} AND
</if>
</trim>
</select>
<update id="updateEmpByEmp">
update
tbl_employee
<set>
<if test="lastName != null">
last_name = #{lastName},
</if>
<if test="email != null">
email = #{email},
</if>
<if test="salary != null">
salary = #{salary}
</if>
</set>
where
id = #{id}
</update>
<select id="selectEmpByEmpChoose" resultType="employee">
SELECT
<include refid="col_employee"></include>
FROM
tbl_employee
<where>
<choose>
<when test="id != null">
id = #{id}
</when>
<when test="lastName != null">
last_name = #{lastName}
</when>
<when test="email != null">
email = #{email}
</when>
<when test="salary != null">
salary = #{salary}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
<select id="selectEmpsByIds" resultType="employee">
SELECT
id,
last_name,
email,
salary,
dept_id
FROM
tbl_employee
WHERE
id in (
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)
</select>
<insert id="insertBatchEmp">
INSERT INTO
tbl_employee(last_name,email,salary)
VALUES
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.salary})
</foreach>
</insert>
</mapper>
第十一章
11.1 缓存概念
- 生活中缓存
- 内容:缓存音频视频等
- 优势:节约数据流量,提高性能
- Mybatis程序中缓存
- 内容:缓存数据【数据库】
- 优势:提高查询效率,减低服务器压力
11.2 Mybatis中一级缓存
- 一级缓存【本地缓存】,默认开启,不能关闭。
- 一级缓存作用域:SqlSession
11.3 一级缓存工作原理
- 第一次获取数据时,先从数据库中查询指定数据。将数据缓存到一级缓存【Map结构,key:hashCode+查询的SqlId+编写的sql查询语句+参数】
- 以后在同一个SqlSession中,获取相同数据时,会先从一级缓存中获取数据,如一级缓存中没有指定数据,再从数据库中获取【在缓存到一级缓存】
11.4 一级缓存五种失效情况
-
不同的SqlSession对应不同的一级缓存
-
同一个SqlSession但是查询条件不同
-
同一个SqlSession两次查询期间执行了任何一次增删改操作
-
同一个SqlSession两次查询期间手动清空了缓存
- sqlSession.clearCache()
- 同一个SqlSession两次查询期间提交了事务
day05
11.6 Mybatis中二级缓存
- 二级缓存(second level cache),全局作用域缓存【SqlSessionFactory】
- 二级缓存默认不开启,需要手动开启并配置
11.7 使用Mybatis二级缓存步骤
① 全局配置文件中开启二级缓存
② 需要使用二级缓存的映射文件处使用cache配置缓存
③ 注意:POJO需要实现Serializable接口
④ 关闭sqlSession或提交sqlSession时,将数据缓存到二级缓存
11.8 Mybatis二级缓存工作原理
- 第一次获取数据时,从数据库中查询指定数据。并先将数据缓存至一级缓存,再关闭或提交SqlSession时,将数据缓存至二级缓存
- 以后在获取数据时,先从一级缓存中获取数据,如获取不到数据;再从二级缓存中获取数据【如未获取到数据】,则从数据库中获取数据【并重复上述操作】
11.9 Mybatis二级缓存相关属性
-
eviction:缓存清除【回收】策略:
- LRU – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
-
flushInterval:刷新间隔,单位毫秒
- 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
-
size:引用数目,正整数
- 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
-
readOnly:只读,true/false
11.10 Mybatis支持第三方缓存【EhCache】
-
使用步骤
-
导入jar包
<!-- mybatis-ehcache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.0.3</version> </dependency> <!-- slf4j-log4j12 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.2</version> <scope>test</scope> </dependency>
-
编写EhCache配置文件
-
位置:resources
-
名称:ehcache.xml
-
示例代码
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盘保存路径 --> <diskStore path="E:\mybatis\ehcache" /> <defaultCache maxElementsInMemory="512" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache> <!-- 属性说明: l diskStore:指定数据在磁盘中的存储位置。 l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略 以下属性是必须的: l maxElementsInMemory - 在内存中缓存的element的最大数目 l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大 l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断 l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 以下属性是可选的: l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大 l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区. l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作 l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) -->
-
-
开启第三方缓存【映射文件】
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
-
-
注意:第三方缓存使用是建立在二级缓存的基础之上的。
第十二章 Mybatis逆向工程
12.1 逆向工程概述
-
正向工程:通过Java工程【Mapper&POJO】,影响数据库中数据
-
逆向工程:通过数据库,影响Java工程【Mapper&POJO】
-
逆向工程简介
- MyBatis Generator: 简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。
- 支持基本的增删改查,以及QBC风格的条件查询。
-
官方文档地址
12.2 逆向工程使用步骤
-
导入jar包
<dependencies> <!--导入MyBatis的jar包--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <!-- Mysql驱动包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- mybatis-generator-core --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.6</version> </dependency> </dependencies>
-
编写配置文件
-
位置:resources
-
名称:mbg.xml
-
示例代码
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- id属性:设置一个唯一标识 targetRuntime属性值说明: MyBatis3Simple:基本的增删改查 MyBatis3:带条件查询的增删改查【QBC风格查询】 --> <context id="simple" targetRuntime="MyBatis3Simple"> <!--设置连接数据库的相关信息--> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/db1216" userId="root" password="root"/> <!--设置JavaBean的生成策略--> <javaModelGenerator targetPackage="com.atguigu.mybatis.mbg.pojo" targetProject="src/main/java"/> <!--设置SQL映射文件的生成策略--> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/> <!--设置Mapper接口的生成策略--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mbg.mapper" targetProject="src/main/java"/> <!--逆向分析的表--> <table tableName="tbl_employee" domainObjectName="Employee"/> <table tableName="tbl_dept" domainObjectName="Department"/> </context> </generatorConfiguration>
-
-
使用代码生成器,生成相关代码
@Test public void testMBG() throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException { List<String> warnings = new ArrayList<String>(); boolean overwrite = true; File configFile = new File("src/main/resources/mbg.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); }
12.3 逆向工程之QBC风格
-
mbg.xml中设置
<context id="simple" targetRuntime="MyBatis3">
-
使用条件对象【XXXExample】
@Test public void testCache2(){ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(); EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class); //测试普通MBG // List<Employee> employees = mapper.selectAll(); // for (Employee employee : employees) { // System.out.println("employee = " + employee); // } //测试QBC风格MBG EmployeeExample ee = new EmployeeExample(); //为条件对象【ee】设置条件 EmployeeExample.Criteria criteria = ee.createCriteria(); criteria.andIdBetween(1,10); criteria.andSalaryGreaterThanOrEqualTo(100000.0); criteria.andLastNameLike("%i%"); List<Employee> employees = mapper.selectByExample(ee); for (Employee employee : employees) { System.out.println("employee = " + employee); } }
第十三章 分页插件【PageHelper】
13.1 分页基本概念
-
为什么需要分页?
- 提高用户体验度
- 降低服务器压力
-
手动搭建分页【Page工具类】
- pageNum【当前页码】
- pages【总页码=总数据条数/每页显示数量】
- total【总数据条数】
- pageSize【每页显示数量】
- List
【当前页显示数据集合】
13.2 使用Mybatis中分页插件【PageHelper】
-
PageHelper是MyBatis中非常方便的第三方分页插件
-
PageHelper使用步骤
-
导入jar包
<!-- pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.0.0</version> </dependency>
-
在MyBatis全局配置文件中配置分页插件
- 书写位置:核心配置文件【mybatis-config.xml】中的环境上面即可
<plugins> <!--配置PageHelper分页插件--> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
-
使用PageHelper提供的方法进行分页【在查询之前开启分页】
//开启分页插件功能 PageHelper.startPage(pageNum, pageSize);
-
可以使用更强大的PageInfo封装返回结果
@Test public void testPageInfo(){ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(); EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class); //开启分页 PageHelper.startPage(9, 3); //测试QBC风格MBG EmployeeExample ee = new EmployeeExample(); List<Employee> employees = mapper.selectByExample(ee); for (Employee employee : employees) { System.out.println("employee = " + employee); } //查询之后,将结果封装PageInfo PageInfo<Employee> pageInfo = new PageInfo<>(employees,5); System.out.println("====================================="); System.out.println(pageInfo.getPageNum()+"/"+pageInfo.getPages()); System.out.println("总条数:"+pageInfo.getTotal()); System.out.println("每页显示条数:"+pageInfo.getPageSize()); for (Employee employee : pageInfo.getList()) { System.out.println("employee = " + employee); } System.out.println("页码信息:"); int[] navigatepageNums = pageInfo.getNavigatepageNums(); for (int navigatepageNum : navigatepageNums) { System.out.print(navigatepageNum+" "); } System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage()); System.out.println("上一页是:"+pageInfo.getPrePage()); System.out.println("是否有下一页:"+pageInfo.isHasNextPage()); System.out.println("下一页是:"+pageInfo.getNextPage()); System.out.println("是否是第一页:"+pageInfo.isIsFirstPage()); System.out.println("是否是最后一页:"+pageInfo.isIsLastPage()); System.out.println("导航页的第一个页码是:"+pageInfo.getNavigateFirstPage()); System.out.println("导航页的最后一个页码是:"+pageInfo.getNavigateLastPage()); System.out.println("导航页的总页码是:"+pageInfo.getNavigatePages()); }
-
13.3 PageHelper底层实现原理
-
//开始下标【index】=(pageNum-1)*pageSize PageHelper.startPage(2,3);
-
-- 分页底层执行两条SQl -- 1. 查询数据库数量【total(总数据条数)】 SELECT count(0) FROM tbl_employee -- 2. 查询当前页显示数据集合【List<T>(当前页显示数据集合)】 select id, last_name, email, salary, dept_id from tbl_employee LIMIT 3,3
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧