文章目录
- 搭建环境
- 一对一
2.1 使用ResultType
2.2 使用ResultMap - 一对多
- 多对多
- 搭建环境
本文以用户User、订单Order、角色Role来进行描述mybatis中的关联查询
用户和订单之间是一对多的关系,一个用户可以有多个订单。订单和用户之间是多对一的关系,多个订单可以属于同一个用户。用户和角色之间是多对多的关系,一个用户可以有多个角色,多个角色也可以只属于一个用户。
Order——User
在这里插入图片描述
User——Role
在这里插入图片描述
建表语句
创建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=28 DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
在这里插入图片描述
创建Order表
CREATE TABLE order
(
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_order_id
FOREIGN KEY (user_id
) REFERENCES user
(id
) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
10
在这里插入图片描述
注意,用户表和订单表之间使用外键连接的,外键要建在多的一方,因为,如果建在一的一方,那么主键要一个字段要存多个值了,不利于维护和操作,所以,mysql中,外键都是要建在多的一方。
创建Role表
create table role
(
id
int (11) not null AUTO_INCREMENT,
name
varchar(32) not null,
primary key (`id))
1
2
3
4
在这里插入图片描述
(数据可能不太恰当,只要能说明问题就行【捂脸】)
User表和Role表是多对多关系,相当于是两个多对一,所以,建立一张辅助表user_role
create table role_user
(
id
int(10) not null auto_increment,
u_id
int(10) not null,
r_id
int(10) not null,
PRIMARY key(id
),
CONSTRAINT user_id
FOREIGN KEY(u_id
) REFERENCES user
(id
),
CONSTRAINT role_id
FOREIGN key(r_id
) REFERENCES role
(id
)
)
1
2
3
4
5
6
7
8
9
在这里插入图片描述
实体类
User
public class User {
private Integer id;
private String username;
private String sex;
private Date birthday;
private String address;
//…(getter、setter)
}
1
2
3
4
5
6
7
8
Order
public class Order {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//getter、setter方法
}
1
2
3
4
5
6
7
8
9
10
11
12
Role
public class Role {
private Integer id;
private String name;
//getter、setter方法
}
1
2
3
4
5
6
2. 一对一
一个订单只属于一个用户,从订单的角度看是一对一关系。
一对一映射,有两种方式:
2.1 使用ResultType
新建OrderUser的pojo,继承自Order(这里继承User、Order类都一样,只要这个Pojo包含User、Order的所有属性即可)。
//一对一关联查询的时候,使用的新的实体类,作为返回值类型
public class OrderUser extends Order {
private Integer id;
private String username;
private String sex;
private Date birthday;
private String address;
//getter、setter方法
}
1
2
3
4
5
6
7
8
9
修改order的映射文件,新增查询方法getOrderUser
@Test //测试使用resultType的一对一关联查询
//查询订单的用户信息
public void testQueryOrderUser() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List list = orderMapper.queryOrderUser();
for (OrderUser orderUser : list) {
System.out.println(orderUser);
}
}
1
2
3
4
5
6
7
8
9
10
11
结果
在这里插入图片描述
2.2 使用ResultMap
resultMap用于结果映射,使用这种方式,就是手动的将查询结果进行映射
改造Order的pojo,在Order类中添加一个User属性
//添加User属性
private User user;
//并生成响应的getter、setter方法
1
2
3
修改Order的映射文件
<id property="id" column="id"/>
<!--result标签用于数据库中的字段和javaBean的绑定
property:javaBean中的属性名
column:数据库中字段名
-->
<result property="userId" column="user_id"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
<!-- association:配置一对一关联映射
property:pojo中的一个对象属性,order里面的User属性名
javaType:pojo关联的pojo对象类型
-->
<association property="user" javaType="user">
<!-- id标签用于绑定主键
column:"表的主键字段,或者可以为查询语句中的别名字段"
property:"映射pojo对象的主键属性"
-->
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
</association>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 在这里插入图片描述
- 一对多
一个用户,可以有多个订单,在用户的角度上,用户和订单是一对多的关系
改造User的pojo,一个User可以有多个Order,可以在User中建一个只能装Order的List
//配置一对多关系映射
private List orders;
//生成响应的getter、setter方法
1
2
3
修改User的映射文件
<!-- 一对多关联映射配置,注意是oftype,
property:pojo的集合属性名
ofType:集合中的pojo对象类型
-->
<collection property="orders" ofType="order">
<!-- id标签用于绑定主键
column:"表的主键字段,或者可以为查询语句中的别名字段"
property:"映射pojo对象的主键属性"
-->
<id property="id" column="oid"/>
<result property="userId" column="user_id"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
</collection>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 测试
@Test //测试一对多关联查询
public void testSelectUserOrderResultMap(){
SqlSessionFactory sessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List list = userMapper.selectUserOrderResultMap();
for (User user : list) {
System.out.println(user);
for (Order order : user.getOrders()) {
System.out.println(" 订单有:" + order);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
结果
在这里插入图片描述
- 多对多
一个用户可以有多个角色,一个角色也可以有多个用户,多对多用户,可以拆分为两个一对多,只看用户的话,一个用户可以有多个角色,只看角色的话,一个角色可以有多个用户。或者,你不用在意他是多对多,只需要根据查询的的结果配置相应的结果映射即可。
比如,根据id查询用户的信息以及角色信息
首先,在 User 中添加一个List roles集合属性
//配置多对多关系映射
private List roles;
//生成响应的getter、setter方法
1
2
3
修改User的映射文件
<collection property="roles" ofType="role">
<id property="r_id" column="r_id"></id>
<result property="name" column="name"></result>
</collection>
select u.id,u.username,u.birthday,u.sex,u.address,r.name from user u left join role_user ru on u.id=ru.u_id left join role r on r.r_id=ru.r_id where u.id=#{id} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 测试
@Test //测试多对多
public void testSelectUserRoleById() {
SqlSessionFactory sessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserRoleById(2);
System.out.println(user);
}
1
2
3
4
5
6
7
8
结果
在这里插入图片描述
如果是查询角色对应的用户和上述过程一样,这里就不叙述了。
另外,保存用户的时候,要手动维护第三张表(可以使用foreach标签进行批量插入),否则用户表和角色表无法关联。
小结
关联-association
集合-collection
所以association是用于一对一和多对一,而collection是用于一对多的关系
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型。
注意说明:
1、保证SQL的可读性,尽量通俗易懂
2、根据实际要求,尽量编写性能更高的SQL语句
3、注意属性名和字段不一致的问题
4、注意一对多和多对一 中:字段和属性对应的问题