Mybatis1.5——高级映射(1对1,1对多,多对多,延迟加载)

JavaWeb框架学习文章索引
下面将以一个例子来进行演示
简单的数据模型如下:
数据模型
实际sql:

/*
SQLyog v10.2 
MySQL - 5.1.72-community : Database - mybatis
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `items` */

CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '商品名称',
  `price` float(10,1) NOT NULL COMMENT '商品定价',
  `detail` text COMMENT '商品描述',
  `pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
  `createtime` datetime NOT NULL COMMENT '生产日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Table structure for table `orderdetail` */

CREATE TABLE `orderdetail` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) NOT NULL COMMENT '订单id',
  `items_id` int(11) NOT NULL COMMENT '商品id',
  `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
  PRIMARY KEY (`id`),
  KEY `FK_orderdetail_1` (`orders_id`),
  KEY `FK_orderdetail_2` (`items_id`),
  CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

/*Table structure for table `orders` */

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下单用户id',
  `number` varchar(32) NOT NULL COMMENT '订单号',
  `createtime` datetime NOT NULL COMMENT '创建订单时间',
  `note` varchar(100) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

/*Table structure for table `user` */

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

一对一查询使用resultType方式:
例1,查询订单信息和关联的用户的姓名,性别
sql语句:

select orders.*,user.username,user.sex from user,orders where user.id = orders.user_id

创建和表对用的pojo,User和Orders
由于要使用resultType方式,返回值只能指定一个pojo类型。由于orders查询出的字段更加多,所以创建一个Orders的包装类OrdersCustom并添加需要的User部分属性
代码如下:

public class OrdersCustom extends Orders{
	//在查询user和orders的时候,orders的字段内容多一些,所以将user的部分属性定义到该类中
	private String username;
	private String sex;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
}

编写Mapper.xml:

	<select id="findOrdersUser" resultType="com.hhh.dao.OrdersCustom">
		select orders.*,user.username,user.sex from user,orders where user.id = orders.user_id
	</select>

编写Mapper.java

	public  List<OrdersCustom> findOrdersUser() throws Exception;

测试方法:

	@Test
	public void test() throws Exception{
		InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
		SqlSession session = factory.openSession();
		
		Mapper mapper = session.getMapper(Mapper.class);
		List<OrdersCustom> list = mapper.findOrdersUser();
		System.out.println(list.toString());
	}

dubug结果:
结果
一对一查询使用resultMap方式:
编写xml:

	<resultMap type="com.hhh.dao.Orders" id="orderUserMap">
		<!-- column中的id 表示查询列中的唯一标识
				加入该标识由多个字段组成,则需要配置多个id
			 property中的id是Orders的属性id
		 -->
		<id column="id" property="id"/>
		<result column="user_Id" property="user_Id"/>
		<result column="number" property="number"/>
		<result column="createtime" property="createtime"/>
		<result column="note" property="note"/>
		<!-- 
		association:用于映射关联查询单个对象的信息
		property:要将关联查询的用户信息映射到Orders中哪个属性 -->
		<association property="user" javaType="com.hhh.dao.User">
			<!-- id:关联查询用户的唯一标识
				 column:查询列中能唯一标识用户信息的列
				  -->
			<id column="user_id" property="id"/>
			<result column="username" property="username"/>
			<result column="sex" property="sex"/>
			<result column="birthday" property="birthday"/>
			<result column="address" property="address"/>
		</association>
	</resultMap>
	<select id="findOrdersUser2" resultMap="orderUserMap">
		select orders.*,user.username,user.sex from user,orders where user.id = orders.user_id
	</select>

方法:

public List<Orders> findOrdersUser2() throws Exception;

测试:

List<Orders> list = mapper.findOrdersUser2();

结果:
结果

resultType和resultMap实现一对一的对比:
resultType方式实现简单,如果pojo中没有包括查询出来的列名,就再添加需要的列名。
resultMap方式需要在xml中单独定义resultMap,实现要麻烦一点。但是resultMap可以实现延迟加载。

使用resultMap方式实现一对多:
例2,假如在上面的查询中再将订单明细的查询添加进去,那么由于一个订单可能有多个订单明细,所以如果使用resultType方式的话会比较麻烦,需要将查询出来的整条信息作为整体放到list中,在手动对结果进行解析。
sql定义如下:

select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num
from user,orders,orderdetail
where user.id = orders.user_id and orders.id = orderdetail.orders_id

查询结果:
查询结果

首先,新建OrderDetail类,在Orders中定义装Orderdetail的List集合List,并设置getter和setter。
然后编写xml:

	<resultMap type="com.hhh.dao.Orders" id="orderUserAndDetail">
		<id column="id" property="id"/>
		<result column="user_Id" property="user_Id"/>
		<result column="number" property="number"/>
		<result column="createtime" property="createtime"/>
		<result column="note" property="note"/>
		<association property="user" javaType="com.hhh.dao.User">
			<id column="user_id" property="id"/>
			<result column="username" property="username"/>
			<result column="sex" property="sex"/>
			<result column="birthday" property="birthday"/>
			<result column="address" property="address"/>
		</association>
		<!-- collection对关联查询到多条记录映射到集合对象中
			ofType:集中中装的pojo的类型
		 -->
		<collection property="orderdetails" ofType="com.hhh.dao.OrderDetail">
			<id column="orderdetail_id" property="id"/>
			<result column="items_id" property="items_id"/>
			<result column="orders_id" property="orders_id"/>
			<result column="items_num" property="items_num"/>
		</collection>
	</resultMap>
		<select id="findOrderUserAndDetail" resultMap="orderUserAndDetail">
		select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num
		from user,orders,orderdetail
		where user.id = orders.user_id and orders.id = orderdetail.orders_id
	</select>

这里resultMap的定义很多地方都与上一个例子中的内容相似,可以在resultMap节点中定义extends继承上一个resultMap的内容,然后省略相同的内容。

方法定义:

public List<Orders> findOrderUserAndDetail() throws Exception;

测试:

List<Orders> list = mapper.findOrderUserAndDetail();

结果:
结果

使用resultMap实现多对多
例3,在上面的条件下,再要求将商品的信息映射进去,主查询为User
要实现的结构:
User中定义一个List装Orders
Order中定义一个List装OrderDetail
OrderDetail中定义属性Items

sql:

select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num,items.name,items.price,items.pic,items.detail,items.createtime
from user,orders,orderdetail,items
where user.id = orders.user_id and orders.id = orderdetail.orders_id and orderdetail.items_id = items.id

根据上面的结构编辑类

编写xml

	<resultMap type="com.hhh.dao.User" id="UserItems">
		<id column="user_id" property="id"/>
		<result column="username" property="username"/>
		<result column="sex" property="sex"/>
		<result column="birthday" property="birthday"/>
		<result column="address" property="address"/>
		<collection property="orders" ofType="com.hhh.dao.Orders">
			<id column="id" property="id"/>
			<result column="user_Id" property="user_Id"/>
			<result column="number" property="number"/>
			<result column="createtime" property="createtime"/>
			<result column="note" property="note"/>
			
			<collection property="orderdetails" ofType="com.hhh.dao.OrderDetail">
				<id column="orderdetail_id" property="id"/>
				<result column="items_id" property="items_id"/>
				<result column="orders_id" property="orders_id"/>
				<result column="items_num" property="items_num"/>
				
				<association property="items" javaType="com.hhh.dao.Items">
					<id column="items_id" property="id"/>
					<result column="name" property="name"/>
					<result column="price" property="price"/>
					<result column="detail" property="detail"/>
					<result column="pic" property="pic"/>
					<result column="createtime" property="createtime"/>
				</association>
			</collection>
		</collection>
	</resultMap>
	<select id="findUserItems" resultMap="UserItems">
		select orders.*,user.username,user.sex,user.address,user.birthday,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.orders_id,orderdetail.items_num,items.name,items.price,items.pic,items.detail,items.createtime
		from user,orders,orderdetail,items
		where user.id = orders.user_id and orders.id = orderdetail.orders_id and orderdetail.items_id = items.id
	</select>

方法定义:

public List<User> findUserItems() throws Exception;

测试:

List<User> list = mapper.findUserItems();

结果:
结果

关于使用resultMap还是resultType:
其实上述的很多东西用resultType就可以轻松完成的,只不过基于题意来达到练习的效果。如果是要求查询用户的商品信息,可以直接将这些东西定义成一个pojo,然后用resultType就可以很容易查询出来。但是使用resultMap的话可以应对一些特殊需求。总是怎么用需要看实际的业务需求。

延迟加载:
使用resultMap中的association、collection是具备延迟加载的功能的。
延迟加载就是查询的时候先从单表查询,然后有需求的时候再去关联查询。这样做可以很大减少数据库的开销,尤其是连接的表比较多的时候。

例4,使用延迟加载的方式查询订单并且关联查询用户信息。
延迟加载是可以手动进行的。
1,首先定义两个查询语句。并实现对应的方法。
2,使用其中的一个语句查询出订单信息。
3,遍历订单信息的List,然后在循环中使用另外一个语句来查询出当前订单的用户信息。

下面以association的方式为例,介绍mybatis的延迟加载机制:
编写xml:

	<resultMap type="com.hhh.dao.Orders" id="OrderUserLazyLoading">
		<id column="id" property="id"/>
		<result column="user_Id" property="user_Id"/>
		<result column="number" property="number"/>
		<result column="createtime" property="createtime"/>
		<result column="note" property="note"/>
		
		<!-- 
		select:指定延迟加载使用的statement的id,如果使用的statement不在本mapper中,需要在id前面加上 命名空间.
		column:主查询中关联子查询的列名
		如,select *,
			(select username from user where user.id = orders.user_id) username
			from orders
			,这里的column应该是orders表中的user_id
		 -->
		<association property="user" select="findUserById" column="user_id">
			<id column="user_id" property="id"/>
			<result column="username" property="username"/>
		</association>
	
	</resultMap>
	<select id="findUserById" parameterType="int" resultType="com.hhh.dao.User">
		select * from user where id = #{id}
	</select>
	<select id="findOrderUserLazyLoading" resultMap="OrderUserLazyLoading">
		select * from orders
	</select>	

在SqlMapConfig.xml中配置:

	<!-- 配置延迟加载 -->
	<settings>
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>

编写方法:

	public User findUserById(int id) throws Exception;
	
	public List<Orders> findOrderUserLazyLoading() throws Exception;

测试方法:

		List<Orders> orders = mapper.findOrderUserLazyLoading();
		for (Orders order : orders) {
			//通过get的方式,mybatis实现延迟加载
			User user = order.getUser();
			System.out.println(user.getUsername());
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值