總結mybatis的多表查詢
-
- 前言
- 資料庫表及關系
- 一對多查詢
- 多對一及一對一查詢
- 總結
前言
表之間的關系有幾種:一對多、多對一、 一對一、多對多
在多對一關系中,把多的部分拆成一個一個對象其實就是一對一關系,如賬戶和使用者是多對一關系,但每個賬戶隻對應一個使用者。是以在mybatis中,多對一的關系可以看成一對一的關系。
這裡我把一對多和多對一的xml配置方式總結了一下,同時還有加載方式。
一對多,多對多:通常情況下我們都是采用延遲加載。
多對一,一對一:通常情況下我們都是采用立即加載。
至于注解方式和多對多查詢的xml和注解方式我會另外寫部落格。
資料庫表及關系
我們以使用者和賬戶為例,使用者可以有多個賬戶,賬戶隻能對應一個使用者。是以使用者對賬戶是一對多關系,賬戶對使用者是多對一關系。表如下圖所示,使用者表user,賬戶表account,賬戶表UID對應使用者表id。
一對多查詢
首先我們要在User實體類中添加List accounts的集合成員變量,表示一對多映射關系,主表實體含有從表實體的集合引用。
public class User implements Serializable{
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一對多映射關系,主表實體含有從表實體的集合引用
private List<Account> accounts;
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 + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
同時在User Dao接口中提供查詢所有方法findAll,在Account Dao接口中提供根據id查詢user的方法findById,以便延時加載時調用。
這裡說明因為使用者可能對應許多賬戶,當我們查詢使用者時可能并不需要賬戶資訊,而且如果我們每次查詢使用者時都立即查詢使用者的賬戶資訊,并且賬戶資訊有很多,勢必對記憶體有很大的開銷。是以當我們需要賬戶資訊時再調用findById方法去查詢使用者對應的賬戶資訊。
public interface IUserDao {
/**
* 查詢所有操作,并攜帶賬戶資訊
* @return
*/
List<User> findAll();
/**
* 根據id查詢一個使用者
* @param uid
*/
User findById(Integer uid);
}
public interface IAccountDao {
/**
* 查詢所有賬戶
* @return
*/
List<Account> findAll();
/**
* 根據使用者id查詢賬戶
* @param uid
* @return
*/
List<Account> findByUid(Integer uid);
}
然後配置userDao.xml,說明會在代碼中給出。
<mapper namespace="com.cc.dao.IUserDao">
<!--定義resultMap-->
<!--因為在主配置檔案中配置了domain包下的所有實體類别名,是以這裡封裝類型隻需要寫實體類名即可,不分大小寫-->
<resultMap id="userWithAccount" type="user">
<!--封裝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隊形中account集合的映射-->
<!--定義一對多的關系映射,實作對account的封裝,用collection标簽
ofType屬性指定内容:要封裝的實體對象類型
select屬性指定内容:查詢使用者的唯一辨別
column屬性指定内容:使用者根據id查詢是所需要的參數
-->
<collection property="accounts" ofType="account" column="id" select="com.cc.dao.IAccountDao.findByUid"></collection>
</resultMap>
<!--查詢所有-->
<select id="findAll" resultMap="userWithAccount">
select * from user
</select>
<!--根據id查詢一個使用者-->
<select id="findById" parameterType="java.lang.Integer" resultType="user">
select * from user where id=#{uid};
</select>
</mapper>
當然我們還要在主配置檔案中開啟延時加載,預設情況下是立即加載。
lazyLoadingEnabled:是否啟用延遲加載,mybatis預設為false,不啟用延遲加載。lazyLoadingEnabled屬性控制全局是否使用延遲加載,特殊關聯關系也可以通過嵌套查詢中fetchType屬性單獨配置(fetchType屬性值lazy或者eager)。
也就是說我們可以不用在主配置檔案中配置而在userDao.xml中配置,這裡我們采用全局配置。
<!--配置參數-->
<settings>
<!--開啟Mybatis支援延時加載-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
<!--配置domain包下所有實體類别名-->
<typeAliases>
<!--<typeAlias type="com.cc.domain.User" alias="user"></typeAlias>-->
<package name="com.cc.domain"></package>
</typeAliases>
然後我們就可以測試了
public class UserTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession sqlSession;
private IUserDao userDao;
@Before//在測試方法執行之前執行
public void init() throws IOException {
//1.讀取配置檔案,生成位元組輸入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.生成SqlSessionFactory
factory = new SqlSessionFactoryBuilder().build(in);
//3.擷取SqlSession
sqlSession = factory.openSession();
//4.擷取dao的代理對象
userDao = sqlSession.getMapper(IUserDao.class);
}
@After//在測試方法執行之後執行
public void destory() throws IOException {
//送出事務
sqlSession.commit();
//關閉資源
sqlSession.close();
in.close();
}
/**
* 測試查詢所有賬戶
*/
@Test
public void TestFindAll() {
//5.執行查詢所有方法
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
System.out.println(user.getAccounts());
}
}
}
先把周遊輸出部分代碼注釋掉,測試可以看出我們隻查詢了使用者資訊。
然後去掉注釋,發現當我們需要輸出使用者賬戶時,他就會去查詢使用者的賬戶資訊。
多對一及一對一查詢
步驟其實和一對多差不多。
首先我們在account實體類中加入user成員變量表示一對一映射。
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;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
Dao接口中需要的的方法在上面總結一對多查詢時的圖中已經給出。
然後配置accountDao.xml,這裡是立即查詢,在我們已經配置全局延時加載的情況下,我們需要配置fetchType=“eager”。
<mapper namespace="com.cc.dao.IAccountDao">
<!--開啟account支援二級緩存-->
<cache/>
<!--定義封裝account和user的resultMap-->
<resultMap id="accountAndUser" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--定義一對一的關系映射,實作對user的封裝
select屬性指定内容:查詢使用者的唯一辨別
column屬性指定内容:使用者根據id查詢是所需要的參數
fetchType屬性指定内容:lazy延時加載,eager立即加載。
-->
<association property="user" column="uid" javaType="user" select="com.cc.dao.IUserDao.findById" fetchType="eager"></association>
</resultMap>
<!--查詢所有-->
<select id="findAll" resultMap="accountAndUser">
SELECT * from account
</select>
<!--根據使用者id查詢-->
<select id="findByUid" parameterType="java.lang.Integer" resultType="account" useCache="true">
select * from account where uid = #{uid}
</select>
</mapper>
然後我們就可以測試。可以看出當查詢賬戶時就立即查詢了對應的使用者資訊。
總結
第一嘗試部落格,肯定有很多欠缺的地方,希望大家看到能評論指出。我自己學mybatis時間也不是很長,這裡隻給出了簡單的案例。如果什麼了解不到位的地方也請大家諒解并指出。以後我會更多的寫部落格,希望能夠給一起處在學習階段的人一些啟發。