Spring 學習小記(九)
MyBatis對映檔案
本小記學習目標
1.MyBatis的核心配置檔案(全域性配置檔案)的介紹
2.掌握MyBatis的SQL對映檔案(重點掌握)
3.掌握MyBatis的級聯查詢實現方法
一、MyBatis核心配置檔案
MyBatis核心配置檔案,配置了很多影響MyBatis行為的資訊,這些資訊通常來說也只會配置在一個檔案中,並且一般是不會去輕易改變的,當它與Spring整合後,這些配置資訊會配置到Spring的配置檔案中,在實際的開發過程中需要去編寫或修改這個配置檔案的情況不多。
MyBatis核心配置檔案的模板如下:
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
configuration
PUBLIC
"-//
mybatis.org//DTD
Config 3.0//EN"
"
http://mybatis.org/dtd/mybatis-3-config.dtd
"
>
<
configuration
>
<!-- 屬性 -->
<
properties
/>
<!-- 設定 -->
<
settings
>
<
setting
name=
""
value=
""
/>
</
settings
>
<!-- 型別命名(別名) -->
<
typeAliases
/>
<!-- 型別處理器 -->
<
typeHandlers
/>
<!-- 物件工廠 -->
<
objectFactory
type=
""
/>
<!-- 外掛 -->
<
plugins
>
<
plugin
interceptor=
""
></
plugin
>
</
plugins
>
<!-- 配置環境 -->
<
environments
default=
""
>
<!-- 環境變數 -->
<
environment
id=
""
>
<!-- 事務管理器 -->
<
transactionManager
type=
""
/>
<!-- 資料來源 -->
<
dataSource
type=
""
/>
</
environment
>
</
environments
>
<!-- 資料庫廠商標識 -->
<
databaseIdProvider
type=
""
/>
<!-- 對映器,通知MyBatis去哪裡去找對映檔案 -->
<
mappers
>
<
mapper
resource=
"com/XXX/XXX/XXXMapper.xml"
/>
</
mappers
>
</
configuration
>
二、MyBatis對映檔案
MyBatis對映器介紹
對映器,它是MyBatis中最為重要的元件,它是由介面加上Xml檔案(sql對映檔案)組成。MyBatis也可以由註解來完成,但是一般來說不常用註解做Sql對映
Sql對映檔案的常用配置元素有如下一些:
select 查詢語句 可以自定義引數、返回結果集……
insert 插入語句 執行後返回一個整數,表示插入的記錄行數
update 更新語句 執行後返回一個整數,表示更新的記錄行數
delete 刪除語句 執行後返回一個整數,表示刪除的記錄行數
sql 定義一部分sql
resultMap 用來描述由資料庫結果集來載入物件
select元素
<select>元素用來對映SQL的select語句。例如:
<!-- 根據id查詢一條記錄 -->
<
select
id=
"selectStudentById"
parameterType=
"Integer"
resultType=
"com.xiaoxie.pojo.Student"
>
select id,name,age from student where 1=1 and id=#{id}
</
select
>
在上面的配置中parameterType指定為Integer,表明引數是一個Integer型別
resultType指定為com.xiaoxie.pojo.Student,表明返回的是一個Student類的物件
sql語句中#{id},表示傳入的引數是id屬性的值
select元素的常用屬性
id:它與Mapper的名稱空間組合使用,是一個唯一的識別符號,供MyBatis呼叫
parameterType:它表示傳入sql語句的引數型別的全限定名或別名。它是一個可選屬性,MyBatis可以推斷出具體傳入語句的引數
resultType:指定返回的型別(全限定名或別名)如果是集合型別,返回的是集合元素的型別,返回時可以使用resultType或resultMap之一
resultMap:它是對映集的引用,與<resultMap元素一起使用>,返回時可以使用reusltType或resultMap之一
flushCache:用於設定在呼叫sql語句後時否要求MyBatis清空之前查詢的本地快取和二級快取,預設是false
useCache:啟動二級快取開關,預設是true
timeout:設定超時時間,單位是秒,如果超時則會丟擲異常
fetchSize:獲取記錄的總條數設定
statementType:告訴MyBatis使用哪個JDBC的Statement工作,可取值:STATEMENT(Statement)、PREPARED(PreparedStatement)、CALLABLE(CallbleStatement)
resutlSetType:針對JDBC的ResultSet介面而言,它的值可以設定為FORWARD_ONLY(只可以向前訪問)、SCROLL_SENSITIVE(雙向滾動,但不及時更新)、SCROLL_INSENSITIVE(雙向滾動,及時更新)
關於多個引數傳遞的問題
方式一:使用Map做為引數傳遞
在實際的應用開發過程中,查詢sql語句通常需要多個查詢引數(多個條件),這個時候可以在parameterType屬性中指定為map
在Mapper中做如下查詢定義
<!-- 測試多引數傳遞 -->
<
select
id=
"selectStudentByNameAndAge"
resultType=
"com.xiaoxie.pojo.Student"
parameterType=
"map"
>
select id,name,age from student
where 1=1
and name=#{name}
and age=#{age}
</
select
>
這裡可以看到parameterType指定的為map
在對應的Dao介面中對以上標識定義介面方法與之對應
//測試多引數查詢,條件:姓名、年齡
List<Student> selectStudentByNameAndAge(Map<String,Object>
param);
在測試類中新增如下方法進行測試
System.
out.println(
"測試多條件引數:");
//Map條件
Map<String,Object>
param =
new HashMap<>();
param.put(
"name",
"張飛");
param.put(
"age",26);
StudentDao
dao = (StudentDao)
context.getBean(
"studentDao");
List<Student>
stu =
dao.selectStudentByNameAndAge(
param);
for (Student
student :
stu) {
System.
out.println(
student);
}
從上面我們可以看到我們定義了一個map,map的key對應的就是查詢語句中的引數名稱
方式二:使用Java Bean來傳遞引數
對於引數複雜的情況下我們使用Map的方式傳遞引數是比較複雜的需要對引數進行初始化
使用JavaBean作為引數則是專門為引數建立一個JavaBean的類
在com.xiaoxie.dao.param包下建立一個基礎的引數pojo類
package com.xiaoxie.dao.param;
public
class StudnetNameAndAgeParam {
private String
name;
private Integer
age;
public String getName() {
return
name;
}
public
void setName(String
name) {
this.
name =
name;
}
public Integer getAge() {
return
age;
}
public
void setAge(Integer
age) {
this.
age =
age;
}
}
在Mapper中做如下定義
<!-- 測試多引數的傳遞,這裡使用JavaBean的方式傳入多個引數 -->
<
select
id=
"selectStudentByNameAndAgeUseJavaBean"
resultType=
"com.xiaoxie.pojo.Student"
parameterType=
"com.xiaoxie.dao.param.StudnetNameAndAgeParam"
>
select id,name,age from student
where 1=1
and name=#{name}
and age=#{age}
</
select
>
在dao介面中定時對應的介面方法
//測試多引數查詢,條件:姓名、年齡,作用JavaBean
List<Student> selectStudentByNameAndAgeUseJavaBean(StudnetNameAndAgeParam
param);
在測試類的main方法中做如下測試可以把建立的JavaBean物件作為引數傳遞進去
System.
out.println(
"使用JavaBean作為引數傳遞");
StudnetNameAndAgeParam
beanParam =
new StudnetNameAndAgeParam();
beanParam.setName(
"劉備");
beanParam.setAge(30);
stu =
dao.selectStudentByNameAndAgeUseJavaBean(
beanParam);
for (Student
student :
stu) {
System.
out.println(
student);
}
對於多引數的傳遞方式是使用Map還是使用JavaBean,這個可以根據實際的情況靈活確定,如果覺得引數過多則可以選擇JavaBean這種方式
insert元素
<insert>元素用於對映插入語句,在MyBatis插入完成後會返回一個整數表示它執行影響的行數。它的屬性與select元素的不只屬性大部分都是一樣的,有如下幾個特有的屬性
keyProperty:這個屬性是把插入或更新操作時返回值賦給po類的某個屬性上,通常來說會設定為主鍵對應的屬性,如果是聯合主鍵,可以用逗號把多個值隔開
keyColumn:這個屬性是用來設定第幾例為主鍵,當主鍵不是第一列的時候是需要設定的,如果是聯合主鍵則可以使用多個值用逗號隔開
useGeneratedKeys:這個屬性是MyBatis使用JDBC的getGeneratedKeys()方法獲取資料庫內部產生的主鍵,預設值是false
對於mysql、sqlServer資料庫一般會採用自動遞增值作為主鍵,在insert資料完成後,有時是需要剛和新增資料的主鍵值的,這個時候則可以在mapper中對於insert元素新增keyProperty和useGeneratedKeys屬性
自動回填主鍵
在mapper中定義insert元素如下
<!-- 新增一條記錄 -->
<
insert
id=
"addStudent"
parameterType=
"com.xiaoxie.pojo.Student"
keyProperty=
"id"
useGeneratedKeys=
"true"
>
insert into student(name,age) values(#{name},#{age})
</
insert
>
這裡表示主鍵值是id屬性
通過如下方式新增記錄
Student
stu1 =
new Student(
"劉備",30);
int
rows =
studentDao.addStudent(
stu1);
System.
out.println(
"===============新增"+
rows +
"條記錄==============");
System.
out.println(
"新增記錄的主鍵為:" +
stu1.getId());
那麼新增記錄的主鍵會回寫到stu1的id屬性上
自主設定主鍵
有些資料庫是不支援自增主鍵的這個時候則需要自主去設定主鍵,這個時候可以使用<selectKey>元素來實現
在Mapper中需要做如下定義
<
insert
id=
"addStudent"
parameterType=
"com.xiaoxie.pojo.Student"
>
<
selectKey
keyProperty=
"id"
resultType=
"Integer"
order=
"BEFORE"
>
select if(max(id) is null,1,max(id)+1) as mid from student
</
selectKey
>
insert into student(id,name,age) values(#{id},#{name},#{age})
</
insert
>
注:一般對於mySql這樣的資料庫是不可以這樣操作的,因為原表的資料可能會被刪除記錄,這個時候max出來的主鍵是不正確的,非要使用則需要使用額外表來做記錄主鍵當前的遞增值
<selectKey>元素中的keyProperty屬性表表示查詢到的返回給到Po類的哪個屬性,order表示在什麼時機執行(可選值:BEFORE、AFTER)這裡的之前和之後是相對於執行insert語句來說的。
update元素和delete元素
它們分別對應的是sql語句中的update和delete,其屬性與insert、select屬性差不多,它在執行後也會返回一個整數,表示影響到了資料庫多少行記錄
mapper中的定義可以為如下
<!-- 修改一條記錄 -->
<
update
id=
"updateStudentById"
parameterType=
"com.xiaoxie.pojo.Student"
>
update student set name=#{name},age=#{age} where 1=1 and id=#{id}
</
update
>
<!-- 刪除一條記錄 -->
<
delete
id=
"deleteStudentById"
parameterType=
"Integer"
>
delete from student where id=#{id}
</
delete
>
sql元素
這個元素主要是用來自定義sql程式碼片段,這些sql片段可以在後續的配置中進行引用
如下示例:可以把需要使用到的列名用sql元素進行定義,在後續需要使用的地方進行引用即可
<!-- 使用
sql
標籤自定義部分
sql
語句供其他配置中引用 -->
<
sql
id=
"studentColumns"
> id,name,age
</
sql
>
<
select
id=
"selectStudentByColumns"
resultType=
"com.xiaoxie.pojo.Student"
>
select
<
include
refid=
"studentColumns"
/> from student
</
select
>
resultMap元素
它是MyBatis中最為重要的元素,主要用來定義對映規則、級聯的更新以及定義型別轉化器……
<resultMap>元素的結構說明:
<resultMap type="" id="">
<constructor> <!-- 類在例項化的時候用來注入結果到構造方法 -->
<idArg/> <!-- ID引數,結果為ID -->
<arg/> <!-- 注入到構造方法的一個普通結果 -->
</constructor>
<id/> <!-- 用來表示哪個列是主鍵 -->
<result/> <!-- 注入到欄位或JavaBean屬性的普通結果 -->
<association property=""/> <!-- 用於一對一關聯 -->
<collection property=""/> <!-- 用於一對多、多對多關聯 -->
<discriminator javaType=""> <!-- 使用結果值來決定使用哪個結果對映 -->
<case value=""/> <!-- 基於某些值的結果對映 -->
</discriminator>
</resultMap>
簡單說明:
resultMap的type屬性表示需要的pojo,id屬性則表示resultMap的唯一值
子元素<constructor>用來配置構造方法(在POJO中沒有定義無參構造時使用)
子元素<id>表示哪個列為主鍵
子元素<result>表示POJO和資料表普通列的對映關係
子元素<association>、<collection>、<discriminator>用在級聯的情況
使用Map來儲存結果集
指的是在配置select元素時,指定resultType="map"
在Mapper中可以做如下定義
<!-- 使用Map來儲存結果集 -->
<
select
id=
"selectStudentUseMap"
resultType=
"map"
>
select * from student
</
select
>
在Dao介面中新增對應的介面方法
//使用Map來儲存查詢的結果集
List<Map<String,Object>> selectStudentUseMap();
在測試類中新增如下程式碼進行測試
System.
out.println(
"使用Map來儲存查詢返回的結果集");
List<Map<String, Object>>
studentMap =
dao.selectStudentUseMap();
Set<Map.Entry<String, Object>>
entrySet =
null;
for (Map<String, Object>
map :
studentMap) {
//遍歷map
entrySet =
map.entrySet();
for (Map.Entry<String, Object>
entry :
entrySet) {
System.
out.println(
entry.getKey() +
":" +
entry.getValue());
}
System.
out.println(
"------------");
}
這裡我們通過測試的結果可以看到,當使用map做結果集的儲存時,map中的key為欄位名,value則是查詢結果返回的對應欄位的值,使用這種方式對於少量的記錄(比如一條記錄)很方便,但是可讀性並不高。
使用POJO儲存結果集
使用POJO進行結果集的儲存有兩個方面是比較好的
第一,可以使用resultType屬性
第二,當有複雜的對映或級聯,這個時候可以使用select元素的resultMap屬性配置對映集合
在mapper中配置resultMap元素
<!-- resultMap元素進行對映 -->
<
resultMap
type=
"com.xiaoxie.pojo.Student"
id=
"studentResult"
>
<
id
property=
"id"
column=
"id"
/>
<!-- 指定主鍵 -->
<
result
property=
"name"
column=
"name"
/>
<
result
property=
"age"
column=
"age"
/>
</
resultMap
>
<
select
id=
"selectStudentUseResultMap"
resultMap=
"studentResult"
>
select * from student
</
select
>
在Dao介面中新增對應的介面方法
//使用resultMap進行結果集的對映
List<Student> selectStudentUseResultMap();
在測試類中新增如下程式碼進行測試
System.
out.println(
"使用resultMap進行結果集的對映");
List<Student>
resultMap =
dao.selectStudentUseResultMap();
for (Student
student :
resultMap) {
System.
out.println(
student);
}
級聯查詢
級聯查詢,它有三種:一對一級聯,一對多級聯,多對多級聯
優點:可以方便地獲取關聯資料
缺點:過多的級聯會增加資料庫系統的複雜性,同時影響系統的效能
實際開發過程中需要根據實際的情況做取捨,一般不建議做資料庫級別的級聯,關聯的關係放在程式邏輯中即可
何為級聯查詢?
當有一個表A,它其中有一個欄位做外來鍵引用了表B的主鍵,這個時候通過表A的外來鍵把表B對應的記錄查詢出來,這個就是級聯查詢
一對一級聯查詢
MyBatis中對於一對一級聯查詢的處理方式是,通過<resultMap>元素的子元素<association>元素處理,在這個子元素中通常使用以下屬性
property:指定對映到實體類的物件屬性
column:指定表中對應的欄位
javaType:指定對映到實體物件屬性的型別
select:指定引入巢狀查詢的子sql語句
在資料庫中建立如下兩張表
-- 身份證表
create table idcard(
id BIGINT(19) NOT NULL auto_increment COMMENT '主鍵ID',
code varchar(18) NOT NULL DEFAULT '' COMMENT '身份證號碼',
PRIMARY key(id)
);
-- 身份資訊表
CREATE TABLE `person` (
`id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`name` varchar(20) DEFAULT '' COMMENT '姓名',
`age` int(11) NOT NULL DEFAULT '0' COMMENT '年齡',
`address` varchar(512) DEFAULT '' COMMENT '常住地址',
`idcard_id` bigint(19) DEFAULT NULL COMMENT 'idcard表的id',
PRIMARY KEY (`id`),
KEY `idcard` (`idcard_id`),
CONSTRAINT `idcard` FOREIGN KEY (`idcard_id`) REFERENCES `idcard` (`id`)
);
新增POJO實體類:IdCard,Person
IdCard:
package com.xiaoxie.pojo;
public
class IdCard {
private Integer
id;
private String
code;
/*Setter與Getter*/
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getCode() {
return
code;
}
public
void setCode(String
code) {
this.
code =
code;
}
@Override
public String toString() {
return
"idCard[id=+"+
id+
",code="+
code+
"]";
}
}
Person:
package com.xiaoxie.pojo;
public
class Person {
private Integer
id;
private String
name;
private Integer
age;
private String
address;
private IdCard
idcard;
//身份證資訊
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getName() {
return
name;
}
public
void setName(String
name) {
this.
name =
name;
}
public Integer getAge() {
return
age;
}
public
void setAge(Integer
age) {
this.
age =
age;
}
public String getAddress() {
return
address;
}
public
void setAddress(String
address) {
this.
address =
address;
}
public IdCard getIdcard() {
return
idcard;
}
public
void setIdcard(IdCard
idcard) {
this.
idcard =
idcard;
}
@Override
public String toString() {
return
"Person[id=+"+
id+
",name="+
name+
",age="+
age+
",address="+
address+
",idcard="+
idcard+
"]";
}
}
新增Mapper對映檔案
IdCardMapper:
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
mapper
<
mapper
namespace=
"com.xiaoxie.dao.IdCardDao"
>
<
select
id=
"selectIdCardById"
parameterType=
"Integer"
resultType=
"com.xiaoxie.pojo.IdCard"
>
select * from
idcard where id = #{id}
</
select
>
</
mapper
>
PersonMapper:
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
mapper
<
mapper
namespace=
"com.xiaoxie.dao.PersonDao"
>
<!-- 一對一級聯,執行兩個
sql
進行查詢 -->
<
resultMap
type=
"com.xiaoxie.pojo.Person"
id=
"idCardAdnPerson_1"
>
<
id
property=
"id"
column=
"id"
/>
<!-- 指定ID主鍵列 -->
<!-- 普通列的對映關係 -->
<
result
property=
"name"
column=
"name"
/>
<
result
property=
"age"
column=
"age"
/>
<
result
property=
"address"
column=
"address"
/>
<!-- 一對一的級聯查詢 -->
<
association
property=
"idcard"
column=
"idcard_id"
javaType=
"com.xiaoxie.pojo.IdCard"
select=
"com.xiaoxie.dao.IdCardDao.selectIdCardById"
/>
</
resultMap
>
<
select
id=
"selectPersonById_1"
parameterType=
"Integer"
resultMap=
"idCardAdnPerson_1"
>
select * from person where id=#{id}
</
select
>
<!-- 一對一級聯,執行一個
sql
語句 -->
<
resultMap
type=
"com.xiaoxie.pojo.Person"
id=
"idCardAdnPerson_2"
>
<
id
property=
"id"
column=
"id"
/>
<!-- 指定主鍵列 -->
<!-- 普通列的對映關係 -->
<
result
property=
"name"
column=
"name"
/>
<
result
property=
"age"
column=
"age"
/>
<
result
property=
"address"
column=
"address"
/>
<!-- 一對一的級聯查詢 -->
<
association
property=
"idcard"
javaType=
"com.xiaoxie.pojo.IdCard"
>
<
id
property=
"id"
column=
"idcard_id"
/>
<
result
property=
"code"
column=
"code"
/>
</
association
>
</
resultMap
>
<
select
id=
"selectPersonById_2"
parameterType=
"Integer"
resultMap=
"idCardAdnPerson_2"
>
select p.*,c.code from person p left join
idcard c on p.idcard_id = c.id
where p.id=#{id}
</
select
>
<!-- 一對一級聯,根據id查詢個人資訊,連線查詢(使用
pojo
儲存查詢結結果) -->
<
select
id=
"selectPersonById_3"
parameterType=
"Integer"
resultType=
"com.xiaoxie.dao.result.IdCardAdnPerson"
>
select p.*,c.code from person p left join
idcard c on p.idcard_id = c.id
where p.id=#{id}
</
select
>
</
mapper
>
對應新增Dao介面
idCardDao:
package com.xiaoxie.dao;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.pojo.IdCard;
@Repository(
"idCardDao")
@Mapper
public
interface IdCardDao {
IdCard selectIdCardById(Integer
id);
}
PersonDao:
package com.xiaoxie.dao;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.dao.result.IdCardAdnPerson;
import com.xiaoxie.pojo.Person;
@Repository(
"personDao")
@Mapper
public
interface PersonDao {
Person selectPersonById_1(Integer
id);
Person selectPersonById_2(Integer
id);
IdCardAdnPerson selectPersonById_3(Integer
id);
}
新增實體類來儲存MyBatis查詢返回的結果
IdCardAdnPerson:
package com.xiaoxie.dao.result;
public
class IdCardAdnPerson {
private Integer
id;
private String
name;
private Integer
age;
private String
address;
private String
code;
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getName() {
return
name;
}
public
void setName(String
name) {
this.
name =
name;
}
public Integer getAge() {
return
age;
}
public
void setAge(Integer
age) {
this.
age =
age;
}
public String getAddress() {
return
address;
}
public
void setAddress(String
address) {
this.
address =
address;
}
public String getCode() {
return
code;
}
public
void setCode(String
code) {
this.
code =
code;
}
@Override
public String toString() {
return
"IdCardAdnPerson[id=+"+
id+
",name="+
name+
",age="+
age+
",address="+
address+
",code="+
code+
"]";
}
}
在MyBatis的核心配置檔案中把Mapper的對映新增進去
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
configuration
PUBLIC
"-//
mybatis.org//DTD
Config 3.0//EN"
"
http://mybatis.org/dtd/mybatis-3-config.dtd
"
>
<
configuration
>
<!-- 在MyBatis進行巢狀查詢時,使用延遲載入可以提高一定的效能所以在這裡可把把這個配置開啟 -->
<
settings
>
<!-- 延遲載入 -->
<
setting
name=
"lazyLoadingEnabled"
value=
"true"
/>
<!-- 按需載入 -->
<
setting
name=
"aggressiveLazyLoading"
value=
"false"
/>
</
settings
>
<!-- 查詢對映檔案 -->
<
mappers
>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/StudentMapper.xml"
/>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/IdCardMapper.xml"
/>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/PersonMapper.xml"
/>
</
mappers
>
</
configuration
>
新增Controller類
package com.xiaoxie.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import com.xiaoxie.dao.PersonDao;
import com.xiaoxie.dao.result.IdCardAdnPerson;
import com.xiaoxie.pojo.Person;
@Transactional
@Controller(
"personController1")
public
class PersonController1 {
@Autowired
private PersonDao
personDao;
public
void test() {
Person
P1 =
personDao.selectPersonById_1(1);
System.
out.println(
P1);
System.
out.println(
"----------------------");
Person
p2 =
personDao.selectPersonById_2(1);
System.
out.println(
p2);
System.
out.println(
"-----------------------");
IdCardAdnPerson
p3 =
personDao.selectPersonById_3(1);
System.
out.println(
p3);
}
}
在測試類中呼叫
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"spring-config.xml");
PersonController1
personController1 = (PersonController1)
context.getBean(
"personController1");
personController1.test();
注意:上述的例子中使用了資料庫的外來鍵使用資料庫的兩個表有了級聯關係,實際上在資料庫中沒有這種強制的級聯關係,只要邏輯上是這樣的也是可以使用上面的這種方式做級聯查詢的(實際應用中應該這種方式是更常見的,實際上這樣設計會更合理些)
一對多級聯查詢
一對多級聯是指的一個實體表A的記錄對應關聯實體表B中的多條記錄,比如一個使用者購物時會產生多個訂單,那麼使用者與訂單是一對多的關係。
新增兩個資料庫表
-- user表
CREATE TABLE `user` (
`id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`user_code` varchar(50) NOT NULL DEFAULT '' COMMENT '使用者編碼',
`user_name` varchar(50) NOT NULL DEFAULT '' COMMENT '使用者名稱稱',
PRIMARY KEY (`id`)
)
-- order表
CREATE TABLE `order` (
`id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`order_no` varchar(25) NOT NULL DEFAULT '' COMMENT '訂單編號',
`user_code` varchar(50) NOT NULL DEFAULT '' COMMENT '使用者編碼',
PRIMARY KEY (`id`)
)
新增POJO實體類
Order:
package com.xiaoxie.pojo;
public
class Order {
private Integer
id;
private String
order_no;
private String
user_code;
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getOrder_no() {
return
order_no;
}
public
void setOrder_no(String
order_no) {
this.
order_no =
order_no;
}
public String getUser_code() {
return
user_code;
}
public
void setUser_code(String
user_code) {
this.
user_code =
user_code;
}
@Override
public String toString() {
return
"Order[id=+"+
id+
",order_no="+
order_no+
",user_code="+
user_code+
"]";
}
}
User:
package com.xiaoxie.pojo;
import java.util.List;
public
class User {
private Integer
id;
private String
user_code;
private String
user_name;
private List<Order>
orders;
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getUser_code() {
return
user_code;
}
public
void setUser_code(String
user_code) {
this.
user_code =
user_code;
}
public String getUser_name() {
return
user_name;
}
public
void setUser_name(String
user_name) {
this.
user_name =
user_name;
}
public List<Order> getOrders() {
return
orders;
}
public
void setOrders(List<Order>
orders) {
this.
orders =
orders;
}
@Override
public String toString() {
return
"User[id=+"+
id+
",user_code="+
user_code+
",user_name="+
user_name+
",orders:"+
orders+
"]";
}
}
新增Mapper對映檔案
OrderMapper.xml:
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
mapper
<
mapper
namespace=
"com.xiaoxie.dao.OrderDao"
>
<
select
id=
"selectOrderByUserCode"
parameterType=
"String"
resultType=
"com.xiaoxie.pojo.Order"
>
select * from `order` where user_code = #{user_code}
</
select
>
</
mapper
>
UserMapper:
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
mapper
<
mapper
namespace=
"com.xiaoxie.dao.UserDao"
>
<
resultMap
type=
"com.xiaoxie.pojo.User"
id=
"userAndOrders_1"
>
<
id
property=
"id"
column=
"id"
/>
<
result
property=
"user_code"
column=
"user_code"
/>
<
result
property=
"user_name"
column=
"user_name"
/>
<!-- 一對多的級聯,這裡面ofType表示集合的元素型別,把user_code作為引數傳入(巢狀查詢) -->
<
collection
property=
"orders"
ofType=
"com.xiaoxie.pojo.Order"
column=
"user_code"
select=
"com.xiaoxie.dao.OrderDao.selectOrderByUserCode"
/>
</
resultMap
>
<
select
id=
"selectUserOrdersById_1"
parameterType=
"Integer"
resultMap=
"userAndOrders_1"
>
select * from user where id=#{id}
</
select
>
<!-- 一對多的級聯,一個查詢巢狀結果 -->
<
resultMap
type=
"com.xiaoxie.pojo.User"
id=
"userAndOrders_2"
>
<
id
property=
"id"
column=
"id"
/>
<
result
property=
"user_code"
column=
"user_code"
/>
<
result
property=
"user_name"
column=
"user_code"
/>
<
collection
property=
"orders"
ofType=
"com.xiaoxie.pojo.Order"
>
<
id
property=
"id"
column=
"id"
/>
<
result
property=
"order_no"
column=
"order_no"
/>
</
collection
>
</
resultMap
>
<
select
id=
"selectUserOrdersById_2"
parameterType=
"Integer"
resultMap=
"userAndOrders_2"
>
select u.*,o.id,o.order_no,o.user_code from user u left join `order` o on u.user_code = o.user_code
where u.id = #{id}
</
select
>
<!-- 一對多級聯,使用
pojo
類儲存結果 -->
<
select
id=
"selectUserOrdersById_3"
parameterType=
"Integer"
resultType=
"com.xiaoxie.dao.result.UserAndOrders"
>
select u.*,o.order_no from user u left join `order` o on u.user_code = o.user_code
where u.id = #{id}
</
select
>
</
mapper
>
新增對應的Dao介面
OrderDao:
package com.xiaoxie.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.pojo.Order;
@Repository(
"orderDao")
@Mapper
public
interface OrderDao {
List<Order> selectOrderByUserCode(String
user_code);
}
UserDao:
package com.xiaoxie.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.dao.result.UserAndOrders;
import com.xiaoxie.pojo.User;
@Mapper
@Repository(
"userDao")
public
interface UserDao {
User selectUserOrdersById_1(Integer
id);
User selectUserOrdersById_2(Integer
id);
List<UserAndOrders> selectUserOrdersById_3(Integer
id);
}
新增實體類來儲存MyBatis返回的結果
UserAndOrders:
package com.xiaoxie.dao.result;
public
class UserAndOrders {
private Integer
id;
private String
user_code;
private String
user_name;
private String
order_no;
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getUser_code() {
return
user_code;
}
public
void setUser_code(String
user_code) {
this.
user_code =
user_code;
}
public String getUser_name() {
return
user_name;
}
public
void setUser_name(String
user_name) {
this.
user_name =
user_name;
}
public String getOrder_no() {
return
order_no;
}
public
void setOrder_no(String
order_no) {
this.
order_no =
order_no;
}
@Override
public String toString() {
return
"UserOrders[id=+"+
id+
",user_code="+
user_code+
",user_name="+
user_name+
",order_no:"+
order_no+
"]";
}
}
在MyBatis的核心配置檔案中新增對這兩個Mapper對映檔案的掃描
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
configuration
PUBLIC
"-//
mybatis.org//DTD
Config 3.0//EN"
"
http://mybatis.org/dtd/mybatis-3-config.dtd
"
>
<
configuration
>
<!-- 在MyBatis進行巢狀查詢時,使用延遲載入可以提高一定的效能所以在這裡可把把這個配置開啟 -->
<
settings
>
<!-- 延遲載入 -->
<
setting
name=
"lazyLoadingEnabled"
value=
"true"
/>
<!-- 按需載入 -->
<
setting
name=
"aggressiveLazyLoading"
value=
"false"
/>
</
settings
>
<!-- 查詢對映檔案 -->
<
mappers
>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/StudentMapper.xml"
/>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/IdCardMapper.xml"
/>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/PersonMapper.xml"
/>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/OrderMapper.xml"
/>
<
mapper
resource=
"com/xiaoxie/dao/mybatis/UserMapper.xml"
/>
</
mappers
>
</
configuration
>
新增Controller類
UserOrderController:
package com.xiaoxie.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import com.xiaoxie.dao.UserDao;
import com.xiaoxie.dao.result.UserAndOrders;
import com.xiaoxie.pojo.User;
@Controller(
"userOrderController")
@Transactional
public
class UserOrderController {
@
Autowired
private UserDao
userDao;
public
void test() {
User
userOrders1 =
userDao.selectUserOrdersById_1(1);
System.
out.println(
userOrders1);
System.
out.println(
"-------------------------------");
User
userOrder2 =
userDao.selectUserOrdersById_2(1);
System.
out.println(
"-------------------------------");
List<UserAndOrders>
userOrder3 =
userDao.selectUserOrdersById_3(1);
System.
out.println(
userOrder3);
}
}
在測試類中進行測試:
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"spring-config.xml");
UserOrderController
userOrderController = (UserOrderController)
context.getBean(
"userOrderController");
userOrderController.test();
多對多級聯查詢
MyBatis是沒有對多對多的級聯實現的,因為多對多級聯是可以通過兩個一對多的級聯來實現的。
如我們的訂單表與訂單商品表一般就是多對多的關係,一個訂單A、訂單B可以有商品A、商品B
我們再向資料庫新增兩個表
-- order_detail表
CREATE TABLE `order_detail` (
`id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`order_no` varchar(25) NOT NULL DEFAULT '' COMMENT '訂單編號',
`goods_no` varchar(50) NOT NULL DEFAULT '' COMMENT '商品編碼',
PRIMARY KEY (`id`)
);
-- goods表
CREATE TABLE `goods` (
`id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`goods_no` varchar(50) NOT NULL DEFAULT '' COMMENT '商品編碼',
PRIMARY KEY (`id`)
);
新增POJO實體類
Goods
package com.xiaoxie.pojo;
import java.util.List;
public
class Goods {
private Integer
id;
private String
goods_no;
//商品對應訂單是一個對多的關係
private List<Order>
orders;
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getGoods_no() {
return
goods_no;
}
public
void setGoods_no(String
goods_no) {
this.
goods_no =
goods_no;
}
public List<Order> getOrders() {
return
orders;
}
public
void setOrders(List<Order>
orders) {
this.
orders =
orders;
}
@Override
public String toString() {
return
"Goods[id="+
id+
",goods_no="+
goods_no+
",orders="+
orders+
"]";
}
}
修改Order實體類把對goods的一對多關係加入進去
package com.xiaoxie.pojo;
import java.util.List;
public
class Order {
private Integer
id;
private String
order_no;
private String
user_code;
private List<Goods>
goods;
public Integer getId() {
return
id;
}
public
void setId(Integer
id) {
this.
id =
id;
}
public String getOrder_no() {
return
order_no;
}
public
void setOrder_no(String
order_no) {
this.
order_no =
order_no;
}
public String getUser_code() {
return
user_code;
}
public
void setUser_code(String
user_code) {
this.
user_code =
user_code;
}
public List<Goods> getGoods() {
return
goods;
}
public
void setGoods(List<Goods>
goods) {
this.
goods =
goods;
}
@Override
public String toString() {
return
"Order[id=+"+
id+
",order_no="+
order_no+
",user_code="+
user_code+
",goods="+
goods+
"]";
}
}
在OrderMapper的對映檔案中新增<resultMap>來處理多對多的查詢
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<!
DOCTYPE
mapper
<
mapper
namespace=
"com.xiaoxie.dao.OrderDao"
>
<
select
id=
"selectOrderByUserCode"
parameterType=
"String"
resultType=
"com.xiaoxie.pojo.Order"
>
select * from `order` where user_code = #{user_code}
</
select
>
<!-- 多對多的級聯 -->
<
resultMap
type=
"com.xiaoxie.pojo.Order"
id=
"OrdersAndGoods"
>
<
id
property=
"id"
column=
"id"
/>
<
result
property=
"order_no"
column=
"order_no"
/>
<
result
property=
"user_code"
column=
"user_code"
/>
<!-- 多對多 -->
<
collection
property=
"goods"
ofType=
"com.xiaoxie.pojo.Goods"
>
<
id
property=
"id"
column=
"id"
/>
<
result
property=
"goods_no"
column=
"goods_no"
/>
</
collection
>
</
resultMap
>
<
select
id=
"selectAllOrderAndGoods"
resultMap=
"OrdersAndGoods"
>
select o.*,g.* from `order` o
left join order_detail d on o.order_no = d.order_no
left join goods g on d.goods_no = g.goods_no
</
select
>
</
mapper
>
新增對應的Dao介面方法
package com.xiaoxie.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.pojo.Order;
@Repository(
"orderDao")
@Mapper
public
interface OrderDao {
List<Order> selectOrderByUserCode(String
user_code);
List<Order> selectAllOrderAndGoods();
//新增的多對多介面方法
}
新增Controller類
OrdersAndGoodsController:
package com.xiaoxie.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import com.xiaoxie.dao.OrderDao;
import com.xiaoxie.pojo.Order;
@Controller(
"ordersAndGoodsController")
@Transactional
public
class OrdersAndGoodsController {
@Autowired
private OrderDao
orderDao;
public
void test() {
List<Order>
orders =
orderDao.selectAllOrderAndGoods();
System.
out.println(
orders);
}
}
在測試類中進行測試
ApplicationContext
context =
new ClassPathXmlApplicationContext(
"spring-config.xml");
OrdersAndGoodsController
ogc
= (OrdersAndGoodsController)
context
.getBean(
"ordersAndGoodsController"
);
ogc.test();
相關文章
- Spring 學習小結Spring
- HexMap學習筆記(九)——地形特徵筆記特徵
- robot framework學習筆記之九-雜記Framework筆記
- java學習小記Java
- MQ學習小記MQ
- Dubbo學習小記
- Spring boot學習(九)Spring boot配置郵件傳送Spring Boot
- spring學習筆記Spring筆記
- Spring 學習筆記Spring筆記
- ES6學習筆記(九)【class】筆記
- STM32學習記錄(九):RTC
- 正則學習小記
- Python學習小記Python
- Ruby/Elixir學習小記
- 042學習小記(1)
- 042學習小記(2)
- PHP 第九周函式學習記錄PHP函式
- 飛機的 PHP 學習筆記九:安全PHP筆記
- ReactNative學習筆記九之TabNavigatorReact筆記
- hive學習筆記之九:基礎UDFHive筆記
- JavaWeb學習筆記——第九天JavaWeb筆記
- Spring學習記錄1Spring
- spring學習筆記(1)Spring筆記
- Spring學習筆記(一)Spring筆記
- Spring 學習筆記(2) Spring BeanSpring筆記Bean
- Spring 學習筆記(3)Spring MVCSpring筆記MVC
- 小墨學習記--微服務微服務
- 微信小程式學習筆記微信小程式筆記
- react小書學習筆記React筆記
- 學習es6小記
- Activiti 學習筆記 小結筆記
- oracle sqr工作學習小記Oracle
- ES[7.6.x]學習筆記(九)搜尋筆記
- Vue學習筆記(九):元件化程式設計Vue筆記元件化程式設計
- iOS學習筆記49 Swift(九)訪問控制iOS筆記Swift
- 《Mastering Delphi 6》學習筆記之九 (轉)AST筆記
- Spring Cloud Eureka 學習記錄SpringCloud
- Spring Security Filter 學習筆記SpringFilter筆記