需要查询关联信息时,使用 Mybatis 懒加载特性可有效的减少数据库压力,首次查询只查询主表信息,关联表的信息在用户获取时再加载。
Mybatis 一对一关联的 association 和一对多的 collection 可以实现懒加载。懒加载时要使用 resultMap,不能使用 resultType。
启动懒加载
Mybatis 默认没有打开懒加载配置,需要在 SqlMapperConfig.xml 中通过settings 配置 lazyLoadingEnabled 来开启懒加载。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
settings>
我们建立一个实例来体现懒加载,体现懒加载的优势
创建一个方法用来创建SqlSessionFactory负责创建每次会话
package com.util;
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 java.io.IOException;
import java.io.InputStream;
public class SqlSessionUtil {
static SqlSessionFactory sqlSessionFactory;
static {
//读取mybatis配置文件信息
try {
InputStream in = Resources.getResourceAsStream("myBatis-configer.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
//创建SqlSessionFactory负责创建每次会话的sqlSession==connection
//创建开销比较大,所以整个应用程序只需要创建一个
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
我们创建个bean类
package com.pojo;
//一个emp员工类
public class Emp {
private int id;
private String name;
private int age;
private Dept dept;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
package com.pojo;
import java.util.List;
public class Dept {
private int id;
private String name;
private List<Emp> empList;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
}
empDao接口
package com.dao;
import com.ff.pojo.Emp;
import org.apache.ibatis.annotations.Param;
public interface EmpDao {
// 延迟加载
Emp findEmpById1(@Param("id") int id);
}
EmpMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.EmpDao">
<resultMap id="EmpMap1" type="Emp">
<id property="id" column="id">id>
<result property="name" column="name">result>
<result property="age" column="age">result>
<association property="dept" javaType="Dept"
select="findDeptById" fetchType="lazy" column="dept_id">
<id property="id" column="id">id>
<result property="name" column="name">result>
association>
resultMap>
<select id="findEmpById1" resultMap="EmpMap1">
select id,name,age,dept_id,user_id from emp where id = #{id}
select>
<select id="findDeptById" resultType="Dept">
select id,name from dept where id = #{id}
select>
mapper>
package com.ff.test;
import com.ff.dao.EmpDao;
import com.ff.dao.UserDao;
import com.ff.pojo.Dept;
import com.ff.pojo.Emp;
import com.ff.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class emp {
@Test
public void findEmpById() throws IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpDao empDao = sqlSession.getMapper(EmpDao.class);
empDao.findEmpById(1);
sqlSession.commit();
sqlSession.close();
}
}
他会将两个表关联查询,所有的信息全部加载出来
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 396883763.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
==> Preparing: SELECT e.id eId, e.name eName, e.age, d.id dId, d.name dName/*, u.id uId, u.user_name uName*/ FROM emp e LEFT JOIN dept d ON e.dept_id = d.id /*LEFT JOIN USER u ON e.user_id = u.id*/ WHERE e.id = ?
==> Parameters: 1(Integer)
<== Columns: eId, eName, age, dId, dName
<== Row: 1, 小崔, 20, 1, 科技部
<== Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Returned connection 396883763 to pool.
Process finished with exit code 0
我们创建一个test方法,用来调用service中的方法
package com.test;
import com.ff.dao.EmpDao;
import com.ff.pojo.Dept;
import com.ff.pojo.Emp;
import com.ff.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class emp {
@Test
public void findEmpById() throws IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpDao empDao = sqlSession.getMapper(EmpDao.class);
//延迟加载
Emp emp = empDao.findEmpById1(2);
System.out.println(emp.getName());
//如果不调用emp中的关于Dept的方法,就不会查询部门信息,只会查询emp的数据库信息
System.out.println("__________________________________");
System.out.println(emp.getDept().getName());
sqlSession.close();
}
}
运行结果
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 396883763.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
==> Preparing: select id,name,age,dept_id from emp where id = ?
==> Parameters: 1(Integer)
<== Columns: id, name, age, dept_id
<== Row: 1, 小崔, 20, 1
<== Total: 1
小崔
__________________________________
==> Preparing: select id,name from dept where id = ?
==> Parameters: 1(Integer)
<== Columns: id, name
<== Row: 1, 科技部
<== Total: 1
科技部
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Returned connection 396883763 to pool.
Process finished with exit code 0
我们会发现,只有需要部门信息 的时候他才会查询,两张表上的信息他是分两次查询,这样就减少了数据库的开销