欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Mybatis-详解2

程序员文章站 2022-05-23 14:16:36
...


11、MyBatis的注解使用方式

12、mybatis的参数传递

12.1、一个普通数据类型

12.2、多个普通数据类型

12.3、传递一个Map对象作为参数

12.4、一个Pojo数据类型

12.5、多个Pojo数据类型

12.6、模糊查询

12.7#{}${}的区别

12.7.2MySQL的字符串拼接,concat函数实现官方推荐)

13、自定义结果集<resultMap></resultMap> 

13.1<resultMap>的作用

13.2、创建一对一数据库表

13.3、创建实体对象

13.4一对一 级联属性 使用

13.4.2<association /> 嵌套结果集映射配置(取代result的级联映射)

13.5、延迟加载

13.5.1<association /> 定义分步查询使用延迟加载

13.6、多对一、一对多的使用示例

13.6.1、创建一对多数据库

13.6.2<collection/> 一对多,立即加载

13.6.3、一对多,赖加载(需要创建副表接口和Mapper.xml

13.6.4、双向关联

 


11MyBatis的注解使用方式(主要使用xml


public interface UserMapper {

	@SelectKey(before = false, statement = "select last_insert_id()", keyProperty = "id", resultType = Integer.class)
	@Insert(value = "insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})")
	public int saveUser(User user);

	@Select(value = "select id,last_name lastName,sex from t_user where id = #{id}")
	public User queryUserById(int id);

	@Select(value = "select id,last_name lastName,sex from t_user")
	public List<User> queryUsers();

	@Delete(value = "delete from t_user where id = #{id}")
	public int deleteUserById(int id);

	@Update(value = "update t_user set last_name = #{lastName},sex = #{sex} where id = #{id}")
	public int updateUser(User user);

}

测试方法就是传统的测试方法,不贴了

12、mybatis的参数传递

12.1、一个普通数据类型

推荐使用#{变量名}(优先)  #{value}

方法:

public User queryUserById(int id);

xml中传递参数值的使用方法:


<!-- 	public User queryUserById(int id); -->
	<select id="queryUserById" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where id = #{id}
	</select>

12.2、多个普通数据类型

 

在方法的参数是多个普通数据类型的情况,传递的参数的方式是使用#{ param1 }#{param2} ……或01

 

第一个参数使用#{param1}传递

第二个参数使用#{param2}传递

第三个参数使用#{param3}传递

……

N个,参数使用#{paramN}传递

 

代码方法是:

public List<User> queryUsersByNameAndSex(String name, int sex);

 

xml中传递参数值的使用方法:

<!-- 	public List<User> queryUsersByNameAndSex(String name, int sex); -->
	<select id="queryUsersByNameAndSex" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where last_name like #{param1} and sex = #{param2}
	</select>

@Param注解命名参数

 

代码中:

public List<User> queryUsersByNameAndSex(@Param("name") String name,
			@Param("sex") int sex);

在xml中传递参数如下:
	<select id="queryUsersByNameAndSex" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where last_name like #{name} and sex = #{sex}
	</select>

12.3、传递一个Map对象作为参数

 

当代码中以map做为参数值传递。

Map<String, Object>param = new HashMap<String, Object>();

param.put("name", "%bbb%");

param.put("sex", 1);

那么在xml中配置的时候,以#{mapKey}的方式输出参数值。

 

代码:

public List<User> queryUsersByMap(Map<String, Object> param);

 

 

xml中如何输入map中参数的值:

<!-- 	public List<User> queryUsersByMap(Map<String, Object> param);  -->
	<select id="queryUsersByMap" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where last_name like #{name} and sex = #{sex}
	</select>

12.4、一个Pojo数据类型

如果传入的参数是pojo数据类型(javaBean对象)。那么在xml中使用#{属性名}

 

代码中:

public List<User> queryUsersByUser(User user);

 

xml配置文件中:

<!-- 		public List<User> queryUsersByUser(User user); -->
	<select id="queryUsersByUser" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where last_name like #{lastName} and sex = #{sex}
	</select>

12.5、多个Pojo数据类型

如果参数是传入多个pojo对象。

第一个pojo对象,使用 param1表示

要输出第一个pojo对象的属性#{ param1.property }

第二个pojo对象,使用param2表示

要输出第一个pojo对象的属性#{ param2.property }

 

代码:

public List<User> queryUsersByUsers(User name, User sex);

 

xml中的配置是:

<!-- 		public List<User> queryUsersByUsers(User name, User sex); -->
	<select id="queryUsersByUsers" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where last_name like #{param1.lastName} and sex = #{param2.sex}
	</select>

12.6、模糊查询

需求:现在要根据用户名查询用户对象。 也就是希望查询如下: select * from t_user where user_name like '%%'

 

12.7#{}${}的区别

#{} 是占位符 ?

xml中的配置:

select `id`,`last_name` lastName,`sex` from t_user where last_name like #{name}

解析后的sql语句是:

select `id`,`last_name` lastName,`sex` from t_user where last_name like ?

 

${} 是原样输出参数的值。然后做字符串的拼接操作。

xml中的配置:

select `id`,`last_name` lastName,`sex` from t_user where last_name like '${name}'  

解析后的sql语句是:

select `id`,`last_name` lastName,`sex` from t_user where last_name like '%bbbb%' 

Mybatis-详解2

12.7.2MySQL的字符串拼接,concat函数实现官方推荐)

Mybatis-详解2

代码中:

public List<User> queryUsersByName(@Param("name")String name);

 

xml中的配置推荐:

<select id="queryUsersByName" resultType="com.tcent.pojo.User">
		select `id`,`last_name` lastName,`sex` from t_user where last_name like concat('%',#{name},'%') 
	</select>

13、自定义结果集<resultMap></resultMap> 

13.1<resultMap>的作用。

原来我们查询都是返回一个简单的JavaBean对象。我们可以直接使用ResultType定义返回在的类型。

但是如果我们查询的结果返回在的JavaBean中,又包含一个javaBeanassociation

或者包含一个javaBean对象的集合(collection

那么这个时候,只能使用ResultMap来自定义返回的结果。

 

13.2、创建一对一数据库表

## 一对一数据表
## 创建锁表
create table t_lock(
	`id` int primary key auto_increment,
	`name` varchar(50)
);


## 创建钥匙表
create table t_key(
	`id` int primary key auto_increment,
	`name` varchar(50),
	`lock_id` int ,
	foreign key(`lock_id`) references t_lock(`id`)
);


## 插入初始化数据
insert into t_lock(`name`) values('阿里巴巴');
insert into t_lock(`name`) values('华为');
insert into t_lock(`name`) values('联想');

insert into t_key(`name`,`lock_id`) values('马云',1);
insert into t_key(`name`,`lock_id`) values('任正非',2);
insert into t_key(`name`,`lock_id`) values('柳传志',3);

13.3、创建实体对象

 

锁实体Bean

public class Lock {

	private int id;
private String name;

钥匙实体Bean

public class Key {

	private int id;
	private String name;
	private Lock lock;

13.4一对一 级联属性 使用

(1)、第一次

创建KeyMapper接口:

public interface KeyMapper {

	public Key queryKeyByIdForSample(int id);

}

创建KeyMapper.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">
<!-- 
	namespace 属性一般情况下。
		一种定义规则:
			一种是使用对应的javaBean的全类名
			一种是使用Mapper接口的全类名
 -->

<mapper namespace="com.tcent.dao.KeyMapper">
 	<select id="queryKeyByIdForSimple" resultType="com.tcent.pojo.Key">
 		select id ,name,lock_id lock1 from t_key where id = #{id}
 	</select>
</mapper>

测试类:

@Test
	public void testQueryKeyByIdForSimple() throws IOException {
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
				.build(Resources.getResourceAsStream("mybatis-config.xml"));
		SqlSession session = sqlSessionFactory.openSession();
		KeyMapper mapper = session.getMapper(KeyMapper.class);
		Key key = mapper.queryKeyByIdForSimple(1);
		System.out.println(key);
	}

测试结果:

Mybatis-详解2

从结果看到lock显示null,说明我们用resultType这种查询都是返回一个简单的JavaBean对象,(我们可以直接使用ResultType定义返回的类型)

但是如果我们查询的结果返回的JavaBean中,又包含一个javaBean,或者包含一个javaBean对象的集合

那么这个时候,只能使用ResultMap来自定义返回的结果。

所以用resultMap进行测试,其他地方都不做修改

(2)、第二次

修改KeyMapper.xml配置文件:

 <resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForSimple_resultMap">
	 	<id column="id" property="id"/>
	 	<result column="name" property="name"/>
	 	<result column="lock_id" property="lock.id"/>	  
	 </resultMap>
	 
	 <select id="queryKeyByIdForSimple" resultMap="queryKeyByIdForSimple_resultMap">
 		select id ,name,lock_id  from t_key where id = #{id}
 	</select>

这里说明以下:我之前的查询lock_id随便起了个别名,但测试结果和第一次的简单查询一样,之后我把别名去掉,就获得了下面该有的结果。

测试结果:

Mybatis-详解2

代码和xml文件的调用示意图:

Mybatis-详解2

(3) 、第三次

解释:

column表示数据库表的字段名,property表示与之对应的JavaBean对象的属性名

resultMap 标签中:

id专门用来映射id主键列

 

result标签映射非主键列

 

resultMap标签可以自定义结果集。定义成你需要的bean对象的结果

type属性表示当前这个ResultMap会封装什么对象返回

id属性定义一个唯一的标识,方便别人使用

 

 

由于上一中方法只能返回被关联表的主键结果(副表的),得不到副表的name值,所以需要result Map中 的级联映射并且为了区分主副表的name不同,这里给副表的name取了别名:lock_name

 

修改KeyMapper.xml配置文件:

<!-- 由于上一中方法只能返回被关联表的主键结果(副表的),得不到副表的name值,所以需要result Map中 的级联映射-->
 	<!-- column表示数据库表的字段名,property表示与之对应的JavaBean对象的属性名 -->
	 <resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForSimple_resultMap">
		 <!-- id专门用来映射id主键列 -->
	 	<id column="id" property="id"/>
	 	<!-- result标签映射非主键列-->
	 	<result column="name" property="name"/>
	 	<!-- 级联映射 -->
	 	<result column="lock_id" property="lock.id"/>
	 	<result column="lock_name" property="lock.name"/>
	  
	 </resultMap>
	 
	 <select id="queryKeyByIdForSimple" resultMap="queryKeyByIdForSimple_resultMap">
 		select t_key.*,t_lock.name lock_name
 		from 
 			t_key left join t_lock
 		on
 			t_key.lock_id = t_lock.id
 		where
 			t_key.id=#{id}
 		 
 	</select>

测试结果:

Mybatis-详解2

13.4.2<association /> 嵌套结果集映射配置(取代result的级联映射)

前三次的方法官方都不推荐使用,官方推荐使用第四种,因为<association /> 功能更强大,主要可用定义分步查询

(4)、第四次

修改KeyMapper.xml配置文件:

<resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForSample_resultMap">
		<!-- id专门用来映射id主键列-->
		<id column="id" property="id"/>
		<!-- result标签映射非主键列-->
		<result column="name" property="name"/>
		<!-- association 标签专门 映射Bean对象中的子对象(一个Bean)
				专门用来配置一对一标签
		 -->
		<association property="lock" javaType="com.tcent.pojo.Lock">
			<!-- 把数据库表中的lock_id列	注入	--→到lock属性对象中的id属性值 -->
			<id column="lock_id" property="id"/>
			<!-- 把查询的lock_name列的值给lock子对象中的name属性 -->
			<result column="lock_name" property="name"/>
		</association>
	</resultMap>

测试结果:

Mybatis-详解2

这里的四次方法只改了配置文件 其他都没变化

总的代码粘出来:

<?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">
<!-- 
	namespace 属性一般情况下。
		一种定义规则:
			一种是使用对流的javaBean的全类名
			一种是使用Mapper接口的全类名
 -->
<mapper namespace="com.tcent.dao.KeyMapper">
<!-- 1、 	<select id="queryKeyByIdForSimple" resultType="com.tcent.pojo.Key"> -->
<!--  		select id ,name,lock_id lock1 from t_key where id = #{id} -->
<!--    	</select> -->
	 
<!-- 2、	<resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForSimple_resultMap"> -->
<!-- 	 	<id column="id" property="id"/> -->
<!-- 	 	<result column="name" property="name"/> -->
<!-- 	 	<result column="lock_id" property="lock.id"/>	   -->
<!-- 	   </resultMap> -->
	 
<!-- 	    <select id="queryKeyByIdForSimple" resultMap="queryKeyByIdForSimple_resultMap"> -->
<!--  		select id ,name,lock_id  from t_key where id = #{id} -->
<!--  	    </select> -->
<!-- 3、	<resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForSimple_resultMap"> -->
<!-- 	 	<id column="id" property="id"/> -->
<!-- 	 	<result column="name" property="name"/> -->
<!-- 	 	<result column="lock_id" property="lock.id"/> -->
<!-- 	 	<result column="lock_name" property="lock.name"/> -->
<!-- 	   </resultMap> -->
<!-- 	  <select id="queryKeyByIdForSimple" resultMap="queryKeyByIdForSimple_resultMap"> -->
<!--  		select t_key.*,t_lock.name lock_name -->
<!--  		from  -->
<!--  			t_key left join t_lock -->
<!--  		on -->
<!--  			t_key.lock_id = t_lock.id -->
<!--  		where -->
<!--  			t_key.id=#{id} -->
<!--  	</select> -->
<!-- 4、	 <resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForSimple_resultMap"> -->
<!-- 		 <!-- id专门用来映射id主键列 --> -->
<!-- 	 	<id column="id" property="id"/> -->
<!-- 	 	<!-- result标签映射非主键列--> -->
<!-- 	 	<result column="name" property="name"/> -->
<!-- 	 	<!-- 级联映射 --> -->
<!-- 	 	<association property="lock" javaType="com.tcent.pojo.Lock"> -->
<!-- 	 		<id column="lock_id" property="id"/> -->
<!-- 	 		<result column="lock_name" property="name"/> -->
<!-- 	 	</association> -->
<!-- 	 </resultMap> -->
<!-- 	 <select id="queryKeyByIdForSimple" resultMap="queryKeyByIdForSimple_resultMap"> -->
<!--  		select t_key.*,t_lock.name lock_name -->
<!--  		from  -->
<!--  			t_key left join t_lock -->
<!--  		on -->
<!--  			t_key.lock_id = t_lock.id -->
<!--  		where -->
<!--  			t_key.id=#{id} -->
<!--  	</select> -->
</mapper>

13.5、延迟加载

 

延迟加载在一定程序上可以减少很多没有必要的查询。给数据库服务器提升性能上的优化。

要启用延迟加载,需要在mybatis-config.xml配置文件中,添加如下两个全局的settings配置。

<!-- 打开延迟加载的开关 -->  
       <setting name="lazyLoadingEnabled" value="true" />  
       <!-- 将积极加载改为消极加载  按需加载 -->  
<setting name="aggressiveLazyLoading" value="false"/>  

懒加载功能,mybatis3.2.8版本,需要同时引入两个jar包,我使用的版本是mybatis3.4.1版本,不需要导包,包会在后面给出的

13.5.1<association /> 定义分步查询使用延迟加载

在KeyMapper接口中创建一个分步查询方法:

 

/*
	 * 一开始我只需要使用key表的信息,所以我只查key表的信息。
	 * <br/>
	 * 当我们需要用到key对象对应的Lock对象的信息的时候。我再查Lock的信息
	 * 
	 */
	public Key queryKeyByIdForTwoStep(int id);

创建LockMapper接口:

public interface LocKMapper {
	public Lock queryLockById(int lockId);
}

mybatis-config.xml配置文件中:

<settings>
			<!-- 打开延迟加载的开关 -->  
	       <setting name="lazyLoadingEnabled" value="true" />  
	       <!-- 将积极加载改为消极加载  按需加载 -->  
			<setting name="aggressiveLazyLoading" value="false"/>  
</settings>

keyMapper.xml配置文件中使用第四种association,并做修改 (黄色字底背景)

<resultMap type="com.tcent.pojo.Key" id="queryKeyByIdForTwoStep_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- 
			association 标签是推荐用来映射一对一关联
			property是你要映射的子对象的变量名
			javaType 表示你要映射的这个子对象的具体类型
			select 属性表示你要执行的查询语句:”全限定名.方法名”
			column 属性设置你要传递给select设置的查询语句用的参数列
这里使用association 单标签
		 -->
		<association property="lock" javaType="com.tcent.pojo.Lock" 
			select="com.tcent.dao.LocKMapper.queryLockById" column="lock_id"
		/>
	</resultMap>
	
<!-- 	public Key queryKeyByIdForTwoStep(int id); -->
	<select id="queryKeyByIdForTwoStep" resultMap="queryKeyByIdForTwoStep_resultMap">
		select id,name,lock_id from t_key where id = #{id}
	</select>
Mybatis-详解2

注意:注释不能嵌套<!-- <!-- -->-->

创建LockMapper.xml配置文件内容如下:

<!-- 	public Lock queryLockById(int lockId); 
id = #{id}占位符由keyMapper.xml中的column给出
-->
	<select id="queryLockById" resultType="com.tcent.pojo.Lock">
		select id,name from t_lock where id = #{id}
	</select>

测试结果:

只输出:System.out.println("只想使用key的属性值,就会只执行一次查询语句在一张表中:"+key.getName());

Mybatis-详解2

输出:System.out.println("只想使用key的属性值,就会只执行一次查询语句在一张表中:"+key.getName());

System.out.println("也想使用lock的属性值,就会执行两次查询语句在两张表中"+key.getLock());

Mybatis-详解2

目录结构示意图:

Mybatis-详解2

<association property="lock" javaType="com.tcent.pojo.Lock">

javaType映射Bean对象中的子对象(一个Bean)所属的全类名

Property映射Bean对象中的子对象

13.6、多对一、一对多的使用示例

13.6.1、创建一对多数据库


## 一对多数据表
## 创建班级表
create table t_clazz(
	`id` int primary key auto_increment,
	`name` varchar(50)
);

## 插入班级信息
insert into t_clazz(`name`) values('高三28班');
insert into t_clazz(`name`) values('高三34班');
insert into t_clazz(`name`) values('高三20班');
insert into t_clazz(`name`) values('高三32班');

## 创建学生表
create table t_student(
	`id` int primary key auto_increment,
	`name` varchar(50),
	`clazz_id` int,
	foreign key(`clazz_id`) references t_clazz(`id`)
);

## 插入班级信息
insert into t_student(`name`,`clazz_id`) values('孟小贤',1);
insert into t_student(`name`,`clazz_id`) values('李小想',1);
insert into t_student(`name`,`clazz_id`) values('徐小鹏',1);
insert into t_student(`name`,`clazz_id`) values('张小磊',2);
insert into t_student(`name`,`clazz_id`) values('彭小梁',2);
insert into t_student(`name`,`clazz_id`) values('小强',3);

创建实体Bean对象:

学生
public class Student {

	private int id;
	private String name;

班级
public class Clazz {

	private int id;
	private String name;
	private List<Student> stuList;

一个Java项目:mybatis的简单目录结构

Mybatis-详解2

13.6.2<collection/> 一对多,立即加载

创建ClazzMapper接口


public interface ClazzMapper {

	public Clazz queryClazzByIdForSample(int id);

}

编写ClazzMapper.xml配置文件:

<resultMap type="com.tcent.pojo.Clazz" id="queryClazzByIdForSample_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- 
			collection 标签专门用来映射集合属性
				property	表示你要映射的集合属性名是什么
		 -->
		<collection property="stuList" ofType="com.tcent.pojo.Student">
			<id column="stu_id" property="id"/>
			<result column="stu_name" property="name"/>
		</collection>
	</resultMap>
	
<!-- 	public Clazz queryClazzByIdForSample(int id); -->
	<select id="queryClazzByIdForSample" resultMap="queryClazzByIdForSample_resultMap">
		select 
			t_clazz.*,t_student.id stu_id,t_student.name stu_name
		from 
			t_clazz left join t_student
		on 
			t_clazz.id = t_student.clazz_id
		where 
			t_clazz.id = #{id}
	</select>

测试代码:

@Test
	public void testQueryClazzByIdForSimple() throws IOException {
		SqlSessionFactory sqlSessionFactory = new  SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
		SqlSession session = sqlSessionFactory.openSession();
		ClazzMapper mapper = session.getMapper(ClazzMapper.class);
		System.out.println(mapper.queryClazzByIdForSimple(1));
	}

测试结果:

Mybatis-详解2

立即加载:创建一个对应的pojo,只需要在查询语句 的时候查询字段并起 别名,并在collection 中指定对应的类型即可,其他不需要配置任何有关副表的数据代码。

13.6.3、一对多,赖加载(需要创建副表接口和Mapper.xml

再创建一个StudentMapper接口


public interface StudentMapper {
	public List<Student> queryStudentsByClazzId(int clazzId);
}

目录结构:

Mybatis-详解2

创建副表简单的查询语句:StudentMapper.xml配置文件:

<!-- 	public List<Student> queryStudentsByClazzId(int clazzId); -->
	<select id="queryStudentsByClazzId" resultType="com.tcent.pojo.Student">
		select id,name from t_student where clazz_id = #{clazzid}
	</select>

ClazzMapper接口中添加一个新方法来实现懒加载

/**
	 * 	我要分两次查询,
	 * 一次只查常用数据,班级信息<br/>
	 * 当我需要使用学生信息的时候。再查询一次<br/>
	 * 还要用到懒加载
	 */
	public Clazz queryClazzByIdForTwoStepLazy(int id);

ClazzMapper.xml进行重新配置queryClazzByIdForTwoStepLazy方法对应的查询语句与结果集:并做修改 黄色字底背景

Mybatis-详解2
<resultMap type="com.tcent.pojo.Clazz" id="queryClazzByIdForTwoStepLazy_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- 
			collection 是专门映射集合的标签
				property 属性设置你要设置和集合的属性名
				ofType是 这个集合中每个元素的具体类型
				select 是你要查询的语句
				column 属性设置你要执行的select对应的查询语句 需要的 主表的(Clazz)参数列,
也就是根据现在的表的id值去查询副表,产生关联关系
		 -->
		<collection property="stuList" ofType="com.tcent.pojo.Student" 
			select="com.tcent.dao.StudentMapper.queryStudentsByClazzId"
			column="id"
		/>
	</resultMap>
<!-- 	public Clazz queryClazzByIdForTwoStepLazy(int id); -->
	<select id="queryClazzByIdForTwoStepLazy" resultMap="queryClazzByIdForTwoStepLazy_resultMap">
		select id,name from t_clazz where id = #{id}
	</select>

测试代码:

@Test
	public void testQueryClazzByIdFor2Step() throws IOException {
		SqlSessionFactory sqlSessionFactory = new  SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
		SqlSession session = sqlSessionFactory.openSession();
		ClazzMapper mapper = session.getMapper(ClazzMapper.class);
		 Clazz clazz = mapper.queryClazzByIdFor2Step(1);
		 System.out.println(clazz.getName());
		 System.out.println(clazz.getStuList());
		 System.out.println(clazz.getStuList().get(1));
	}

测试结果:System.out.println(clazz.getName());

Mybatis-详解2

测试结果: System.out.println(clazz.getStuList());

 System.out.println(clazz.getStuList().get(1));

Mybatis-详解2

13.6.4、双向关联

注意点:双向关联实体类中都要互含对方的bean对象或含bean对象的list集合,所以要加上private Clazz clazz;

2、两边都要用selectresultMap,没有主副表了,所以没有resultType标签

3、双向关联两边都是懒加载,所以都是简单的查询语句和单向懒加载的副表一样

4、但为了终止死循环,必须要有一个名义上的副表使用association,主表还是collection集合标签

public class Student {

	private int id;
	private String name;
	private Clazz clazz;

这里Student又添加了一个clazz属性,以便双向关联,但相对于Student被关联的Clazz就变成了副表了,而且只是Student 的一个简单JavaBean对象,所以在resultMap中使用association  javaType标签属性

StudentMapper接口中也添加一个懒加载的方法:

public List<Student> queryStudentByClazzIdForLazy(int clazzId);

然后在StudentMapper.xml配置文件中

<resultMap type="com.tcent.pojo.Student" id="queryStudentByClazzIdForLazy_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- association标签是专门用来映射单个子对象的标签 -->
		<association property="clazz" javaType="com.tcent.pojo.Clazz" 
			select="com.tcent.dao.ClazzMapper.queryClazzByIdForTwoStepLazy"
			column="clazz_id"
		/>
	</resultMap>
<!-- public List<Student> queryStudentByClazzIdForLazy(int clazzId); -->
	<select id="queryStudentByClazzIdForLazy" resultMap="queryStudentByClazzIdForLazy_resultMap">
		select id,name,clazz_id from t_student where clazz_id = #{clazzId}
	</select>

还需要修改原来懒加载查询班级里,懒加载学生的select属性

<resultMap type="com.tcent.pojo.Clazz" id="queryClazzByIdForTwoStepLazy_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- 
			collection 是专门映射集合的标签
				property 属性设置你要设置和集合的属性名
				ofType是 这个集合中每个元素的具体类型
				select 是你要查询的语句
				column 属性设置你要执行的select对应的查询语句需要的参数列
		 -->
		<collection property="stuList" ofType="com.atguigu.pojo.Student" 
			select="com.tcent.dao.StudentMapper.queryStudentByClazzIdForLazy"
			column="id"
		/>
	</resultMap>

黑框中的命名规范是select”id_resultMap

Mybatis-详解2

双向关联会有死循环出现!

如何防止双向关联呢?

1、不要调用toString方法

2在你需要终止关联的时候,最后一次查询使用resultType

死循环的测试结果:System.out.println(clazz.getStuList());

Mybatis-详解2

总结:

<association /> 一对一 立即加载

 

 

<association property="lock" javaType="com.tcent.pojo.Lock"

 

一对一,延迟加载

javaType 表示你要映射的这个子对象的具体类型

 

 

<collection/> 一对多,立即加载:

 

<collectionproperty="stuList"ofType="com.atguigu.pojo.Student">

collection 标签专门用来映射集合属性

property表示你要映射的集合属性名是什么

 

一对多,延迟加载

ofType是 这个集合中每个元素的具体类型(即副表全类名)

 

 

立即加载(不需要副表的xml文件和接口方法,只需要bean实体类)

延迟/懒加载(需要副表的xml文件和接口方法,xml文件只是简单的select语句)

双向关联(需要副表的xml文件和接口方法,两个xml文件都要resultMap标签,主表collection副表association)

 

懒加载要在mybatis-config的核心配置文件中添加

<settings>

<!-- 打开延迟加载的开关 -->  

       <setting name="lazyLoadingEnabled" value="true" />  

       <!-- 将积极加载改为消极加载  按需加载 -->  

<setting name="aggressiveLazyLoading" value="false"/>  

</settings>

双向关联

注意点:双向关联实体类中都要互含对方的bean对象或含bean对象的list集合,所以要加上private Clazz clazz;

2、两边都要用selectresultMap,没有主副表了,所以没有resultType标签

3、双向关联两边都是懒加载,所以都是简单的查询语句和单向懒加载的副表一样

4、但为了终止死循环,必须要有一个名义上的副表使用association,主表还是collection集合标签


第二次查询没有结果输出,并且Junit测试包错

由于我是高版本的mybatis,所以没有导包,所以我把包和项目分开上传

项目

控制延迟加载的Asmcglibjar

 Mybatis-详解1