1、myBatis的延迟加载一般使用在一对多、一对一的场景中,即一些信息当需要时才会去加载;
相对的也就有即时加载,主要在多对一,多对多场景中使用。
2、一对一场景下实现延迟加载
2.1、myBatis配置文件中的配置:
<?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 url="file:///E:/Idea/MyBatis01/src/main/resources/jdbcConfig.properties">
</properties>
<!--设置延迟加载开关-->
<!--配置参数,此处需要注意settings标签要优先于typeAliases标签-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<typeAliases>
<package name="Model"></package>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的必备信息 type属性表示是否使用数据源(连接池)
property标签中value属性值java:comp/env/ 此为固定写法 ;
jdbc/mybatis 数据源名称(在META-INF中的配置文件中配置的数据)
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--此处使用package标签配置映射需要注意,接口映射文件与SQL映射文件必须是一一对应的,不然编译会出现异常-->
<package name="myBatis.dao"></package>
</mappers>
</configuration>
2.2、SQL映射文件配置:
<?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="myBatis.dao.JNDIMapper">
<resultMap id="userAccountJNDI" type="userAcountJNDI">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="accounts" ofType="account">
<id property="id" column="aid"></id>
<result property="uid" column="UID"></result>
<result property="money" column="MONEY"></result>
</collection>
</resultMap>
<!--账户与用户一一对应的关系:
此处主要是实现一一对应关系的懒加载(延迟加载)
-->
<resultMap id="accountUser" type="accountUsermodel">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--此处的column属性必须写,属性的值作为select属性中引用的查询sql的参数-->
<association property="user" column="uid" javaType="userCRUDmodeltwo" select="myBatis.dao.IUserCRUDDao.queryUserInfoById"></association>
</resultMap>
<select id="getAllUserInfo" resultMap="userAccountJNDI">
SELECT u.*,
a.id aid,
a.UID,
a.MONEY
FROM user u
left join account a
on a.UID = u.id
</select>
<select id="getAccountUserByLazy" resultMap="accountUser">
select * from account
</select>
</mapper>
上述延迟加载是引用的SQL为根据id查询用户信息:
2.3、封装实体类:
package Model;
/**
* 账户-人员 一对一的关系加载
*/
public class accountUserModel {
private Integer id;
private Integer uid;
private Double money;
private userCRUDModelTwo user;
public userCRUDModelTwo getUser() {
return user;
}
public void setUser(userCRUDModelTwo user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "accountUserModel{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
", user=" + user +
'}';
}
}
3、测试方法:
InputStream in=null;
SqlSessionFactoryBuilder ssfb = null;
SqlSessionFactory ssf = null;
SqlSession ss = null;
JNDIMapper jndi;
//初始化操作
@Before //Junit注解,在@Test之前运行
public void init() throws IOException {
in = Resources.getResourceAsStream("MyBatis_LAZY.xml");
ssfb = new SqlSessionFactoryBuilder();
ssf = ssfb.build(in);
ss = ssf.openSession();
jndi = ss.getMapper(JNDIMapper.class);
}
//释放资源,在@Tes之后运行
@After
public void close() throws IOException {
ss.commit();//提交操作,此处要注意设置,此处默认没有自动提交
ss.close();
in.close();
}
/**
* 查询操作
*/
@Test
public void queryAccountUserByLazy(){
List<accountUserModel> list = jndi.getAccountUserByLazy();
for ( accountUserModel accountUser:list
) {
System.out.println(accountUser);
//System.out.println(accountUser.getUser()); //触发加载用户信息(延迟加载的信息)
}
}
**4、**此处需要注意的是,在配置文件中配置延迟加载的开关是需要用到CGLIB包,不然会报错:
org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in SQL Mapper Configuration
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:79)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:63)
at myBatisDemo.JNDITest.init(JNDITest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:106)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:89)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:77)
... 25 more
Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
at org.apache.ibatis.executor.loader.CglibProxyFactory.<init>(CglibProxyFactory.java:50)
at org.apache.ibatis.session.Configuration.setLazyLoadingEnabled(Configuration.java:275)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.settingsElement(XMLConfigBuilder.java:199)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:100)
... 27 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: net.sf.cglib.proxy.Enhancer
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:188)
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:87)
at org.apache.ibatis.io.Resources.classForName(Resources.java:254)
at org.apache.ibatis.executor.loader.CglibProxyFactory.<init>(CglibProxyFactory.java:48)
此时需要在pom.xml文件中引入包CGLIB:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
5、扩展:一对多的延迟加载配置:
SQL映射文件配置:
<!--用户与账户信息 一对多的关系:
主要实现一对多关系的延迟加载
-->
<resultMap id="userAccountLazy" type="userAcountJNDI">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="accounts" ofType="account" select="myBatis.dao.JNDIMapper.getAccountByUId" column="id">
</collection>
</resultMap>
----------------------------------------------
<select id="getQueryAllUserAccountByLazy" resultMap="userAccountLazy">
select * from user
</select>
-------------------------------------------------------
<resultMap id="accountResult" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</resultMap>
<select id="getAccountByUId" resultMap="accountResult" parameterType="int">
select * from account where uid = #{uid}
</select>