MyBatis-相关知识点
1. Mybatis 执行流程
1.1 mybatis-config.xml中主要配置数据库连接和mapper接口信息
1.2 MappedStatement对象中的主要属性有:
① resource : mapper.xml的路径信息
② id : dao层中关联mapper的方法
③ SqlSource : 需要执行的Sql信息
④ resultMaps: 查询数据的结果
2. MyBatis 支持延迟加载,但是默认关闭
2.1 延迟加载的原理
① 使用CGLIB 创建目标对象的代理对象
② 当调用目标方法 user.selectUserById()时,进入拦截器invoke方法,发现user.getOrderList()是Null值,执行Sql查询order列表
③ 查询order列表后,调用user.setOrderList方法赋值。
此处疑问:如果开启延迟加载,已经获取了orderList,,并且不为null,此时数据库插入一条改用的订单记录,再次使用user的getOrderList方法,结果是否改变?
延迟加载的代码演示
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><setting name="cacheEnabled" value="true"/><!--开启二级缓存--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启驼峰命名--><setting name="lazyLoadingEnabled" value="true"/><!--全局开启延迟加载--></settings><typeAliases><package name="org.example.day03.entity"></package></typeAliases><!--配置环境--><environments default="mysql"><!--配置mysql的环境--><environment id="mysql"><!--配置事务--><transactionManager type="JDBC"></transactionManager><!--配置连接池--><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql://127.0.0.1:3306/spring_study?useSSL=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"></property><property name="username" value="aaa"></property><property name="password" value="ccc"></property></dataSource></environment></environments><!--配置映射文件的位置--><mappers><package name="org.example.day03.mapper"></package></mappers>
</configuration>
实体类 User Order
package org.example.day03.entity;import java.io.Serializable;
import java.util.List;public class User implements Serializable {private Integer id;private String username;private List<Order> orderList;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public List<Order> getOrderList() {return orderList;}public void setOrderList(List<Order> orderList) {this.orderList = orderList;}public User() {}public User(Integer id, String username) {this.id = id;this.username = username;}public User(Integer id, String username, List<Order> orderList) {this.id = id;this.username = username;this.orderList = orderList;}
}package org.example.day03.entity;import java.io.Serializable;public class Order implements Serializable {private Integer id;private String name;private Integer userId;public Order(Integer id, String name, Integer userId) {this.id = id;this.name = name;this.userId = userId;}public Order(String name, Integer userId) {this.name = name;this.userId = userId;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Order(Integer id, String name) {this.id = id;this.name = name;}public Order() {}@Overridepublic String toString() {String value = "id="+this.id+";name="+this.name;return value;}}
mapper接口
package org.example.day03.mapper;import org.example.day03.entity.User;public interface UserMapper {User selectUserById(Integer id);
}package org.example.day03.mapper;import org.example.day03.entity.Order;public interface OrderMapper {Order findOrderByUserId(Integer userId);int insertOrder(Order order);
}
mapper.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="org.example.day03.mapper.OrderMapper"><select id="findOrderByUserId" resultType="org.example.day03.entity.Order">SELECT * FROM tb_order WHERE user_id = #{id}</select><insert id="insertOrder" parameterType="org.example.day03.entity.Order">INSERT INTO tb_order (name, user_id)VALUES (#{name}, #{userId})</insert>
</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="org.example.day03.mapper.UserMapper"><!-- 定义ResultMap --><resultMap id="UserResultMap" type="org.example.day03.entity.User" autoMapping="true"><id property="id" column="id"/><result property="username" column="username"/><!-- 可以添加更多的association或collection映射 --><collection property="orderList" ofType="org.example.day03.entity.Order"select="org.example.day03.mapper.OrderMapper.findOrderByUserId" column="id"></collection></resultMap><!-- 使用ResultMap的查询 --><select id="selectUserById" resultMap="UserResultMap">SELECT * FROM tb_user WHERE id = #{id}</select>
</mapper>
启动测试类
package day03;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.example.day03.entity.Order;
import org.example.day03.entity.User;
import org.example.day03.mapper.OrderMapper;
import org.example.day03.mapper.UserMapper;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class MybatisTest {@Testpublic void testSelectUser() throws IOException {//1. 加载 mybatis-config.xml 获取SqlSessionFactoryInputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 通过获取UserMapper接口的代理对象 执行SqlUserMapper userMapper = sqlSession.getMapper(UserMapper.class);User user = userMapper.selectUserById(2);System.out.println(user.getUsername());System.out.println("---------------------");List<Order> orderList = user.getOrderList();System.out.println(orderList);/*//插入一条订单记录OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);Order order = new Order("新的记录",2);int index = orderMapper.insertOrder(order);sqlSession.commit();if(index > 0){System.out.println("order写入成功");System.out.println(user.getOrderList());}*///4.关闭资源inputStream.close();sqlSession.close();}
}
当关闭延迟加载时,输出结果如下:
打开延迟加载:
局部开启方式:
userMapper.xml
<collection property="orderList" ofType="org.example.day03.entity.Order"select="org.example.day03.mapper.OrderMapper.findOrderByUserId" column="id" fetchType="lazy"></collection>
全局开启方式:
mybatis-config.xml
<settings><setting name="cacheEnabled" value="true"/><!--开启二级缓存--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启驼峰命名--><setting name="lazyLoadingEnabled" value="true"/><!--开启延迟加载--></settings>
开启延迟加载后的输出情况:
3. 一级缓存和二级缓存
3.1 一级缓存 基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session进行flush或close之后,该session中的所有cache将会清空。默认打开一级缓存。
3.2 二级缓存 基于namespace 和 mapper 的作用域起作用的,不依赖于session,默认也是采用PerpetualCache的HashMap缓存。
二级缓存默认是关闭的,开启方式有两步:
① 全局配置文件 mybatis-config.xml
<settings><setting name="cacheEnabled" value="true"/><!--开启二级缓存--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启驼峰命名--><setting name="lazyLoadingEnabled" value="true"/><!--开启延迟加载--></settings>
② 相应的mapper.xml文件,添加 <cache/>标签