MyBatis的多表查詢
表之間的關係:一對多,多對一,一對一,多對多。
一對多:一個班級對應多個學生
多對一:多個學生對應一個班級
一對一:一個人對應一個身份證號碼
多對多:一個訂單可以有多個商品,一個商品也可以對應多個訂單。
一對一
新建一個賬戶信息表:
其中ID是主鍵,UID對應於user表的id
需求:查詢所有account表中的信息,並且包含對應的用戶名和地址。
方式一(不常用):
新建賬戶類:
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
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;
}
public Account(Integer id, Integer uid, Double money) {
this.id = id;
this.uid = uid;
this.money = money;
}
public Account() {
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
由於只使用Account類只能包含賬戶信息,無法包含用戶用戶信息,因此新建一個類AccountUser繼承與Account類:
public class AccountUser extends Account {
private String username;
private String address;
@Override
public String toString() {
return super.toString()+" AccountUser{" +
"username='" + username + '\'' +
", address='" + 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;
}
}
對應的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.lwl.dao.IAccountDao">
<!--查詢所有-->
<select id="findAll" resultType="com.lwl.domain.Account">
select * from account;
</select>
<!--查詢所有賬戶,包含用戶名和地址-->
<select id="findAllAccount" resultType="com.lwl.domain.AccountUser">
select a.*,u.username,u.address from account a, user u where u.id=a.uid;
</select>
</mapper>
創建測試類進行測試:
public class AccountTest {
private InputStream is;
private SqlSession sqlSession;
private IAccountDao accountDao;
//初始化進行封裝
@Before //用於在測試方法執行之前執行
public void init() throws Exception {
//1.讀取配置文件,形成字節輸入流
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.獲取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.獲取SqlSession對象
sqlSession = factory.openSession();
//4.獲取dao的代理對象
accountDao = sqlSession.getMapper(IAccountDao.class);
}
//close進行封裝
@After //用於在測試方法執行之後執行
public void distory() throws Exception {
//提交事務
sqlSession.commit();
//6.關閉資源
sqlSession.close();
is.close();
}
//查詢所有賬戶
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
}
}
//查詢所有賬戶,幷包含用戶名和地址
@Test
public void testFindAllAccount(){
List<AccountUser> accountUsers = accountDao.findAllAccount();
for (AccountUser accountUser : accountUsers) {
System.out.println(accountUser);
}
}
}
查詢結果:
方式二:
使用resultMap,定義專門的resultMap用於映射一對一查詢結果。 通過面向對象的關係可以得知,我們可以在Account類中加入一個User類的對象來代表這個賬戶是哪個用戶的。
resultMap關鍵字
resultType
resultType可以把查詢結果封裝到pojo類型中,但必須pojo類的屬性名和查詢到的數據庫表的字段名一致。
如果sql查詢到的字段與pojo的屬性名不一致,則需要使用resultMap將字段名和屬性名對應起來,進行手動配置封裝,將結果映射到pojo中。
<!-- resultMap最終還是要將結果映射到pojo上,type就是指定映射到哪一個pojo -->
<!-- id:設置ResultMap的id -->
<resultMap type="User" id="UserResultMap">
<!-- property:pojo中的屬性名 -->
<!-- column:對應在數據庫中的列名 -->
<id property="id" column="id" />
<!-- 定義普通屬性 -->
<result property="name" column="username" />
<result property="usersex" column="sex" />
<result property="old" column="age" />
<result property="address" column="address" />
</resultMap>
resultMap可以實現將查詢結果映射爲複雜類型的pojo,比如在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。例如:
<!--定義封裝account和user的resultMap-->
<resultMap id="accountUserMap" type="com.lwl.domain.Account">
<!--property爲當前類的屬性,即count類,column爲主表數據庫的列名,主鍵用id標籤-->
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--user屬性屬於另一個類的實例,需要進行映射-->
<!--association :一對一的關係映射,對user實例的內容進行封裝-->
<!--property:是accout類中需要映射的user屬性,column是其在user屬性在count數據庫中對應的表名,javaType是其user對應的類-->
<association property="user" column="uid" javaType="com.lwl.domain.User">
<!--property爲當前類的屬性,column爲主表數據庫的列名,主鍵用id標籤-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
</association>
</resultMap>
參考鏈接:https://blog.csdn.net/qq_42780864/article/details/81429114
修改Account類
從表實體應該包含一個主表的對象的實例
重新定義AccountDao.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.lwl.dao.IAccountDao">
<!--定義封裝account和user的resultMap-->
<resultMap id="accountUserMap" type="com.lwl.domain.Account">
<!--property爲當前類的屬性,column爲主表數據庫的列名,主鍵用id標籤-->
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--association :一對一的關係映射,配置user的內容,-->
<!--property:是accout類中user屬性,column是其在數據庫中對應的表名,javaType是其對應的類-->
<association property="user" column="uid" javaType="com.lwl.domain.User">
<!--property爲當前類的屬性,column爲主表數據庫的列名,主鍵用id標籤-->
<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="age" column="age"></result>
<result property="email" column="email"></result>
<result property="qq" column="qq"></result>
</association>
</resultMap>
<!--查詢所有-->
<select id="findAll" resultMap="accountUserMap">
select a.*,u.* from account a, user u where u.id=a.uid;
</select>
<!--查詢所有賬戶,包含用戶名和地址-->
<select id="findAllAccount" resultType="com.lwl.domain.AccountUser">
select a.*,u.username,u.address from account a, user u where u.id=a.uid;
</select>
</mapper>
在AccountTest類中加入測試方法
//查詢所有賬戶及用戶信息
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
System.out.println(account.getUser());
}
}
一對多
修改count表的數據,使部分的user具有多個賬戶。
修改User對應,增加賬戶的集合屬性,以及對應的get和set方法
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
創建IUserDao.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.lwl.dao.IUserDao">
<!--定義User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<result property="age" column="age"></result>
<result property="email" column="email"></result>
<result property="address" column="address"></result>
<result property="qq" column="qq"></result>
<!--配置user對象中accounts集合的映射-->
<collection property="accounts" ofType="com.lwl.domain.Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!--查詢所有-->
<select id="findAll" resultMap="userAccountMap">
select * from user u left outer join account a on a.uid=u.id;
</select>
</mapper>
創建測試類進行查詢:
public class UserTest {
private InputStream is;
private SqlSession sqlSession;
private IUserDao userDao;
//初始化進行封裝
@Before //用於在測試方法執行之前執行
public void init() throws IOException {
//1.讀取配置文件,形成字節輸入流
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.獲取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.獲取SqlSession對象
sqlSession = factory.openSession();
//4.獲取dao的代理對象
userDao = sqlSession.getMapper(IUserDao.class);
}
//close進行封裝
@After //用於在測試方法執行之後執行
public void distory() throws IOException {
//提交事務
sqlSession.commit();
//6.關閉資源
sqlSession.close();
is.close();
}
//測試查詢所有
@Test
public void testFindAll(){
//5.執行查詢所有方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
System.out.println(user.getAccounts());
}
}
}
多對多
示例:用戶和角色
一個用戶可以有多個角色
一個角色可以賦予多個用戶
步驟:
1、建立兩張表:用戶表,角色表
讓用戶表和角色表具有多對多的關係。需要使用中間表,中間表中包含各自的主鍵,在中間表中是外鍵。
2、建立兩個實體類:用戶實體類和角色實體類
讓用戶和角色的實體類能體現出來多對多的關係
各自包含對方一個集合引用
3、建立兩個配置文件
用戶的配置文件
角色的配置文件
4、實現配置:
當我們查詢用戶時,可以同時得到用戶所包含的角色信息
當我們查詢角色時,可以同時得到角色的所賦予的用戶信息
創建數據庫:
上面一個是role表。另一個是中間表,指定兩表之間的關聯。
創建角色Role類並提供set和get以及toString方法:
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
//set和get略
}
創建相應Dao接口:
public interface IRoleDao {
List<Role> findAll();
}
映射的xml文件:
注意類中的屬性名和數據庫中的列名不一樣
<resultMap id="roleMap" type="role">
<id property="roleId" column="id"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</resultMap>
<!--查詢所有-->
<select id="findAll" resultMap="roleMap">
select * from role;
</select>
進行查詢測試:
public class RoleTest {
private InputStream is;
private SqlSession sqlSession;
private IRoleDao roleDao;
//初始化進行封裝
@Before //用於在測試方法執行之前執行
public void init() throws IOException {
//1.讀取配置文件,形成字節輸入流
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.獲取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.獲取SqlSession對象
sqlSession = factory.openSession();
//4.獲取dao的代理對象
roleDao = sqlSession.getMapper(IRoleDao.class);
}
//close進行封裝
@After //用於在測試方法執行之後執行
public void distory() throws IOException {
//提交事務
sqlSession.commit();
//6.關閉資源
sqlSession.close();
is.close();
}
//測試查詢所有
@Test
public void testFindAll(){
List<Role> roles = roleDao.findAll();
for (Role role : roles) {
System.out.println(role);
}
}
}
接下來實現:
當我們查詢角色時,可以同時得到角色的所賦予的用戶信息
在Role添加User的一個實例:
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
在IRoleDao.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.lwl.dao.IRoleDao">
<resultMap id="roleMap" type="role">
<!--寫成rid是因爲在SQL語句中對id起了別名爲rid-->
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="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="findAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
left outer join user_role ur on r.id = ur.rid
left outer join user u on u.id = ur.uid
</select>
</mapper>
測試:
//測試查詢所有
@Test
public void testFindAll(){
List<Role> roles = roleDao.findAll();
for (Role role : roles) {
System.out.println(role);
System.out.println(role.getUsers());
}
}
接下來實現:
當我們查詢角色時,可以同時得到角色的所賦予的用戶信息
修改SQL語句:
select u.*,r.id as rid,r.role_name,r.role_desc from user u
left outer join user_role ur on u.id = ur.uid
left outer join role r on r.id = ur.rid
在User表中添加Role的實例:
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
配置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.lwl.dao.IUserDao">
<resultMap id="userMap" type="user">
<!--寫成rid是因爲在SQL語句中對id起了別名爲rid-->
<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 property="roles" ofType="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<!--查詢所有-->
<select id="findAll" resultMap="userMap">
select u.*,r.id as rid,r.role_name,r.role_desc from user u
left outer join user_role ur on u.id = ur.uid
left outer join role r on r.id = ur.rid
</select>
</mapper>
進行測試:
/**
* @author liwenlong
* @data 2020/5/4
*/
public class UserTest {
private InputStream is;
private SqlSession sqlSession;
private IUserDao userDao;
//初始化進行封裝
@Before //用於在測試方法執行之前執行
public void init() throws IOException {
//1.讀取配置文件,形成字節輸入流
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.獲取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.獲取SqlSession對象
sqlSession = factory.openSession();
//4.獲取dao的代理對象
userDao = sqlSession.getMapper(IUserDao.class);
}
//close進行封裝
@After //用於在測試方法執行之後執行
public void distory() throws IOException {
//提交事務
sqlSession.commit();
//6.關閉資源
sqlSession.close();
is.close();
}
//測試查詢所有
@Test
public void testFindAll(){
//5.執行查詢所有方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
System.out.println(user.getRoles());
}
}
}