Mybatis_day3_Mybatis的多表查询
Mybatis 多表查询
- 本次案例主要以最为简单的用户和账户的模型来分析 Mybatis 多表关系。用户为 User 表,账户为Account表。一个用户(User)可以有多个账户(Account)。具体关系如下:
一对一查询(多对一)
- 需求
- 查询所有账户信息,关联查询下单用户信息。
- 注意:
- 因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。
方式一
- 定义账户信息的实体类
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;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 + "]";}
}
- 定义 AccountUser 类
public class AccountUser extends Account implements Serializable {
private String username;
private String address;public String getUsername() {return username;
}
public void setUsername(String username) {this.username = username;
}
public String getAddress() {return address;
}
public void setAddress(String address) {this.address = address;
}
@Override
public String toString() {
return super.toString() + " AccountUser [username=" + username + ",
address=" + address + "]";}
}
- 编写 Sql 语句
实现查询账户信息时,也要查询账户所对应的用户信息。
SELECT account.*, user.username, user.address
FROM account,user
WHERE account.uid = user.id
- 定义账户的持久层 Dao 接口
public interface IAccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<AccountUser> findAll();
}
- 定义 AccountDao.xml 文件中的查询配置信息
<mapper namespace="cn.myp666.dao.IAccountDao">
<!-- 配置查询所有操作-->
<select id="findAll" resultType="accountuser">select a.*,u.username,u.address from account a,user u where a.uid =u.id;
</select>
</mapper>
- 注意: 因为上面查询的结果中包含了账户信息同时还包含了用户信息,所以我们的返回值类型 returnType的值设置为 AccountUser 类型,这样就可以接收账户信息和用户信息了。
- 创建 AccountTest 测试类
@Test
public void testFindAll() {
//6.执行操作List<AccountUser> accountusers = accountDao.findAll();for(AccountUser au : accountusers) {System.out.println(au);}
- 总结
- 定义专门的 po 类作为输出类型,其中定义了 sql 查询结果集所有的字段。此方法较为简单,企业中使用普遍。
方式二
- 使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。
- 通过面向对象的(has a)关系可以得知,我们可以在 Account 类中加入一个 User 类的对象来代表这个账户是哪个用户的。
- 修改 Account 类
在 Account 类中加入 User 类的对象作为 Account 类的一个属性。
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//添加User对象
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 + "]";}
}
- 修改 AccountDao 接口中的方法
注意:第二种方式,将返回值改 为了 Account 类型。因为 Account 类中包含了一个 User 类的对象,它可以封装账户所对应的用户信息。
public interface IAccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<Account> findAll();
}
- 重新定义 AccountDao.xml 文件
<mapper namespace="cn.myp666.dao.IAccountDao"><!-- 建立对应关系 --><resultMap type="account" id="accountMap"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/><!-- 它是用于指定从表方的引用实体属性的 --><!--多对一的关系, property: 指的是属性的值, javaType:指的是属性的类型 --><association property="user" javaType="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="findAll" resultMap="accountMap">select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>
</mapper>
- 在 AccountTest 类中加入测试方法
@Test
public void testFindAll() {List<Account> accounts = accountDao.findAll();for(Account au : accounts) {System.out.println(au);System.out.println(au.getUser());}
}
一对多查询
-
需求:
- 查询所有用户信息及用户关联的账户信息。
-
分析:
- 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,我们想到了左外连接查询比较合适。
-
步骤如下:
- 编写 SQL 语句
SELECTu.*, acc.id as aid,acc.uid,acc.money
FROMuser u
LEFT JOIN account acc ON u.id = acc.uid
- User 类加入 List< Account >
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;public List<Account> getAccounts() {return accounts;
}
public void setAccounts(List<Account> accounts) {this.accounts = 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;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", birthday=" + birthday
+ ", sex=" + sex + ", address="
+ address + "]";}
}
- 用户持久层 Dao 接口中加入查询方法
List<User> findAll();
- 用户持久层 Dao 映射文件配置
<mapper namespace="cn.myp666.dao.IUserDao"><resultMap type="user" id="userMap"><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 是用于建立一对多中集合属性的对应关系
ofType 用于指定集合元素的数据类型
--><collection property="accounts" ofType="account"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/></collection></resultMap><!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">select u.*,a.id as aid ,a.uid,a.money from user u left outer join account
a on u.id =a.uid
</select>
</mapper>
- collection
部分定义了用户关联的账户信息。表示关联查询结果集 - property=“accounts”:
关联查询的结果集存储在 User 对象的上哪个属性里。 - ofType=“account”:
指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。
- 测试方法
@Test
public void testFindAll() {
//6.执行操作List<User> users = userDao.findAll();for(User user : users) {System.out.println("-------每个用户的内容---------");System.out.println(user);System.out.println(user.getAccounts());}
}