ibatis延迟加载的含义(可能我讲不太清楚,具体看下面代码就明白什么含义了):
在牵涉到1:N关系,或 N:N关系的时候查询,那么会需要查询多张表,但并不是所有情况都会需要查询另一张相关的表。
采用延迟加载可以在真正使用的时候去查询另一张相关表。提高性能。
我用的是maven构建我的测试代码,其中pom文件配置如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yajun</groupId> <artifactId>IbatisDemo</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>IbatisDemo</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.ibatis</groupId> <artifactId>ibatis-sqlmap</artifactId> <version>2.3.4.726</version> <scope>compile</scope> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.4</version> <scope>provide</scope> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>1.0</version> <scope>complie</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.9</version> <scope>provide</scope> </dependency> </dependencies> </project>
先把我遇到的问题抛下出来,大家在用的时候也注意下吧,不知道是不是我个人的问题:
第一个问题:
cacheModelsEnabled="true" 与 lazyLoadingEnabled="true" 相冲突?
如果启用延迟加载,并且启用 cacheModelsEnabled="true",那么会报如下错误
Caused by: java.io.NotSerializableException: com.ibatis.sqlmap.engine.mapping.result.loader.LazyResultLoader
网上搜罗了一圈找到这个:http://issues.apache.org/jira/browse/IBATIS-529
是否是个BUG?
第二个问题:
lazyLoadingEnabled="true"
enhancementEnabled="true" 这二项在<settings/>中默认为true,如果没有在config.xml中没有出现<settings/>,就当做false来处理。
enhancementEnabled="true"时要在项目中 导入cglib的jar。
如果enhancementEnabled="false",lazyLoadingEnabled="true",延迟加载只对某个属性为集合生效。
如果属性是个类,则不会延迟加载。
ibatis的其它功能还须其它jar,继续摸索中。
========================================================================
下面开始我的测试。
第一步,构建我的测试代码
建立DO类 BabyDO和AddressDO,其中 baby 的id 和address 的id是相关联的:
package com.yajun.dataobject;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.time.DateFormatUtils;
import com.yajun.enumdemo.SexEnum;
/**
* Baby DO类
*
* @author yajun
*
*/
public class BabyDO implements Serializable {
private static final long serialVersionUID = -579987226803641422L;
private int id;
private String name; // 姓名
private SexEnum sex; // 性别
private Date birthday; // 生日
private String hobby; // 喜好
private int age; // 年龄 注意这里是原生类型
private List<AddressDO> address; // 地址复杂类型
// 一堆get set 方法
public List<AddressDO> getAddress() {
return address;
}
public void setAddress(List<AddressDO> address) {
this.address = address;
}
@Override
public String toString() {
String s = "id :" + id + "\t" + "name :" + name + "\t" + "\t" + "birthday:"
+ DateFormatUtils.format(birthday, "yyyy-MM-dd") + "\t" + "hobby:" + hobby;
if (address != null) {
s = address.toString();
}
return s;
}
}
package com.yajun.dataobject;
import java.io.Serializable;
/**
* 地址类
*
* @author yajun
*
*/
public class AddressDO implements Serializable {
private static final long serialVersionUID = -7544474673567062502L;
private Integer id; // id 与 baby的id关联
private String address; // 地址
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
第二步,配置文件
baby.xml中重要配置
<resultMap id="baby-Result" class="baby"> <result property="id" column="id" jdbcType="Integer" javaType="integer" /> <result property="name" column="name" jdbcType="VARCHAR" javaType="string" /> <result property="sex" column="sex" jdbcType="VARCHAR" javaType="com.yajun.enumdemo.SexEnum" typeHandler="com.yajun.typehandler.SexEnumTypeHandlerCallBack" /> <result property="birthday" column="birthday" jdbcType="DATE" javaType="date" /> <result property="hobby" column="hobby" jdbcType="VARCHAR" javaType="string" /> <result property="age" column="age" jdbcType="INTEGER" javaType="int" nullValue="0" /> <result property="address" select="getAddressById" column="id" /> </resultMap> <select id="getBabyByParams" resultMap="baby-Result" cacheModel="baby-cache"> select * from Baby <dynamic prepend="where"> <isPropertyAvailable property="name" prepend="and"> name = #name# </isPropertyAvailable> <isPropertyAvailable property="sex" prepend="and"> sex = #sex,jdbcType=VARCHAR,javaType=com.yajun.enumdemo.SexEnum# </isPropertyAvailable> <isPropertyAvailable property="BirthdayBondStart" prepend="and"> <![CDATA[ birthday >= cast(#BirthdayBondStart# as datetime) ]]> </isPropertyAvailable> <isPropertyAvailable property="BirthdayBondEnd" prepend="and"> <![CDATA[ birthday <= cast(#BirthdayBondEnd# as datetime) ]]> </isPropertyAvailable> <isPropertyAvailable property="hobby" prepend="and"> hobby like #hobby#||'%' </isPropertyAvailable> </dynamic> </select>
address.xml中重要配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="babyStore"> <typeAlias alias="address" type="com.yajun.dataobject.AddressDO" /> <resultMap id="address-Result" class="address"> <result property="id" column="id" jdbcType="INTEGER" javaType="integer"/> <result property="address" column="address" jdbcType="VARCHAR" javaType="string" /> </resultMap> <select id="getAddressById" resultMap="address-Result"> select * from address where id = #id# </select> </sqlMap>
sqlMapConfig.xml中重要配置
<settings lazyLoadingEnabled="true" cacheModelsEnabled="true"></settings>
第三步,建立测试类:
package com.yajun;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.yajun.dataobject.BabyDO;
import com.yajun.impl.BabyDAOImpl;
/**
* 专门测试延迟加载的
*
* @author yajun
*
*/
public class LazyLoadTest {
private BabyDAOImpl babyDAO = new BabyDAOImpl();
public static void main(String[] args) throws SQLException {
LazyLoadTest test = new LazyLoadTest();
// System.out.println(test.addressDAO.query(9));
Map<String, Object> params = new HashMap<String, Object>();
params.put("name", "吴亚军");
List<BabyDO> list = test.babyDAO.testBabyLazyLoad(params);
BabyDO baby = list.get(0);
System.out.println(baby.getId());
System.out.println(baby.getHobby());
System.out.println(baby.getAge());
System.out.println(baby.getAddress());
}
}
BabyDAOImpl 中重要代码
/**
* 测试延迟加载的
*
* @param params
* @return
* @throws SQLException
*/
public List<BabyDO> testBabyLazyLoad(Map params) throws SQLException {
return client.queryForList("getBabyByParams", params);
}
第四步,调试可得当执行到
System.out.println(baby.getAddress);
这句话的时候并没有地址,地址那个属性是个被代理过的类,当真正去取address的时候才把这个类查出来。
那么延迟加载和连接查询,到底选用哪一个就要看使用者平衡了:
延迟加载 | Join |
如果要加载大量的数据,它们不会马上用到,延迟加载会比较合适。 | 数据量较小或者数据马上就会用到, Join方法比较合适。 |
我觉得还有一条很重要的原则,那就是永远只加载必需的数据 。