第三天:mybatis的深入和多表
mybatis框架 學習計劃
共四天
第一天:mybatis入門
mybatis的概述
mybatis的環(huán)境搭建
mybatis入門案例
自定義mybatis框架(主要的目的是為了讓大家了解mybatis中執(zhí)行細節(jié))
第二天:mybatis基本使用
mybatis的單表crud操作
mybatis的參數(shù)和返回值
mybatis的dao編寫
mybatis配置的細節(jié)
幾個標簽的使用
第三天:mybatis的深入和多表
mybatis的連接池
mybatis的事務(wù)控制及設(shè)計的方法
mybatis的多表查詢
一對多(多對一)
多對多
第四天:mybatis的緩存和注解開發(fā)
mybatis中的加載時機(查詢的時機)
mybatis中的一級緩存和二級緩存
mybatis的注解開發(fā)
單表CRUD
多表查詢
3.1 Mybatis 連接池與事務(wù)深入
3.1.1 Mybatis 的連接池技術(shù)
? 我們在前面的 WEB 課程中也學習過類似的連接池技術(shù),而在 Mybatis 中也有連接池技術(shù),但是它采用的是自己的連接池技術(shù)而柑。在 Mybatis 的 SqlMapConfig.xml 配置文件中,通過<dataSource type=”pooled”>
來實現(xiàn) Mybatis 中連接池的配置文捶。
Mybatis 連接池的分類
3.1.1.1 Mybatis 連接池的分類
在 Mybatis 中我們將它的數(shù)據(jù)源 dataSource
分為以下幾類:
UNPOOLED
不使用連接池的數(shù)據(jù)源
POOLED
使用連接池的數(shù)據(jù)源
JNDI
使用 JNDI 實現(xiàn)的數(shù)據(jù)源
? 相應地,MyBatis 內(nèi)部分別定義了實現(xiàn)了 java.sql.DataSource 接口的 UnpooledDataSource,
PooledDataSource 類來表示 UNPOOLED荷逞、POOLED 類型的數(shù)據(jù)源粹排。
? 在這三種數(shù)據(jù)源中,我們一般采用的是 POOLED 數(shù)據(jù)源(很多時候我們所說的數(shù)據(jù)源就是為了更好的管理數(shù)據(jù)庫連接,也就是我們所說的連接池技術(shù))种远。
Mybatis 中數(shù)據(jù)源的配置
3.1.1.2 Mybatis 中數(shù)據(jù)源的配置
? 我們的數(shù)據(jù)源配置就是在 SqlMapConfig.xml
文件中,具體配置如下:
<!-- 配置數(shù)據(jù)源(連接池)信息 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
? MyBatis 在初始化時,根據(jù)<dataSource>的 type 屬性來創(chuàng)建相應類型的的數(shù)據(jù)源 DataSource,即:
type="POOLED"
: MyBatis 會創(chuàng)建 PooledDataSource 實例
type="UNPOOLED"
: MyBatis 會創(chuàng)建 UnpooledDataSource 實例
type="JNDI"
: MyBatis 會從 JNDI 服務(wù)上查找 DataSource 實例,然后返回使用
3.1.1.3 Mybatis 中 DataSource
的存取
? MyBatis 是 通 過 工 廠 模 式 來 創(chuàng) 建 數(shù) 據(jù) 源 DataSource 對 象 的 , MyBatis 定 義 了 抽 象 的 工 廠 接口 :org.apache.ibatis.datasource.DataSourceFactory
,通過其 getDataSource()
方法返回數(shù)據(jù)源DataSource
。
下面是 DataSourceFactory 源碼,具體如下:
package org.apache.ibatis.datasource;
import java.util.Properties;
import javax.sql.DataSource;
/**
* @author Clinton Begin
*/
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}
? MyBatis 創(chuàng)建了 DataSource
實例后,會將其放到 Configuration
對象內(nèi)的 Environment
對象中, 供以后使用顽耳。
具體分析過程如下:
1.先進入 XMLConfigBuilder
類中,可以找到如下代碼:
2.分析 configuration
對象的 environment
屬性,結(jié)果如下:
3.1.1.4 Mybatis 中連接的獲取過程分析
? 當我們需要創(chuàng)建 SqlSession
對象并需要執(zhí)行 SQL 語句時,這時候 MyBatis 才會去調(diào)用 dataSource
對象來創(chuàng)建 java.sql.Connection
對象坠敷。也就是說,java.sql.Connection
對象的創(chuàng)建一直延遲到執(zhí)行 SQL 語句的時候。
@Test
public void testSql() throws Exception {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("findUserById",41);
System.out.println(list.size());
}
? 只有當?shù)?4 句 sqlSession.selectList("findUserById")
,才會觸發(fā) MyBatis 在底層執(zhí)行下面這個方
法來創(chuàng)建 java.sql.Connection
對象射富。
如何證明它的加載過程呢?
我們可以通過斷點調(diào)試,在 PooledDataSource
中找到如下 popConnection()
方法,如下所示:
分析源代碼,得出 PooledDataSource
工作原理如下:
下面是連接獲取的源代碼:
? 最后我們可以發(fā)現(xiàn),真正連接打開的時間點,只是在我們執(zhí)行 SQL 語句時,才會進行膝迎。其實這樣做我們也可以進一步發(fā)現(xiàn),數(shù)據(jù)庫連接是我們最為寶貴的資源,只有在要用到的時候,才去獲取并打開連接,當我們用完了就再立即將數(shù)據(jù)庫連接歸還到連接池中。
3.1.2 Mybatis 的事務(wù)控制
3.1.2.1 Mybatis 中手動提交事務(wù)
? Mybatis 中事務(wù)的提交方式,本質(zhì)上就是調(diào)用 JDBC 的 setAutoCommit()
來實現(xiàn)事務(wù)控制胰耗。
我們運行之前所寫的代碼:
@Test
public void testSaveUser() throws Exception {
User user = new User();
user.setUsername("mybatis user09");
//6.執(zhí)行操作
int res = userDao.saveUser(user);
System.out.println(res);
System.out.println(user.getId());
}
@Before//在測試方法執(zhí)行之前執(zhí)行
public void init()throws Exception {
//1.讀取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創(chuàng)建構(gòu)建者對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.創(chuàng)建 SqlSession 工廠對象
factory = builder.build(in);
//4.創(chuàng)建 SqlSession 對象
session = factory.openSession();
//5.創(chuàng)建 Dao 的代理對象
userDao = session.getMapper(IUserDao.class);
}
@After//在測試方法執(zhí)行完成之后執(zhí)行
public void destroy() throws Exception{
//7.提交事務(wù)
session.commit();
//8.釋放資源
session.close();
in.close();
}
? 這是我們的Connection
的整個變化過程,通過分析我們能夠發(fā)現(xiàn)之前的 CUD 操作過程中,我們都要手動進行事務(wù)的提交,原因是 setAutoCommit()
方法,在執(zhí)行時它的值被設(shè)置為 false
了,所以我們在 CUD 操作中,必須通過 sqlSession.commit()
方法來執(zhí)行提交操作
3.1.2.2 Mybatis 自動提交事務(wù)的設(shè)置
? 通過上面的研究和分析,現(xiàn)在我們一起思考,為什么 CUD 過程中必須使用 sqlSession.commit()
提交事務(wù)?主要原因就是在連接池中取出的連接,都會將調(diào)用 connection.setAutoCommit(false)
方法,這樣我們就必須使用 sqlSession.commit()
方法,相當于使用了 JDBC 中的 connection.commit()
方法實現(xiàn)事務(wù)提交限次。
明白這一點后,我們現(xiàn)在一起嘗試不進行手動提交,一樣實現(xiàn) CUD 操作。
@Before//在測試方法執(zhí)行之前執(zhí)行
public void init()throws Exception {
//1.讀取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創(chuàng)建構(gòu)建者對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.創(chuàng)建 SqlSession 工廠對象
factory = builder.build(in);
//4.創(chuàng)建 SqlSession 對象
session = factory.openSession(true);
//5.創(chuàng)建 Dao 的代理對象
userDao = session.getMapper(IUserDao.class);
}
@After//在測試方法執(zhí)行完成之后執(zhí)行
public void destroy() throws Exception{
//7.釋放資源
session.close();
in.close();
}
? 我們發(fā)現(xiàn),此時事務(wù)就設(shè)置為自動提交了,同樣可以實現(xiàn) CUD 操作時記錄的保存宪郊。雖然這也是一種方式,但就編程而言,設(shè)置為自動提交方式為 false 再根據(jù)情況決定是否進行提交,這種方式更常用掂恕。因為我們可以根據(jù)業(yè)務(wù)情況來決定提交是否進行提交。
3.2 Mybatis 的動態(tài) SQL 語句
3.2.1 動態(tài) SQL 之<if>
標簽
? 我們根據(jù)實體類的不同取值,使用不同的 SQL 語句來進行查詢弛槐。比如在 id 如果不為空時可以根據(jù) id 查詢,如果 username 不同空時還要加入用戶名作為條件懊亡。這種情況在我們的多條件組合查詢中經(jīng)常會碰到。
- 持久層 Dao 接口
/**
* 根據(jù)傳入?yún)?shù)條件
* @param user 查詢的條件,有可能有用戶名,有可能有性別,也有可能有地址,還有可能是都有
* @return
*/
List<User> findUserByCondition(User user);
- 持久層 Dao 映射配置
<!--根據(jù)條件查詢-->
<select id="findUserByCondition" resultType="org.example.domain.User" parameterType="org.example.domain.User">
select * from user
where 1=1
<if test="username != null and username != '' ">
and username like concat('%',#{username},'%')
</if>
<if test="address != null and address != '' ">
and address like concat('%',#{address},'%')
</if>
</select>
? 注意:<if>標簽的 test 屬性中寫的是對象的屬性名,如果是包裝類的對象要使用 OGNL 表達式的寫法乎串。
另外要注意 where 1=1 的作用~!
-
測試
@Test public void testFindUserByCondition(){ User user = new User(); user.setUsername("王"); List<User> list = userDao.findUserByCondition(user); for (User u: list) { System.out.println(u); } }
3.2.2 動態(tài) SQL 之<where>
標簽
為了簡化上面 where 1=1 的條件拼裝,我們可以采用<where>
標簽來簡化開發(fā)店枣。
持久層 Dao 映射配置
<!--根據(jù)條件查詢-->
<select id="findUserByCondition" resultType="org.example.domain.User" parameterType="org.example.domain.User">
select * from user
<where>
<if test="username != null and username != '' ">
and username like concat('%',#{username},'%')
</if>
<if test="address != null and address != '' ">
and address like concat('%',#{address},'%')
</if>
</where>
</select>
3.2.3 動態(tài)標簽之<foreach>
標簽
? 傳入多個 id 查詢用戶信息,用下邊兩個 sql 實現(xiàn):
SELECT * FROM USERS WHERE username LIKE '%張%' AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE '%張%' AND id IN (10,89,16)
? 這樣我們在進行范圍查詢時,就要將一個集合中的值,作為參數(shù)動態(tài)添加進來。
這樣我們將如何進行參數(shù)的傳遞?
- 在 QueryVo 中加入一個 List 集合用于封裝參數(shù)
public class QueryVo implements Serializable {
private User user;
private List<Integer> ids;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
-
持久層 Dao 接口
/** * 根據(jù)queryVo提供的id集合,查詢用戶信息 * @param vo * @return */ List<User> findUserInIds(QueryVo vo);
持久層 Dao 映射配置
<!--根據(jù)queryVo提供的id集合,查詢用戶信息-->
<select id="findUserInIds" resultType="org.example.domain.User" parameterType="org.example.domain.QueryVo">
select * from user
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
SQL 語句:
select 字段 from user where id in (?)
<foreach>
標簽用于遍歷集合,它的屬性:
collection
: 代表要遍歷的集合元素,注意編寫時不要寫#{}
open:
代表語句的開始部分
close
: 代表結(jié)束部分
item="id" item
: 代表遍歷集合的每個元素,生成的變量名
sperator
: 代表分隔符
-
編寫測試方法
/** * foreach 標簽的使用 */ @Test public void testFindUserInIds(){ QueryVo vo = new QueryVo(); List<Integer> ids = new ArrayList<Integer>(); ids.add(41); ids.add(42); ids.add(51); vo.setIds(ids); List<User> list = userDao.findUserInIds(vo); for (User u: list) { System.out.println(u); } }
3.2.4 Mybatis 中簡化編寫的 SQL 片段
? Sql 中可將重復的 sql
提取出來,使用時用 include
引用即可,最終達到 sql 重用的目的叹誉。
-
定義代碼片段
?
<sql id="defaultUser"> select * from user </sql>
-
引用代碼片段
<!-- 配置查詢所有操作 --> <select id="findAll" resultType="org.example.domain.User"> <include refid="defaultUser"></include> <!-- select * from user--> </select>
3.3 Mybatis 多表查詢之一對多
3.3.1 一對一查詢(多對一)
? 使用 resultMap
,定義專門的 resultMap
用于映射一對一查詢結(jié)果鸯两。
通過面向?qū)ο蟮?has a)關(guān)系可以得知,我們可以在 Account 類中加入一個 User 類的對象來代表這個賬戶是哪個用戶的。
1. 定義賬戶信息的實體類
/**
* 賬號實體類
*/
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 +
", user=" + user +
'}';
}
}
2. 編寫 Sql 語句
select b.*,a.id as aid,a.uid,a.money from account a, user b where a.uid = b.id;
3. 定義賬戶的持久層 Dao 接口
/**
* 查詢所有賬號,同時還要獲取到當前賬號的所屬用戶信息
* @return
*/
List<Account> findAll();
4. 定義 AccountDao.xml
文件中的查詢配置信息
<!-- 定義account和user的resultMap-->
<resultMap id="accountUserMap" type="org.example.domain.Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一對一的關(guān)系映射: 配置封裝user的內(nèi)容 -->
<association property="user" column="uid" javaType="org.example.domain.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="findAll" resultMap="accountUserMap">
select b.*,a.id as aid,a.uid,a.money from account a, user b where a.uid = b.id;
</select>
5. 測試方法
/**
* 查詢所有賬號
*/
@Test
public void testFindAll() {
//6.使用代理對象執(zhí)行查詢所有方法
List<Account> accounts = accountDao.findAll();
for(Account account : accounts) {
System.out.println(account);
//System.out.println(account.getUser());
}
}
3.3.2 一對多查詢
? 需求:
查詢所有用戶信息及用戶關(guān)聯(lián)的賬戶信息长豁。
分析:
用戶信息和他的賬戶信息為一對多關(guān)系,并且查詢過程中如果用戶沒有賬戶信息,此時也要將用戶信息
查詢出來,我們想到了左外連接查詢比較合適钧唐。
1 . 編寫 SQL 語句
SELECT
u.*,
a.ID as aid,
a.MONEY
FROM
user u
LEFT JOIN account a on
u.id = a.UID
2 . User 類加入 List<Account>
/**
* 用戶的實體類
*/
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一對多關(guān)系映射; 主表實體應該包含從表實體的集合引用
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 List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
3. 用戶持久層 Dao 接口中加入查詢方法
/**
* 查詢所有用戶操作
* @return
*/
List<User> findAll();
4. 用戶持久層 Dao 映射文件配置
<!-- 定義User的resultMap -->
<resultMap id="userAccountMap" type="org.example.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<result property="address" column="address"></result>
<!--配置user對象中國accounts集合映射-->
<collection property="accounts" ofType="org.example.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
u.*,
a.ID as aid,
a.MONEY
FROM
user u
LEFT JOIN account a on
u.id = a.UID
</select>
5. 測試方法
@Test
public void testFindAll() {
//6.使用代理對象執(zhí)行查詢所有方法
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println("---------------------------------");
System.out.println(user);
for (Account account : user.getAccounts()){
System.out.println(account);
}
}
}
3.4 Mybatis 多表查詢之多對多
3.4.1 實現(xiàn) Role 到 User 多對多
通過前面的學習,我們使用 Mybatis 實現(xiàn)一對多關(guān)系的維護。多對多關(guān)系其實我們看成是雙向的一對多關(guān)系匠襟。
1 業(yè)務(wù)要求及實現(xiàn) SQL需求:
實現(xiàn)查詢所有對象并且加載它所分配的用戶信息钝侠。
分析:
查詢角色我們需要用到 Role 表,但角色分配的用戶的信息我們并不能直接找到用戶信息,而是要通過中間表(USER_ROLE 表)才能關(guān)聯(lián)到用戶信息。
下面是實現(xiàn)的 SQL 語句:
SELECT
r.id as rid,
r.role_name,
r.role_desc,
u.id ,
u.username,
u.birthday,
u.sex,
u.address
FROM
`role` r
LEFT JOIN user_role ur ON
r.ID = ur.RID
LEFT JOIN `user` u ON u.id = ur.UID
2 編寫角色實體類
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
// 多對多的關(guān)系映射: 一個角色可以賦予多個用戶
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
3 編寫 Role 持久層接口
/**
* 查詢所有角色
* @return
*/
List<Role> findAll();
}
4 編寫映射文件
<!--定義Role表的ResultMap-->
<resultMap id="roleMap" type="org.example.domain.Role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="ROLE_NAME"></result>
<result property="roleDesc" column="ROLE_DESC"></result>
<collection property="users" ofType="org.example.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
<!-- 查詢所有角色-->
<select id="findAll" resultMap="roleMap">
SELECT
r.id as rid,
r.role_name,
r.role_desc,
u.id ,
u.username,
u.birthday,
u.sex,
u.address
FROM
`role` r
LEFT JOIN user_role ur ON
r.ID = ur.RID
LEFT JOIN `user` u ON u.id = ur.UID
</select>
5 編寫測試類
public class RoleTest {
private InputStream in;
private SqlSession sqlSession;
private RoleDao roleDao;
@Before // test方法執(zhí)行之前執(zhí)行
public void init() throws IOException {
//1.讀取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創(chuàng)建 SqlSessionFactory 的構(gòu)建者對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.使用構(gòu)建者創(chuàng)建工廠對象 SqlSessionFactory
SqlSessionFactory factory = builder.build(in);
//4.使用 SqlSessionFactory 生產(chǎn) SqlSession 對象
sqlSession = factory.openSession();
//5.使用 SqlSession 創(chuàng)建 dao 接口的代理對象
roleDao = sqlSession.getMapper(RoleDao.class);
}
@After // test方法執(zhí)行之后執(zhí)行
public void destroy() throws IOException {
//提交事務(wù)
sqlSession.commit();
//7.釋放資源
sqlSession.close();
in.close();
}
/**
* 查詢所有賬號
*/
@Test
public void testFindAll() {
//6.使用代理對象執(zhí)行查詢所有方法
List<Role> roles = roleDao.findAll();
for(Role role : roles) {
System.out.println(role);
System.out.println(role.getUsers());
}
}
}
12
3.4.2 實現(xiàn) User 到 Role 的多對多
? 從 User 出發(fā),我們也可以發(fā)現(xiàn)一個用戶可以具有多個角色,這樣用戶到角色的關(guān)系也還是一對多關(guān)系酸舍。這樣我們就可以認為 User 與 Role 的多對多關(guān)系,可以被拆解成兩個一對多關(guān)系來實現(xiàn)帅韧。
1 業(yè)務(wù)要求及實現(xiàn) SQL需求:
SELECT
u.id ,
u.username,
u.birthday,
u.sex,
u.address,
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
2 編寫角色實體類
/**
* 用戶的實體類
*/
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一對多關(guān)系映射; 主表實體應該包含從表實體的集合引用
private List<Account> accounts;
// 多對多的關(guān)系映射: 一個用戶可以具有多個角色
private List<Role> roles;
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 List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
3 編寫 Role 持久層接口
/**
* 查詢所有用戶及權(quán)限信息
* @return
*/
List<User> findAllRole();
4 編寫映射文件
<!-- 定義User權(quán)限的resultMap -->
<resultMap id="userRoleMap" type="org.example.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<result property="address" column="address"></result>
<!--配置user對象中國accounts集合映射-->
<collection property="roles" ofType="org.example.domain.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="findAllRole" resultMap="userRoleMap">
SELECT
u.id ,
u.username,
u.birthday,
u.sex,
u.address,
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>
5 編寫測試類
@Test
public void testFindAllRole(){
List<User> users = userDao.findAllRole();
for (User user : users){
System.out.println(user);
System.out.println(user.getRoles());
}
}