【07】Mybatis笔记–多表查询
一、表之间的关系:
- 一对多
- 多对多
- 一对一
1)一对多
示例:一个用户可以有多个银行账户,但一个账户只能属于一个用户(一对多
要求:查询所有用户和它所拥有的账户
步骤:
- 创建用户表和账户表
-- 账户表
CREATE TABLE `account` (
`ID` int(11) NOT NULL COMMENT '编号',
`UID` int(11) DEFAULT NULL COMMENT '用户编号',
`MONEY` double DEFAULT NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 用户表
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8;
- 创建对应的实体类
/**
* @author a_apple
* @create 2020-02-05 14:02
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//一对一关系体现。 ”多“方添加一个”一“方的对象
private User user;
//getter(),setter(),toString() ...
}
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系体现。 在“一”方添加"多“方的集合
private List<Account> accounts;
//getter(),setter(),toString() ...
}
- 创建Dao接口
//AccountDao
public interface AccountDao {
/**
* 查询所有账户,及其账户所属用户
*/
List<Account> list();
}
//UserDao
public interface UserDao {
/**
* 查询所有用户,同时获取用户下所有账户信息
*/
List<User> list();
}
- 配置对应的映射配置文件(UserDao.xml、AccountDao.xml
关键:
UserDao.xml
新使用的标签:<collection>
标签内的属性:
- property:主表实体类里面集合名(这里指Account集合
- ofType:指的是集合元素的类型,要写全限定类名。(这里使用了别名
映射配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="indi.xu.dao.UserDao">
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--主附表一对多体现-->
<!--配置user对象中accounts集合的映射
ofType:指的是集合元素类型,要写全限定类名。(这里使用了别名
-->
<collection property="accounts" ofType="account">
<!--注,当主表主键名和副表相同要使用别名区分-->
<id property="id" column="aid"></id>
<!--非主键字段对应-->
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!-- 查询所有-->
<select id="list" resultMap="userAccountMap">
SELECT u.*,a.id as aid,a.uid,a.money
FROM USER u
LEFT JOIN account a ON u.id = a.uid;
</select>
</mapper>
几点注意:
- sql语句的书写:由于主表和副表的主键名称都为"id",在mybatis中,写sql语句需要用别名把这2个区分
错误写法:
SELECT * FROM USER u
LEFT JOIN account a
ON u.id = a.uid;
-- 虽然在也能实现正常的查询,但放到mybatis中就会出现封装对象错误
正确写法:
SELECT u.*,a.id as aid,a.uid,a.money
FROM USER u
LEFT JOIN account a
ON u.id = a.uid;
-- 上面account的id使用了别名aid,这样就能正确封装对象
- 上面的
select
标签使用了resultMap
属性而不是resultType
。是因为resultType
只能封装一个对象,这里要求查询用户的同时还要获取其账户。所以使用resultMap
2)一对一
要求:查询所有账户及其对应的用户
即:在查询所有Account时,需要把Account类里面的User对象也查出来
AccountDao.xml配置:
新使用的标签:<association>
标签中的属性:
- column:指的是与主表关联的外键
- property:副表实体类里面主表对象名
- javaType:指的是主表对应的实体类
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="indi.xu.dao.AccountDao">
<resultMap id="AccountMap" type="Account">
<!--主键字段对应-->
<id property="id" column="id"></id>
<!--非主键字段对应-->
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--一对一的关系映射,配置封装user的内容-->
<!--就是在副表里面添加主表对象,以获取主表内容
column:指的是与主表关联的外键
javaTyep:指的是主表对应的实体类
property:副表实体类里面主表对象名
-->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
<!--查询所有账户同时包含用户名和地址信息-->
<select id="list" resultMap="AccountMap">
SELECT u.*,a.id ,a.uid,a.money
FROM account a,USER u
WHERE u.id = a.uid;
</select>
</mapper>
3)多对多
示例:
- 一个读者可借阅多本书,一本书可以被多个读者借阅过。产生一个借阅关系(也就是中间表)
- 一个人可以有多种角色,一种角色可以多个人扮演。
步骤:
- 创建表。用户表,用户角色表(中间表),角色表
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0wYq7jgz-1581479052109)(C:\Users\Yang xu\Desktop\Mybatis\img\1581142238963.png)]
3.创建对应实体类。分别在User类和Role类中放入对方的集合
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多体现
private List<Role> roles;
//getter(),setter(),toString()
}
public class Role implements Serializable {
private Integer id;
private String roleName;
private String roleDesc;
//多对多的关系映射:一个角色可以赋予多个用户
private List<User> users;
//getter(),setter(),toString()
}
- 创建Dao接口
public interface UserDao {
/**
* 查询所有用户及其角色
*/
List<User> list();
}
- 配置UserDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="indi.xu.dao.UserDao">
<resultMap id="userRoleMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="roles" ofType="role">
<id property="id" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<!-- 查询所有-->
<select id="list" resultMap="userRoleMap">
SELECT u.*,r.id AS rid,r.role_name,r.role_desc
FROM USER u
LEFT JOIN user_role ur ON u.id = ur.uid
LEFT JOIN role r ON r.id = ur.rid;
</select>
</mapper>
- 注:多对多关系一般是通过操作中间表来实现的。