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_ pleft 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_ pleft join category_ c on p.cid = c.idleft join order_item_ oi on p.id =oi.pidleft 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_ oleft join order_item_ oi on o.id =oi.oidleft 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_ oleft join order_item_ oi on o.id =oi.oidleft join product_ p on p.id = oi.pidwhere 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_ pleft join category_ c on p.cid = c.idleft join order_item_ oi on p.id =oi.pidleft join order_ o on oi.oid=o.id

