文章目录
resultMap复杂映射:
一对一:
一个用户对应一个购物车(业务场景)
1: 表设计
person(照图)
car表中的字段不能与person表中的字段重复,如果重复了写复杂sql时需给重复的字段起别名,为了减少sql编写的复杂,所以确保两张表之间的字段唯一性
DROP TABLE IF EXISTS `car`;
CREATE TABLE `car` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(20) DEFAULT NULL,
`pid` int(11) NOT NULL,
PRIMARY KEY (`cid`),
KEY `cp` (`pid`),
CONSTRAINT `cp` FOREIGN KEY (`pid`) REFERENCES `person` (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `car` VALUES (1, '忆柳的购物车', 2);
INSERT INTO `car` VALUES (2, '梦琪的购物车', 1);
INSERT INTO `car` VALUES (3, '新柔的购物车', 5);
INSERT INTO `car` VALUES (4, '慕青的购物车', 3);
INSERT INTO `car` VALUES (5, '初夏的购物车', 4);
2: 根据表创建实体对象
public class Car implements Serializable {
private int cid;
private String cname;
private int pid;
// get/set...
}
public class Person implements Serializable {
private int id;
private String name;
private Date bir;
private String address;
private Car car;// 用户拥有购物车
}
3:构建mapper配置文件
第一种方式
<?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="beike.mybatis.mapper.PersonMapper">
<resultMap type="Person" id="PersonCarResultMap">
<!-- 主键字段的配置 -->
<id property="id" column="id"></id>
<!-- 普通字段的配置 -->
<result property="name" column="name"></result>
<result property="bir" column="bir"/>
<!--
property:person中的car属性
javaType:person中的car类型
-->
<!-- 第一种方式,直接在标签处理映射关系 -->
<association property="car" javaType="Car">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
<!-- car中的pid与person中的id进行关联 -->
<result property="pid" column="pid"></result>
</association>
</resultMap>
<!-- sql需编写联表查询 -->
<select id="getPersonCar" resultMap="PersonCarResultMap">
SELECT * FROM person,car
WHERE person.Id=car.pid
</select>
</mapper>
第二种方式
Car的映射关系写在自已的CarMapper.xml中,在PersonMapper.xml使用association引用
<association property="cart" column="id" javaType="Cart" resultMap="调用其他配置文件的map映射 命名空间.resultMap的id值 ">
CarMapper.xml,添加接口CarMapper.java
<?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="beike.mybatis.mapper.CarMapper">
<resultMap type="Car" id="CarResultMap">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
<result property="pid" column="pid"></result>
</resultMap>
</mapper>
PersonMapper.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">
<mapper namespace="beike.mybatis.mapper.PersonMapper">
<resultMap type="Person" id="PersonCarResultMap">
<!-- 主键字段的配置 -->
<id property="id" column="id"></id>
<!-- 普通字段的配置 -->
<result property="name" column="name"></result>
<result property="bir" column="bir"/>
<!--
第一种方式,调用其他配置文件的map映射
命名空间.resultMap的id值
-->
<association property="car" javaType="Car" resultMap="beike.mybatis.mapper.CarMapper.CarResultMap">
</association>
</resultMap>
<select id="getPersonCar" resultMap="PersonCarResultMap">
SELECT * FROM person,car
WHERE person.Id=car.pid
</select>
mybatis-config.xml
<mappers>
<!-- 扫描包的方式加载接口,接口必须与.xml同名 -->
<package name="beike.mybatis.mapper"/>
</mappers>
注意:
第一种关联和第二种关联我们需要写出的是复杂查询的语句
三种关联查询(推荐)
如果是第三种关联查询,我们可以将复杂查询拆分成简单查询
示例
CarMapper
public interface CarMapper {
Car getCar(int pid);
}
<?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="beike.mybatis.mapper.CarMapper">
<resultMap type="Car" id="CarResultMap">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
<result property="pid" column="pid"></result>
</resultMap>
<!-- 通过pid查询购物车对象 -->
<select id="getCar" resultMap="CarResultMap">
SELECT * FROM car WHERE pid=#{pid}
</select>
</mapper>
PersonMapper
//查询
public List<Person> getPersonCar();
public Person getById(int id);
<?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="beike.mybatis.mapper.PersonMapper">
<resultMap type="Person" id="PersonCarResultMap">
<!-- 主键字段的配置 -->
<id property="id" column="id"></id>
<!-- 普通字段的配置 -->
<result property="name" column="name"></result>
<result property="bir" column="bir"/>
<!--
property:person中的car属性
javaType:person中的car类型
column="id" 传person中与car关联的字段
select="命名空间.id"
-->
<association property="car" column="id" javaType="Car" select="beike.mybatis.mapper.CarMapper.getCar">
</association>
</resultMap>
<select id="getPersonCar" resultMap="PersonCarResultMap">
SELECT * FROM person
</select>
<select id="getById" resultMap="PersonCarResultMap">
SELECT * FROM person WHERE id=#{id}
</select>
</mapper>
测试类
@Test
public void testGetPersonCar() {
//定义配置文件路径
String fileName="mybatis-config.xml";
try {
//通过配置文件创建输入流对象
InputStream inputStream = Resources.getResourceAsStream(fileName);
//读取配置文件 实例化我们工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
//通过反射机制获取接口对象
PersonMapper mapper = session.getMapper(PersonMapper.class);
//调用接口方法
List<Person> list = mapper.getPersonCar();
//关闭
session.close();
System.out.println(list);
} catch (IOException e) {
e.printStackTrace();
}
}
一对多:
建模(分析业务)一个用户对应多个订单
1: 建表 person orders(orders外键关联person表主键)
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
`oid` int(11) NOT NULL AUTO_INCREMENT,
`oname` varchar(255) DEFAULT NULL,
`pid` int(11) DEFAULT NULL,
PRIMARY KEY (`oid`),
KEY `op` (`pid`),
CONSTRAINT `op` FOREIGN KEY (`pid`) REFERENCES `person` (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
INSERT INTO `order` VALUES (1, '荣耀MagicBook 2019 14英寸轻薄窄边框', 2);
INSERT INTO `order` VALUES (2, '小米 (MI)Ruby 2019款 15.6英寸金属轻薄', 1);
INSERT INTO `order` VALUES (3, '戴尔灵越14 燃 14英寸英特尔酷睿i5轻薄窄边框', 3);
INSERT INTO `order` VALUES (4, '联想(Lenovo)小新14英寸 锐龙版R5', 4);
INSERT INTO `order` VALUES (5, '红辣椒7X 4+64GB 学生智能手机', 5);
INSERT INTO `order` VALUES (6, '荣耀10青春版 幻彩渐变', 1);
INSERT INTO `order` VALUES (7, 'OPPO K1 全面屏手机', 2);
INSERT INTO `order` VALUES (8, '卡梵蒂GAVADI 鳄鱼皮钱包', 5);
INSERT INTO `order` VALUES (9, '七匹狼钱包', 2);
INSERT INTO `order` VALUES (10, '金利来(Goldlion)男士钱包', 1);
2:Order
public class Order implements Serializable {
private int oid;
private String oname;
private int pid;
}
3:数据模型
Person{
List<Order> orderList;
}
4: 配置文件
<!-- 一对多 -->
<!--
<collection property="ods" column="id" ofType="Orders">
<id property="oid" column="oid"></id>
<result property="odis" column="odis"></result>
<result property="per_fk" column="id"></result>
</collection>
-->
<!-- 一对多 第二種情況 -->
<!--
<collection property="ods" column="id" ofType="Orders" resultMap="调用其他配置文件的resultMap ">
</collection>
-->
<!-- 一对多 第三種情況 -->
<collection property="ods" column="id" ofType="Orders" select="调用其他mapper配置文件的查询 ">
</collection>
示例代码 orderMapper
public interface OrderMapper {
List<Order> list();
}
<?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="beike.mybatis.mapper.OrderMapper">
<resultMap type="Order" id="OrderResultMap">
<id property="oid" column="oid"></id>
<result property="oname" column="oname"></result>
<result property="pid" column="pid"></result>
</resultMap>
<!-- 通过pid查询订单对象 -->
<select id="list" resultMap="OrderResultMap">
SELECT * FROM `order` WHERE pid=#{pid}
</select>
</mapper>
PersonMapper
List<Person> getPersonOrder();
<?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="beike.mybatis.mapper.PersonMapper">
<resultMap type="Person" id="PersonOrderResultMap">
<!-- 主键字段的配置 -->
<id property="id" column="id"></id>
<!-- 普通字段的配置 -->
<result property="name" column="name"></result>
<result property="bir" column="bir"/>
<!--
property:person中的car属性
ofType:person中的orderList集合保存的对象类型
column="id" 传person中与car关联的字段
select="命名空间.id"
-->
<association property="car" column="id" javaType="Car" select="beike.mybatis.mapper.CarMapper.getCar" />
<collection property="orderList" column="id" ofType="Order" select="beike.mybatis.mapper.OrderMapper.list" />
</resultMap>
<select id="getPersonOrder" resultMap="PersonOrderResultMap">
SELECT * FROM person
</select>
</mapper>
测试类
@Test
public void testGetPersonCar() {
//定义配置文件路径
String fileName="mybatis-config.xml";
try {
//通过配置文件创建输入流对象
InputStream inputStream = Resources.getResourceAsStream(fileName);
//读取配置文件 实例化我们工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
//通过反射机制获取接口对象
PersonMapper mapper = session.getMapper(PersonMapper.class);
//调用接口方法
List<Person> list = mapper.getPersonOrder();
//关闭
session.close();
System.out.println(list);
} catch (IOException e) {
e.printStackTrace();
}
}
多对多
多对多的模型设计
学生与课程:一个学生对应多门课程;一门课程对应多个学生
1: 表设计: Student Course stu_cou(中间关系表)
一个student对应多个stu_cou,一个stu_cou对应一个course
建表代码
#学生表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`sname` varchar(20) DEFAULT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `student` VALUES (1, '梦琪');
INSERT INTO `student` VALUES (2, '初夏');
INSERT INTO `student` VALUES (3, '忆柳');
#课程表
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(20) DEFAULT NULL,
PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `course` VALUES (1, 'JAVA');
INSERT INTO `course` VALUES (2, 'HTML');
INSERT INTO `course` VALUES (3, 'DATABASE');
#中间表
DROP TABLE IF EXISTS `stu_cou`;
CREATE TABLE `stu_cou` (
`scid` int(11) NOT NULL AUTO_INCREMENT,
`cid` int(11) DEFAULT NULL,
`sid` int(11) DEFAULT NULL,
PRIMARY KEY (`scid`),
KEY `scs` (`sid`),
KEY `scc` (`cid`),
CONSTRAINT `scc` FOREIGN KEY (`cid`) REFERENCES `course` (`cid`),
CONSTRAINT `scs` FOREIGN KEY (`sid`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
INSERT INTO `stu_cou` VALUES (1, 1, 1);
INSERT INTO `stu_cou` VALUES (2, 1, 2);
INSERT INTO `stu_cou` VALUES (3, 1, 3);
INSERT INTO `stu_cou` VALUES (4, 2, 1);
INSERT INTO `stu_cou` VALUES (5, 2, 2);
INSERT INTO `stu_cou` VALUES (6, 2, 3);
INSERT INTO `stu_cou` VALUES (7, 3, 1);
2: 建立模型
/**
* 学生对课程中间表实体
*/
public class StuCou {
private int scid;
private int sid;
private int cid;
//一个cid对应一个课程对象
private Course course;
}
public class Student {
private int sid;
private String sname;
//一个学生对应多个中间对象 中间表中一个sid对应多个cid
private List<StuCou> scList;
}
public class Course {
private int cid;
private String cname;
}
3: 书写配置文件(通过查询学生关联查询学校)
public interface StudentMapper {
List<Student> list();
}
<?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="beike.mybatis.mapper.StudentMapper">
<!--
多对多在查询设计加载都是比较慢的,所以在静候编程中
多对多的关系拆分成一对多
-->
<resultMap type="Student" id="StudentCourseResultMap">
<id property="sid" column="sid"></id>
<result property="sname" column="sname"></result>
<!—一个student对应多个StuCou-->
<collection property="scList" column="sid" ofType="StuCou">
<id property="scid" column="scid"></id>
<id property="cid" column="cid"></id>
<id property="sid" column="sid"></id>
<!—一个StuCou对应一个Course-->
<association property="course" column="cid" javaType="Course">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
</association>
</collection>
</resultMap>
<!-- 通过pid查询购物车对象 -->
<select id="listStudentCourse" resultMap="StudentCourseResultMap">
SELECT *
FROM student,stu_cou,course
WHERE student.sid=stu_cou.sid
AND stu_cou.cid=course.cid
</select>
</mapper>
测试类
@Test
public void testListStudentCourse() {
//定义配置文件路径
String fileName="mybatis-config.xml";
try {
//通过配置文件创建输入流对象
InputStream inputStream = Resources.getResourceAsStream(fileName);
//读取配置文件 实例化我们工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
//通过反射机制获取接口对象
StudentMapper mapper = session.getMapper(StudentMapper.class);
//调用接口方法
List<Student> list = mapper.listStudentCourse();
//关闭
session.close();
for (Student student : list) {
System.out.println(student);
}
} catch (IOException e) {
e.printStackTrace();
}
}
动态sql
一个方法适应多种操作
Public List<Obje ct> getInfo(StudentVo vo){
String sql=”select * from emp ”;
If(vo.getName()!=null){
Sql+=” where name=”+vo.getName();
}
If(vo.getAge()!=null){
Sql+=”and age=”+vo.getAge()
}
}
Where标签:
代替了我们在sql中的where关键字,自动忽略紧邻where标签中的and或者是or条件连接符
<select id="getAllPerson" resultMap="newPerson" parameterType="PersonVo">
select * from person
<where>
and name=#{names}
</where>
</select>
If标签 :
根据传递过来的参数进行判断,可以灵活的拼接sql语句
1: 传入的参数为自己定义的对象类型
<select id="getAllPerson" resultMap="newPerson" parameterType="PersonVo">
select * from person
<where>
判断条件中我们使用变量名是传入参数的属性名称
<if test="names != null">
and name=#{names}
</if>
<if test="bir != null ">
or bir =#{bir}
</if>
</where>
</select>
2: 常见的数据类型为查询参数 需要在mapper接口中定义方法的时候使用 @Param 指定参数的名称
<select id="getAllPerson" resultMap="newPerson">
select * from person
<where>
<if test="names != null">
and name=#{names}
</if>
</where>
</select>
注意:
1: 判断条件中可以使用当前数据类型的方法
2: 可以在动态sql中使用导航
<select id="getAllPerson" resultMap="newPerson" parameterType="PersonVo">
select * from person
<where>
<if test="dog.dogname.length()>1">
and name=#{dog.dogname}
</if>
</where>
</select>
3: 在判断的条件中可以使用and or 等逻辑运算符
<select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
Choose when otherwise
选择的动态sql,类似于jstl标签库中选择标签,类似于java 中switch case语句
<select id="getAllPerson" resultMap="newPerson">
select * from person
<where>
<choose>
<when test="names != null">
name=#{names}
</when>
<when test="bir != null">
bir = #{bir}
</when>
<otherwise>
id=1
</otherwise>
</choose>
</where>
</select>
注意:
1:Otherwise 标签时不能写到when标签前面
2: 我们只能从多个条件选取一个执行。
Set标签
set标签就是代替sql语句中的set关键字,忽略最后成立条件的分隔符逗号
Update tname set name=ss,age=23,bir=ss where ….
<update id="updateInfo" parameterType="Person">
update person
<set>
<if test="age!=null">
age=#{age},
</if>
<if test="names !=null">
name = #{names},
</if>
</set>
where id=1
</update>
Trim标签
String trim() 去除字符串的前后空格
应用在where条件字句中,如果trim中包含的内容有成立的name就会在原有的sql基础上添加 prefix属性标记的前缀,如果没有成立,忽略trim标签,prefixOverrides=“and|or”,如果有条件成立,为了拼接sql语句会出现一些and or关键字 属性可以忽略第一个成立条件前面的and或者是or
<select id="getAllPerson" resultMap="newPerson" parameterType="PersonVo">
select * from person
<trim prefix="where" prefixOverrides="and|or" >
<if test="age != null">
age =#{age}
</if>
<if test="names !=null">
and name = #{names}
</if>
<if test="bir != null">
or bir = #{bir}
</if>
</trim>
</select>
Trim标签的set应用
条件成立在当前sql后面添加一个set关键字,如果后续的更新数据的字段后有逗号,trim会自动忽略我们的最后一个成立的逗号。
<update id="updateInfo" parameterType="Person">
update person
<trim prefix="set" suffixOverrides=",">
<if test="age!=null">
age=#{age},
</if>
<if test="names !=null">
name = #{names},
</if>
</trim>
where id=1
</update>
Foreach(循环—批量操作)
Foreach标签可以遍历传递的参数为集合类型的方法,批量的添加数据,批量更新数据
<insert id="batchAdd" parameterType="java.util.List">
insert into person(name,bir,age) values
<foreach collection="list" item="pp" separator=",">
(#{pp.names},#{pp.bir},#{pp.age})
</foreach>
</insert>
<delete id="batchDelete" parameterType="PersonVo">
delete from person where id in
<foreach collection="list" item="nid" open="(" close=")" separator=",">
#{nid}
</foreach>
</delete>
Foreach:
Collection=集合,直接list(关键字,不能写其它的)(传入的 参数就是我们的List),一个对象中的集合变量名称
Item:每次循环迭代的那一项数据
Index: 每次循环迭代的索引 从0开始递增
Separator: 每一次迭代的项和下一项之间的分隔符
Open: 整个循环的结果包含在哪种符号里,符号的开始
Close:整个循环的结果包含在哪种符号里,符号的结束
批量更新
<update id="batchupdate" parameterType="java.util.List">
<foreach collection="list" item="pa" separator=";">
update person
<set>
<if test="pa.age != null">
age = #{pa.age},
</if>
<if test="pa.names !=null">
name = #{pa.names},
</if>
<if test="pa.bir != null">
bir = #{pa.bir}
</if>
</set>
<where>
id = #{pa.id}
</where>
</foreach>
</update>
Mysql数据库自身是不允许批量更细的,所以我们要在数据库的连接的url中设定批量更新的参数
jdbc:mysql://localhost:3306/0903dbs?allowMultiQueries=true
延迟加载策略
什么是延迟加载
resultMap 中的 association 和 collection 标签具有延迟加载的功能。
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息
时再去按需加载关联信息。这样会大大 高数据库性能,因为查询单表要比关联查询多张
表速度要快。
关联对象数据:查询当前的人员信息,这一时刻不想去使用当前人对应的订单,在后面的逻辑会使用当前用户的关联数据。(按需加载)
Mybatis 默认是不开启延迟加载功能的,我们需要手动开启。
需要在 SqlMapConfig.xml 文件中,在 标签中开启延迟加载功能。
Mybatis设定了懒加载的设置模式:
<settings>
<!-- 开启了延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭了立即加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 声明触发延迟加载的方法 -->
<setting name="lazyLoadTriggerMethods" value=""/>
</settings>
缓存机制
缓存:临时存储数据的空间,我们二次获取相同数据的时候我们就可以直接从临时存储空间获取,不用去数据库查询,减少数据库的io访问,提高程序的响应效率。
1:一级缓存
SqlSession: 就是我们一级缓存,必须使用的缓存机制,但是如果我们将session关闭之后一级缓存就失效了。
-
第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息, 如果没有,从数据库查询用户信息。
-
得到用户信息,将用户信息存储到一级缓存中。
-
如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存, 这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
-
第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息, 缓存中有,直接从缓存中获取用户信息。
Mybatis 默认支持一级缓存。
示例:
Person onePerson = mapper.getOnePerson(16);
System.out.println(onePerson);
//从缓存中获取的数据
Person onePerson2 = mapper.getOnePerson(16);
System.out.println(onePerson2);
2: 二级缓存
二级缓存图解
二级缓存是 mapper 级别的。
1、第一次调用 mapper 下的 SQL 去查询用户信息。查询到的信息会存到该 mapper 对应的 二级缓存区域内。
2、第二次调用相同 namespace 下的 mapper 映射文件中相同的 SQL 去查询用户信息。会 去对应的二级缓存内取结果。
3、如果调用相同 namespace 下的 mapper 映射文件中的增删改 SQL,并执行了 commit 操作。 此时会清空该 namespace 下的二级缓存。
***\*开启二级缓存\****
Mybatis 默认是开启二级缓存 我们使用的版本默认是开启的
1、在核心配置文件 SqlMapConfig.xml 中加入以下内容(开启二级缓存总开关): 在 settings 标签中添加以下内容:
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
2、 在mapper配置文件中:
<!-- 开启本mapper下的namespace的二级缓存,默认使用的是mybatis 供的 PerpetualCache -->
<cache></cache>
***\*实现序列化\****
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给
缓存的对象执行序列化。
如果该类存在父类,那么父类也要实现序列化。
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查询 ID 为 1 的用户,去缓存找,找不到就去查找数据库
User user1 = mapper1.findUserById(1);
System.out.println(user1);
// 关闭SqlSession1
sqlSession1.close();
// 第二次查询ID为1的用户
User user2 = mapper2.findUserById(1);
System.out.println(user2);
// 关闭SqlSession2
sqlSession2.close();
}
Cache Hit Radio : 缓存命中率
第一次缓存中没有记录,则命中率 0.0;
第二次缓存中有记录,则命中率 0.5(访问两次,有一次命中)
测试2
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查询 ID 为 1 的用户,去缓存找,找不到就去查找数据库
User user1 = mapper1.findUserById(1);
System.out.println(user1);
// 关闭 SqlSession1
sqlSession1.close();
// 修改查询出来的 user1 对象,作为插入语句的参数
user1.setUsername(" 东哥 1");
user1.setAddress(" 清河宝盛西里 ");
mapper3.insertUser(user1);
// 交事务
sqlSession3.commit();
// 关闭 SqlSession3
sqlSession3.close();
// 第二次查询ID为1的用户
User user2 = mapper2.findUserById(1);
System.out.println(user2);
// 关闭 SqlSession2
sqlSession2.close();
}
SQL 输出结果:
根据 SQL 分析,确实是清空了二级缓存了。
#{} 和${}的使用
#{}: 占位符 PreparedStatement sql较为简洁,避免sql注入风险
${}: 字符串拼接 Statement,拼接字符串sql语句较为繁琐,sql注入风险。
<!-- 根据用户名称模糊查询用户信息列表 -->
<!--
[${}]:表示拼接 SQL 字符串
[${value}]:表示要拼接的是简单类型参数。
注意:
1、如果参数为简单类型时,${} 里面的参数名称必须为 value
2、${} 会引起 SQL 注入,一般情况下不推荐使用。
但是有些场景必须 使用 ${},比如 order by ${colname}
-->
<select id="findUsersByName" parameterType="String" resultType="com. offcn.po.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
mybatis逆向工程
构建表:构建表对应数据模型,mapper接口,mapper.xml文件都需要我们手动完成,开发效率比较低,mybatis提供一个插件,可以帮助我们在开发中生成需要文件。
MybatisPlus---》mybatis框架的一个扩展工具,逆向工程,bean mapper service controller(了解)
1: 导入工具包
Generator-core.jar 逆向工程的核心jar包
2: 按照官方文档去创建一个配置文件
逆向工程的官网
http://www.mybatis.org/generator/running/runningWithJava.html:
3: 书写核心代码生成我们需要的文件。