Mybatis的延迟加载
何为延迟加载
通过前面的学习,我们已经掌握了 Mybatis中多表查询的配置及实现,可以实现对象的关联查 询。实际开发过程中很多时候我们并不需要在加载用户信息时就一定要加载他的订单信息。此时 就是我们所说的延迟加载。
作用
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处
能,因为查询单表要比关联查 询多张表速度要快。
应用
通常情况下,一对一查询不需要做延迟加载,一对多需要做延迟加载
一对一延迟加载实现
使用前提
需要在SqlMapConfig.xml 配置文件中开启延迟加载
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
bean类:
public class Employee {
private int eid;
private String ename;
private Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public Employee(int eid, String ename, Dept dept) {
this.eid = eid;
this.ename = ename;
this.dept = dept;
}
public Employee() {
}
public Employee(int eid, String ename) {
this.eid = eid;
this.ename = ename;
}
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
@Override
public String toString() {
return "Employee{" +
"eid=" + eid +
", ename='" + ename + '\'' +
", dept=" + dept +
'}';
}
}
SqlMapConfig.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 resource="jdbc.properties"></properties>
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<typeAliases>
<package name="com.qfedu.bean"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${jdbcUrl}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.qfedu.dao"/>
</mappers>
</configuration>
EmployeeDao.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="com.qfedu.dao.EmployeeDao">
<resultMap id="employeeRM" type="employee">
<id property="eid" column="eid"></id>
<result property="ename" column="ename"></result>
<association property="dept" javaType="dept">
<id property="did" column="did"></id>
<result property="dname" column="dname"></result>
</association>
</resultMap>
<select id="selectEmployeeById" parameterType="int" resultMap="employeeRM">
select * from tb_employee,tb_dept where tb_employee.dno = tb_dept.did and eid = #{eid}
</select>
</mapper>
测试:
public class EmployeeDaoTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
}
@Test
public void selectEmployeeById() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
Employee employee = employeeDao.selectEmployeeById(1);
System.out.println(employee.getEname());
}
}
一对多延迟加载实现
EmployeeDao.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="com.qfedu.dao.EmployeeDao">
<resultMap id="employeeRM1" type="employee">
<id property="eid" column="eid"></id>
<result property="ename" column="ename"></result>
<!--第二次单表查询 : 查询部门-->
<association property="dept"
javaType="dept"
select="com.qfedu.dao.DeptDao.selectDeptById1"
column="dno"
fetchType="eager"></association>
</resultMap>
<!--第一次单表查询-->
<select id="selectEmployeeById1" parameterType="int" resultMap="employeeRM1">
select eid , ename , dno from tb_employee where eid = #{eid}
</select>
<select id="selectEmployeeListByDid" parameterType="int" resultType="employee">
select * from tb_employee where dno = #{did}
</select>
</mapper>
测试:
public class EmployeeDaoTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
}
@Test
public void selectEmployeeById1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
Employee employee = employeeDao.selectEmployeeById1(1);
//没有使用部门信息
// System.out.println(employee.getEname());
//使用部门信息
System.out.println(employee.getDept().getDname());
}
//立即加载 : 不管有没有使用到关联表中的信息,都会去查询关联表 相当于 多表查询
//延迟加载 : 如果没有使用到关联表中的信息,就不会去查询关联表
}
MyBatis的缓存
什么是缓存
存储在内存中的临时数据
为什么使用缓存
减少和数据库的交互次数,提高执行效率
应用场景
1,使用于缓存
- 经常查询并且不经常改变的
- 数据的正确与否对最终结果影响不大
2,不适用于缓存
- 数经常改变的
- 数据的正确与否对最终结果影响不大
比如:
- 商品库存、银行汇率…
一级缓存的验证
-
概念
一级缓存是SQLSession范围的缓存,当调用SqlSession的修改、添加、删除,commit()、close()等方法时,就会清空以及缓存。 -
验证
public interface UserDao { User selectUserById(int id) throws Exception; } <?xml version="1.0" encoding="UTF-8" ?>
<cache></cache>
<select id="selectUserById" parameterType="int" resultType="user" >
select
*
from
tb_user
where
id = #{id}
</select>
<!--
useCache="true" 支持二级缓存
-->
<select id="selectUserById1" parameterType="int" resultType="user" useCache="true">
select * from tb_user where id = #{id}
</select>
</mapper>
public class UserDaoTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
}
@Test
public void selectUserById() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
//第一次查询,user1存放到一级缓存中,范围在sqlSession中
User user1 = userDao.selectUserById(1);
//第二次查询,会直接从缓存中获取这条记录,也就是说,不会执行sql语句
User user2 = userDao.selectUserById(1);
//user1和user2这两个对象,是否是同一个对象了? 同一个对象!!! 是否是同一个对象,不重要! 重要的是减少了操作数据库的次数!!!
System.out.println(user1 == user2);
sqlSession.close();
}
}
一级缓存清空
close:可以清空一级缓存
commit:可以清空一级缓存
添加记录:可以清空一级缓存
删除记录:可以清空一级缓存
修改记录:可以清空一级缓存
为了保证数据的时效性!!!
增删改清空以及缓存
-
概念
如果SqlSession去执行commit操作(执行插入、更新、删除), 清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息 -
以修改操作为例:
public interface UserDao { void addUser(User user) throws Exception; } <insert id="addUser" parameterType="user"> insert into tb_user(username,password) values (#{username},#{password}) </insert> @Test public void selectUserById2() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); //user1存储到sqlSession中 User user1 = userDao.selectUserById(1); sqlSession.commit(); User user2 = userDao.selectUserById(1); sqlSession.close();
}
MyBatis的二级缓存
-
概念
二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存, 二级缓存是跨SqlSession的 -
使用步骤
-
开启二级缓存
<settings> <!--开启缓存--> <setting name="cacheEnabled" value="true"/> </settings>
-
在mapper映射文件配置标签
<mapper namespace="com.qzw.dao.IUserDao"> <!‐‐ 开启二级缓存的支持 ‐‐> <cache></cache> </mapper>
-
配置statement上面的userCache属性
<!-- useCache="true" 支持二级缓存 --> <select id="selectUserById1" parameterType="int" resultType="user" useCache="true"> select * from tb_user where id = #{id} </select>
-
-
注意事项
- 二级缓存存储的并不是java对象,存储的是对象所对应的字符串信息,当从二级缓存取出 时,根据对应字符串生成新的对象,所以,使用二级缓存,会发现取出对象是不同的对象。 但是,sql语句只执行了一次。
-
测试代码
@Test public void selectUserById1() throws Exception { SqlSession sqlSession1 = sqlSessionFactory.openSession(); UserDao userDao = sqlSession1.getMapper(UserDao.class); //user1存储到sqlSession中 User user1 = userDao.selectUserById(1); sqlSession1.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); UserDao userDao1 = sqlSession2.getMapper(UserDao.class); User user2 = userDao1.selectUserById(1); sqlSession2.close();
}