MyBatis(四)高级映射

1.数据库字段名与实体类属性名不一致

当数据库中的字段名和对应的JavaBean中的属性名称不一样时,那么就无法映射,如何解决这个问题呢?

可以在Mapper.xml中书写sql语句时,再指定数据库字段名和JavaBean属性的对应关系,这样mybatis就知道哪个属性对应哪个字段,就不会出错了。

假设数据库字段名为 pid 和 pname,而 Products.java中的属性名为 id 和 name:

那么查询到的数据,mybatis就无法映射到实体类相应的字段上(因为名字不一样,mybatis也不知道该怎么映射了);

此时就需要我们手动的告诉mybatis,你要把哪个字段的数据映射到实体类的哪个属性上:

<!--在resultMap中指定是哪个类,以及该映射的id-->
<!--主键字段使用id标签映射,column为数据库的字段名,property为实体类的属性名-->
<!--非主键字段使用result标签映射-->
    <resultMap id="products_map" type="products">
        <id column="pid" property="id"/>
        <result column="pname" property="name"/>
    </resultMap>
    
<!--在需要映射的地方使用resultMap,指定要映射关系的id-->
<!--resultType和resultMap二选一即可-->
    <select id="selectById" parameterType="int" resultMap="products_map">
        select * from products where pid = #{pid};
    </select>

但是在一开始的时候,最好就让数据库的字段名和实体类的属性名可以一一对应上!这样就减少了这些麻烦事情了。

2.联表查询

先赖准备两张表:

user表:

DROP TABLE IF EXISTS `kuser`;
CREATE TABLE `user`  (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名称',
  `birthday` DATE NULL DEFAULT NULL COMMENT '生日',
  `sex` CHAR(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',
  `address` VARCHAR(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 27 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
 

INSERT INTO `user` VALUES (1, '王五', NULL, '2', '山西太原');
INSERT INTO `user` VALUES (2, '张三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES (3, '张小明', NULL, '1', '山东聊城');
INSERT INTO `user` VALUES (4, '陈小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES (5, '张三丰', '1976-06-01', '1', '河南郑州');
INSERT INTO `user` VALUES (6, '孙二娘', '2000-05-09', '2', '山东郓城');
INSERT INTO `user` VALUES (7, '武松', '1990-12-01', '1', '河北清河县');

orders表:

DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders`  (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `user_id` INT(11) NOT NULL COMMENT '下单用户id',
  `number` VARCHAR(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单号',
  `createtime` DATETIME(0) NOT NULL COMMENT '创建订单时间',
  `note` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;

INSERT INTO `orders` VALUES (6, 1, '1000010', '2019-12-04 13:22:35', NULL);
INSERT INTO `orders` VALUES (7, 1, '1000011', '2019-12-03 13:22:41', NULL);
INSERT INTO `orders` VALUES (8, 2, '1000012', '2019-12-12 16:13:23', NULL);
INSERT INTO `orders` VALUES (9, 2, '1000013', '2019-10-09 18:11:03', NULL);
INSERT INTO `orders` VALUES (10, 3, '1000014', '2019-08-22 08:22:11', NULL);

其中orders表中的user_id字段是user表中id字段的外键。

(1)一对一

一个订单只对应一个用户,为一对一的关系。

(创建user表和order表的实体类,别忘记在Order表中添加User属性)

此时有一个需求:查询订单编号为6的订单信息以及用户名称和地址

sql语句:

SELECT u.username,u.address,o.* FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE o.`id` = 6;

此时如果使用该sql语句直接查询的话,我们看看是什么结果:

<select id="selectByOrderId" parameterType="int" resultType="orders">
    SELECT u.username,u.address,o.* FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE o.`id` = 6;
</select>

结果:

Orders{id=6, user_id=1, number='1000010', createtime=Wed Dec 04 13:22:35 CST 2019, note='null', user=null}

可以看到user的值为null。

这时因为mybatis需要我们指定关联的表:

<resultMap id="orders_resultMap" type="orders">
    <!--        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"/>
    <!--        关联的user表映射-->
    <association property="user" javaType="user">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="birthday" property="birthday"/>
        <result column="sex" property="sex"/>
        <result column="address" property="address"/>
    </association>
</resultMap>

<!--    resultMap使用上述的映射-->
<select id="selectByOrderId" parameterType="int" resultMap="orders_resultMap">
    SELECT u.username,u.address,o.* FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE o.`id` = 6;
</select>

此时结果:

Orders{id=6, user_id=1, number='1000010', createtime=Wed Dec 04 13:22:35 CST 2019, note='null', user=User{id=6, username='王五', birthday=null, sex= , address='山西太原', orders=null}}

可以看到,user的内容已经被查出来了。

如果需求修改为:查询指定订单号的订单信息和用户信息。

sql语句:

SELECT u.*,o.* FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE o.`id` = 6;

我们使用mybatis执行,查看结果:

Orders{id=1, user_id=1, number='1000010', createtime=Wed Dec 04 13:22:35 CST 2019, note='null', user=User{id=1, username='王五', birthday=null, sex=2, address='山西太原'}}

会发现结果是有问题的,orders的id明明为6,结果却为1。

这是因为orders表和user表中都有id字段,mybatis又区分不出来了,但是修改表字段名的不可能的。

此时就需要我们为两张表相同字段取别名了:

并且对应的映射关系也需要修改了:

<resultMap id="orders_resultMap" type="orders">
    <!--        orders表映射-->
    <id column="oid" property="id"/>
    <!--        关联的user表映射-->
    <association property="user" javaType="user">
        <id column="uid" property="id"/>
    </association>
</resultMap>

<!--    resultMap使用上述的映射-->
<select id="selectByOrderId" parameterType="int" resultMap="orders_resultMap">
    SELECT u.*,o.*,u.id uid,o.id oid FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE o.`id` = 6;
</select>

此时的结果:

Orders{id=6, user_id=0, number='null', createtime=null, note='null', user=User{id=1, username='null', birthday=null, sex= , address='null'}}

此时orders表的id就变为正确的6了。

(2)一对多映射

一个用户对应多个订单,即一对多的关系。

需求:查询指定用户对应的用户信息和订单信息;

(还是上述所提到的两个实体类,别忘记了在User类中添加List属性。)

此时也需要关联查询:(一对一的关联查询使用association标签,而一对多的关联查询使用collection标签)

sql语句:

SELECT u.*,o.* FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE u.`id` = 1;

mybatis:

一对多映射必须存在一个手动映射关系。就算是数据库字段名和实体类属性一直,也必须存在一个手动映射,并且剩下的字段如果不手动映射,需要设置autoMapping="true" ,将自动映射字段名与属性名能对应的字段。

<!--    使用autoMapping=true,自动映射-->
<resultMap id="user_resultMap" type="user" autoMapping="true">
    <id column="uid" property="id"/>
<!--    注意这里为ofType-->    
    <collection property="orders" ofType="orders" autoMapping="true">
        <id column="oid" property="id"/>
    </collection>
</resultMap>

<select id="selectByUserId" parameterType="int" resultMap="user_resultMap">
    SELECT u.*,o.*,u.id uid,o.id oid FROM orders o JOIN `user` u ON o.`user_id` = u.`id` WHERE u.`id` = 1;
</select>

结果:

User{id=1, username='王五', birthday=null, sex=2, address='山西太原', orders=[Orders{id=6, user_id=1, number='1000010', createtime=Wed Dec 04 13:22:35 CST 2019, note='null'}, Orders{id=7, user_id=1, number='1000011', createtime=Tue Dec 03 13:22:41 CST 2019, note='null'}]}

(3)嵌套查询

在sql语句中,除了联表查询,我们还可以使用子查询,那么在mybatis中如何实现子查询呢?

sql语句:

SELECT * FROM USER WHERE id = (SELECT user_id FROM orders WHERE id = 6);  

mybatis:

<!--    嵌套查询-->
    <resultMap id="order_rm" type="orders" autoMapping="true">
        <id column="id" property="id"/>
<!--    column为传给内层查询的参数-->
        <association property="user" column="user_id" select="selectUser" javaType="user"/>
    </resultMap>
<!--    外层查询,即()里的-->
    <select id="selectOrder" parameterType="int" resultMap="order_rm">
        select * from orders where id = #{id}
    </select>
<!--    内层查询-->
    <select id="selectUser" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>
posted @ 2021-03-18 11:14  deng-hui  阅读(355)  评论(0编辑  收藏  举报