1.什么是关联查询
-
实体间的关系(拥有 has、属于 belong)
-
OneToOne:一对一关系(account ←→ user)
-
OneToMany:一对多关系(user ←→ account)
-
ManyToMany:多对多关系(user ←→ role)
-
-
什么是关联查询
当访问关系的一方时,如果需要查看与之关联的另一方数据,则必须使用表链接查询,将查询到的另一方数据,保存在本方的属性中
-
关联查询的语法
指定“一方”关系时(对象),使用
< association javaType="" >
指定“多方”关系时(集合),使用
< collection ofType="" >
-
Mybatis中的关联关系实现,主要通过resultMap来实现的
下面以案例的形式展现给大家
2.一对一查询
需求:查询账户信息,关联查询用户信息。
分析:因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。
数据表实现:通过A表的主键引用B表的主键作为外键,就是说在A中主键和外键同一字段。
数据库信息:
建立Account.java:
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//加入User类的对象作为Account类的一个属性
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
", user=" + user +
'}';
}
}
创建接口:
public interface AccountDao {
List<Account> findAll();
}
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="com.by.mapper.AccountMapper">
<resultMap id="getAccountByIdResult" type="com.by.pojo.Account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
<!--
一对一使用association标签指定数据的封装规则
property="user":Account的属性名
javaType="com.by.pojo.User":等价于resultType
-->
<association property="user" javaType="com.by.pojo.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="getAccountById" parameterType="int" resultMap="getAccountByIdResult">
SELECT a.id aid, a.uid uid, a.money money, u.* FROM account a LEFT JOIN user u ON a.uid=u.id WHERE a.id=#{id}
</mapper>
测试类:
@Test
public void testGetAccountById(){
AccountMapper accountMapper = sqlSession.getMapper(AccountMapper.class);
Account account = accountMapper.getAccountById(1);
System.out.println(account);
}
3.一对多查询
需求:查询所有用户信息及用户关联的账户信息。
分析:用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,此时左外连接查询比较合适。
数据表实现:使用一个外键进行关联,外键放在多方的表中;
创建user,一对一用可以对象,一对多时可以使用集合来代表多的一方:
package com.by.pojo;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private Date birthday;
private String sex;
private String address;
//加入List<Account>存储用户所拥有的账户
private List<Account> accounts;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", accounts=" + accounts +
'}';
}
}
创建接口:
public interface AccountDao {
List<Account> findAll();
}
通过resultMap进行结果映射,collection标签可以指定映射的集合,其中porperty属性指定的是该关联属性的名称,ofType指定的是集合里面的java类型,id,result标签同resultMap中的一样是对集合里面的属性进行映射;
创建xml:
<mapper namespace="com.by.mapper.UserMapper">
<resultMap id="getUserByIdResult" type="com.by.pojo.User">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!--一堆多使用collection标签指定数据的封装规则-->
<collection property="accountList" ofType="com.by.pojo.Account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<select id="getUserById" parameterType="int" resultMap="getUserByIdResult">
SELECT u.*, a.id aid, a.uid uid, a.money money FROM user u LEFT JOIN account a ON u.id=a.uid WHERE u.id=#{id}
</select>
测试类:
/**
* 一对多:一个user 对 多个Account
*/
@Test
public void testGetUserById(){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserById(41);
System.out.println(user);
}
3.多对多查询
需求:查询角色及角色赋予的用户信息。
分析:一个用户可以拥有多个角色,一个角色也可以赋予多个用户,用户和角色为双向的一对多关系,多对多关系其实我们看成是双向的一对多关系。
数据表:需要用一张中间表表示多对多的关系,这张中间表引入两张表的主键作为外键;
①多表连接查询,不需要定义中间表实体类
②多表嵌套查询,需要定义中间表实体类
③多表复杂查询,不需要定义中间表实体类,但是返回值是一个List;
多表嵌套查询定义中间实体类:
由于两张表之间分别单独查询,需要通过中间表查找关联并使用resultMap进行映射关系处理,resultMap需要指明映射的java的类,并在实体类中定义关联属性才可以得到关联属性的信息;简单来说:一张表查询完之后想要得到另一张表的信息,实际上是通过中间表来进行映射得到另一张表的信息的;
多表复杂查询:通过一张表先和中间表进行连接查询,然后再查询另一张表的信息;
数据库:
创建Role:
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
//多方
private List<User> userList;
创建接口:
public interface RoleDao {
List<Role> findAll();
}
创建xml:
<mapper namespace="com.by.mapper.RoleMapper">
<resultMap id="getRoleByIdResultMap" type="com.by.pojo.Role">
<id column="rid" property="id"></id>
<result column="role_name" property="roleName"></result>
<result column="role_desc" property="roleDesc"></result>
<!--
一对多使用collection标签指定数据的封装规则
property="userList":pojo的属性
ofType="com.by.pojo.User":集合的泛型,等价于resultType
-->
<collection property="userList" ofType="com.by.pojo.User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
<select id="getRoleById" parameterType="int" resultMap="getRoleByIdResultMap">
SELECT
r.id as rid,r.role_name,r.role_desc,
u.*
FROM
user_role ur
JOIN role r ON ur.rid=r.id
JOIN user u ON ur.uid=u.id
WHERE
r.id=#{id}
</select>
</mapper>
创建测试类:
/**
* 多对多:一个user 对 多个role 一个role 对 多个user
*/
@Test
public void testGetRoleById(){
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRoleById(1);
System.out.println(role);
}