2.MyBatis映射
1 默认映射方式
- 上一节的select语句的resultType默认映射方式要求将查询出来字段属性名和模型类属性名一一对应。有如下规则。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。 只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
这就是默认的映射方式。
- 如果映射出来的模型对象有另一个对象作为他的属性。则不能够使用默认映射,需要使用使用resultMap结点。
2 一对多、多对多的E-R图
- sql脚本
drop database how2java;
create database how2java;
use how2java;
-- 分类表
CREATE TABLE category_ (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(32) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 产品表
create table product_(
id int NOT NULL AUTO_INCREMENT,
name varchar(30) DEFAULT NULL,
price float DEFAULT 0,
cid int ,
PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入数据
delete from category_;
INSERT INTO category_ VALUES (1,'衣服');
INSERT INTO category_ VALUES (2,'玩具');
delete from product_;
INSERT INTO product_ VALUES (1,'帽子', 30, 1);
INSERT INTO product_ VALUES (2,'鞋子', 20, 1);
INSERT INTO product_ VALUES (3,'袜子', 10, 1);
INSERT INTO product_ VALUES (4,'变形金刚', 50, 2);
INSERT INTO product_ VALUES (5,'赛车', 70, 2);
INSERT INTO product_ VALUES (6,'芭比娃娃', 100.5, 2);
select * from category_;
select * from product_;
create table order_ (
id int(11) NOT NULL AUTO_INCREMENT,
code varchar(32) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
create table order_item_(
id int(11) NOT NULL AUTO_INCREMENT,
oid int ,
pid int ,
number int ,
PRIMARY KEY(id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO order_ VALUES (1,'code000A');
INSERT INTO order_ VALUES (2,'code000B');
INSERT INTO order_item_ VALUES (null, 1, 1, 100);
INSERT INTO order_item_ VALUES (null, 1, 2, 100);
INSERT INTO order_item_ VALUES (null, 1, 3, 100);
INSERT INTO order_item_ VALUES (null, 2, 2, 100);
INSERT INTO order_item_ VALUES (null, 2, 3, 100);
INSERT INTO order_item_ VALUES (null, 2, 4, 100);
select * from order_;
select * from order_item_;
模型类
映射文件中select结点不用resultType属性,不使用默认映射,而是使用resultMap来指向一个resultMap结点。
一个select出的条目传入到resultMap中映射,创建相对应的对象。
<select id="listCategory" resultMap="categoryBean">
<!-- 对于重复字段需要给出别名 -->
<!-- 内连接就是指定两张表上具有相同字段的行连接到一起组成新的行 -->
<!-- 左外连接=内连接+左表中连接字段为空的行 -->
<!-- 右外连接=内连接+右表中连接字段为空的行 -->
<!-- 全外连接=内连接+左右表中连接字段为空的行 -->
<!-- 自然连接在相同字段上做笛卡儿积 -->
select c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname',price from category_ c left join product_ p on c.id=p.cid
</select>
- 映射文件中resultMap结点,id属性定义唯一标志,type属性表示模型类。
- id和result结点来对简单数据类型的映射。 column指定SQL语句查询结果的属性,property指定返回对象的某个属性
- collection结点对于集合类型(数组、List等)映射,property指定返回对象,property指定集合元素的类型。其中的id和result结点用来集合中的各个元素。
<resultMap type="Category" id="categoryBean">
<!-- column指定SQL语句查询结果的行,property指定返回对象的某个属性 -->
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!-- 一对多的属性用collection标签,把上述属性相同的条目聚合到一起 -->
<!-- property: 指的是集合属性的值, ofType:指的是集合中元素的类型 -->
<collection property="products" ofType="Product">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
</collection>
</resultMap>
3.2 从商品的角度是多对一,对于单个商品来说是一对一
- 映射文件中select结点。
<!-- 根据cid关联查询所有 -->
<select id="listProduct" resultMap="productBean">
select p.*,c.*,
p.id 'pid',c.id 'cid',
p.name 'pname',c.name 'cname'
from product_ p
left join category_ c on c.id = p.cid
</select>
- 映射文件中resultMap结点。其他结点与上述相同。association结点用来表示单个对象。
<resultMap type="Product" id="productBean">
<id column="pid" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
<!-- 多对一的关系用association标签 -->
<!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
<association property="category" javaType="Category">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
</resultMap>
4 多对多
多对多关系,通常需要第三张表的介入,对于订单和商品两张表,需要订单条目的介入。
<resultMap type="Product" id="productBean2">
<id column="p_id" property="id" />
<result column="pname" property="name" />
<result column="price" property="price" />
<!-- 多对一的关系用association标签 -->
<!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
<association property="category" javaType="Category">
<id column="c_id" property="id"/>
<result column="cname" property="name"/>
</association>
<!-- 一对多的关系用collection标签 -->
<collection property="orderItems" ofType="OrderItem">
<id column="oi_id" property="id" />
<result column="number" property="number" />
<association property="order" javaType="Order">
<id column="o_id" property="id"/>
<result column="code" property="code"/>
</association>
</collection>
</resultMap>
<!-- 查询所有关于该商品的订单和类别的记录 -->
<select id="listProductandItems" resultMap="productBean2">
select p.*,c.*,oi.*,o.*,
p.id 'p_id',c.id 'c_id',o.id 'o_id',oi.id 'oi_id',
p.name 'pname',c.name 'cname'
from product_ p
left join category_ c on p.cid = c.id
left join order_item_ oi on p.id =oi.pid
left join order_ o on oi.oid=o.id
</select>
4.2 从订单的角度对订单条目看
<resultMap type="Order" id="orderBean">
<id column="oid" property="id" />
<result column="code" property="code" />
<!-- 当前Order对象对应多个OrderItem -->
<collection property="orderItems" ofType="OrderItem">
<id column="oiid" property="id" />
<result column="number" property="number" />
<association property="product" javaType="Product">
<id column="pid" property="id"/>
<result column="pname" property="name"/>
<result column="price" property="price"/>
</association>
</collection>
</resultMap>
<!-- 订单表、订单条目表、商品表三表连接,查询出每个订单下各个条目具体信息 -->
<select id="listOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
</select>
<select id="getOrder" resultMap="orderBean">
select o.*,p.*,oi.*, o.id 'oid', p.id 'pid', oi.id 'oiid', p.name 'pname'
from order_ o
left join order_item_ oi on o.id =oi.oid
left join product_ p on p.id = oi.pid
where o.id = #{id}
</select>
4.3 从订单条目对商品、订单看
可以通过对订单条目增加减少对于多对多关系增加
!-- 在中间表上添加条目,相当于增加关系 -->
<insert id="addOrderItem" parameterType="OrderItem">
insert into order_item_
values(null,#{order.id},#{product.id},#{number})
</insert>
<!-- 在中间表删除条目,想到那与删除关系 -->
<insert id="deleteOrderItem" parameterType="OrderItem">
delete from order_item_
where oid = #{order.id} and pid = #{product.id}
</insert>
5 总结
5.1 映射方式
- 默认映射方式,resultType指定特定类型。
- 指定映射方式,resultMap指定某个resultMap结点,通过id、result结点中的column、porperty指定sql中的属性、类中的属性。
5.2 一对多、多对多关系
这些关系都是要从自己这方面看一对多用collection结点,多对一或一对一用association结点。5.3 连接查询
连接查询为了避免一些不必要的特殊问题,连接查询时多个表中的相同字段需要用别名区分。用这种方式查询到所有的结点之后。
同时要注意别名的效果,可能别名也会有冲突,因此映射文件的SQL语句要现在可视化终端执行后再写入到映射配置文件里。
例如在下面的四个表连接时。select p.*,c.*,oi.*,o.*,
p.id 'pid',c.id 'c_id',o.id 'o_id',oi.id 'oi_id',
p.name 'pname',c.name 'cname'
from product_ p
left join category_ c on p.cid = c.id
left join order_item_ oi on p.id =oi.pid
left join order_ o on oi.oid=o.id