一、Mybatis入門
1. jdbc程式設計問題總結
1.1 jdbc程式
@Override
public void insertUser(User user){
Connection conn = DBUtil.getConnection();
PreparedStatement stmt = null;
String sql = "insert into sys_user(NAME,ACCT,PWD,CRTIME,UPTIME) values(?a,?c,?d,now(),now())";
try {
stmt = conn.prepareStatement(sql);
stmt.setString(1, user.getName());
stmt.setString(2, user.getAcct());
stmt.setString(3, user.getPwd());
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeAll(conn, stmt, null);
}
}
1.2 jdbc程式設計步驟
- 加載資料庫驅動
- 建立并擷取資料庫連結
- 建立PreparedStatement對象
- 設定Sql語句中的占位符參數
- 通過PreparedStatement執行Sql并擷取結果
- 對Sql執行結果進行解析處理
- 釋放資源(Connection、Preparedstatement、ResultSet)
1.3 jdbc問題總結如下
- 資料庫連結建立、釋放頻繁造成系統資源浪費進而影響系統性能,如果使用資料庫連結池可解決此問題
- Sql語句在代碼中寫死,造成代碼不易維護,實際應用Sql變化的可能較大,Sql變動需要改變java代碼
- 使用PreparedStatement向占位符号傳參數存在寫死,因為Sql語句的where條件不一定,可能多也可能少,修改Sql還要修改代碼,系統不易維護
- 對結果集解析存在寫死(查詢列名),Sql變化導緻解析代碼變化,系統不易維護,如果能将資料庫記錄封裝成pojo對象解析比較友善
2. MyBatis介紹
MyBatis本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation遷移到了google code,并且改名為MyBatis,實質上MyBatis對iBatis進行一些改進
MyBatis是一個優秀的持久層架構,它對jdbc的操作資料庫的過程進行封裝,使開發者隻需要關注 SQL 本身,而不需要花費精力去處理例如注冊驅動、建立Connection、建立Statement、手動設定參數、結果集檢索等jdbc繁雜的過程代碼
Mybatis通過xml或注解的方式将要執行的各種Statement(Statement、PreparedStatemnt、CallableStatement)配置起來,并通過java對象和Statement中的Sql進行映射生成最終執行的Sql語句,最後由MyBatis架構執行Sql并将結果映射成java對象并傳回
3. MyBatis架構
- MyBatis配置檔案mybatis-config.xml(名稱不固定),此檔案作為MyBatis的全局配置檔案,配置了MyBatis的運作環境等資訊。mapper.xml檔案即Sql映射檔案,檔案中配置了操作資料庫的Sql語句。此檔案需要在mybatis-config.xml中加載
- 通過MyBatis環境等配置資訊構造SqlSessionFactory即會話工廠
- 由會話工廠建立SqlSession即會話,操作資料庫需要通過SqlSession進行
- MyBatis底層自定義了Executor執行器接口操作資料庫,Executor接口有兩個實作,一個是基本執行器、一個是緩存執行器
- Mapped Statement也是MyBatis一個底層封裝對象,它包裝了MyBatis配置資訊及Sql映射資訊等。mapper.xml檔案中一個Sql對應一個Mapped Statement對象,Sql的id即是Mapped statement的id
- Mapped Statement對Sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行Sql前将輸入的java對象映射至Sql中,輸入參數映射就是jdbc程式設計中對PreparedStatement設定參數
- Mapped Statement對Sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql後将輸出結果映射至java對象中,輸出結果映射過程相當于jdbc程式設計中對結果的解析處理過程
4. 搭建MyBatis項目
4.1 建立Java項目
MyBatis是一個持久層架構,操作資料庫時使用的。無需建立JavaWEB項目,建立Java項目即可
4.2 導入MyBatis架構jar包
- mybatis-3.4.6.jar為核心jar包,必須引入
- lib目錄下的jar包為工具包,可有可無
- mysql或oracle資料庫的驅動包,必須引入
maven依賴配置
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
4.3 編寫MyBatis中全局配置檔案
作用:配置了資料源、事務等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>
<!-- 配置環境:與資料庫的連接配接資訊
此配置了解即可,後期與spring架構整合之後,此配置會消失
-->
<environments default="mysql">
<environment id="oracle">
<!-- 配置事務:使用jdbc的事務管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置資料源:連接配接資料庫的資訊
type : 表示連接配接是否使用連接配接池,POOLED表示mybatis中自帶的連接配接池
-->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="username" value="tom"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
4.4 編寫實體類
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
//get,set方法省略...
}
4.5 編寫映射檔案
<?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">
<!--
namespace : 命名空間,作用是mapper檔案進行分類管理
注意:如果使用mapper代理的方式進行開發,namespace有特殊的作用
-->
<mapper namespace="emp">
<!-- 在映射檔案中編寫sql語句 -->
<!-- 1.通過主鍵查詢員工資訊 -->
<!--
通過<select>标簽編寫查詢語句
id : 映射檔案中SQL語句的唯一辨別
mybatis會将SQL語句封裝到Mapped Statement對象中,是以此處的id也可以辨別Mapped Statement對象的id
注意:同一個mapper檔案中id不能重複,而且id在mapper代理模式下有着重要作用
parameterType : 輸入參數的類型
sql語句的占位符:#{}
#{empno}:其中empno表示接收輸入的參數值,參數名稱為empno
但是如果參數的類型為簡單類型(基本資料類型+包裝類+字元串類型),參數名稱可以任意指定
resultType : 輸出參數的類型
需要指定輸出資料為Java中的資料類型(實體類的全限定名)
-->
<select id="findEmpById" parameterType="java.lang.Integer" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp where empno=#{abc}
</select>
</mapper>
4.6 加載映射檔案
在MyBatis中全局配置檔案中添加映射檔案位置
<!-- 加載映射檔案的位置 -->
<mappers>
<mapper resource="com/mybatis/entity/Emp.xml"/>
</mappers>
4.7 編寫測試程式
//1.建立讀取全局配置檔案的流
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//2.通過配置檔案流建立會話工廠
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.通過會話工廠建立會話對象(SqlSession)
SqlSession session = factory.openSession();
/*
4.通過會話對象操作資料庫
selectOne(String statementId, Object param)查詢單條資料
參數1:映射檔案中的statementId,命名空間名.statementId
參數2:向sql語句中傳入的資料,注意:傳入的資料類型必須與映射檔案中配置的parameterType保持一緻
傳回值:就是映射檔案中配置的resultType的類型
*/
Emp emp = session.selectOne("emp.findEmpById",8001);
System.out.println(emp);
//5.關閉資源
session.close();
5. 增删改查的基本操作
5.1 查詢操作
mapper檔案:
<!--
查詢到資料傳回多條記錄,每一條封裝在一個實體類對象中,所有的實體類對象封裝在List集合中
resultType :指定的并不是集合的類型,而是單條資料所對應實體類類型
resultType="java.util.List" 錯誤的配置方式
-->
<select id="findEmp" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp order by empno desc
</select>
Java代碼:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
List<Emp> list = session.selectList("emp.findEmp");
for (Emp e : list) {
System.out.println(e);
}
session.close();
5.2 新增操作
mapper檔案:
<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" >
insert into emp(empno,ename,job,mgr,hiredate,sal,comm)
values(#{empno},#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm})
</insert>
Java代碼:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
Emp emp = new Emp();
emp.setEname("tom");
emp.setJob("clrek");
emp.setMgr(1);
emp.setHiredate(new Date());
emp.setSal(6500.0);
emp.setComm(1200.0);
//在mybaits中事務預設需要手動送出
int result = session.insert("emp.insertEmp",emp);
System.out.println(result);
//執行送出的方法
session.commit();
session.close();
插入資料的主鍵傳回:
- select last_insert_id(),表示得到剛insert進去記錄的主鍵值,适用與自增主鍵的資料庫
- select seq_demo.nextval from dual,表示擷取下一個序列生成的值,适用于存在序列的資料庫
- keyProperty:将查詢到主鍵值設定到parameterType指定的對象的哪個屬性
- order:selectKey标簽中Sql語句,相對于insert語句來說的執行順序
- resultType:指定selectKey标簽中Sql語句的結果類型
<!--mysql-->
<selectKey resultType="java.lang.Integer" keyProperty="empno" order="AFTER">
select last_insert_id()
</selectKey>
<!--oracle-->
<selectKey resultType="java.lang.Integer" keyProperty="empno" order="BEFORE">
select seq_demo.nextval from dual
</selectKey>
如果是主鍵自增型資料庫還可以使用:
5.3 修改操作
mapper檔案:
<update id="updateEmp" parameterType="com.mybatis.entity.Emp">
update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm}
where empno=#{empno}
</update>
Java代碼:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
Emp emp = new Emp();
emp.setEmpno(52);
emp.setEname("jerry");
emp.setJob("manager");
emp.setMgr(10);
emp.setHiredate(new Date());
emp.setSal(8500.0);
emp.setComm(1200.0);
int result = session.update("emp.updateEmp",emp);
System.out.println(result);
//執行送出的方法
session.commit();
session.close();
5.4 删除操作
mapper檔案:
<delete id="deleteEmp" parameterType="java.lang.Integer">
delete from emp where empno=#{empno}
</delete>
Java代碼:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
int result = session.delete("emp.deleteEmp",8000);
System.out.println(result);
//執行送出的方法
session.commit();
session.close();
5.5 條件查詢
mapper檔案:
<!--
#{}占位符,需要在Java中将傳入資料的前後拼接%符号
${}Sql語句拼接,在其中隻能寫value
-->
<select id="findEmpByEname" parameterType="java.lang.String" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where ename like #{abc}
</select>
<select id="findEmpByEname2" parameterType="java.lang.String" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where ename like '%${value}%'
</select>
Java代碼:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
List<Emp> list = session.selectList("emp.findEmpByEname", "%tom%");
//List<Emp> list = session.selectList("emp.findEmpByEname", "tom");
for (Emp e : list) {
System.out.println(e);
}
session.close();
5.6 總結
5.6.1 parameterType和resultType
- parameterType:指定輸入參數類型,MyBatis通過ognl從輸入對象中擷取參數值設定在Sql中
- resultType:指定輸出結果類型,MyBatis将Sql查詢結果的一行記錄資料映射為resultType指定類型的對象
5.6.2 #{} 和 ${}
-
#{}表示一個占位符号,#{}接收輸入參數,類型可以是簡單類型、pojo、HashMap
#{}接收簡單類型,#{}中可以寫成value或其它名稱
#{}接收pojo對象值,通過OGNL讀取對象中的屬性值,通過屬性.屬性.屬性…的方式擷取對象屬性值
-
${}表示一個拼接符号,會引用Sql注入,是以不建議使用${}
${}接收輸入參數,類型可以是簡單類型、pojo、HashMap
${}接收簡單類型,${}中隻能寫成value
${}接收pojo對象值,通過OGNL讀取對象中的屬性值,通過屬性.屬性.屬性…的方式擷取對象屬性值
5.6.3 selectOne和selectList
-
selectOne表示查詢出一條記錄進行映射
如果使用selectOne可以實作使用selectList也可以實作(list中隻有一個對象)
-
selectList表示查詢出一個清單(多條記錄)進行映射
如果使用selectList查詢多條記錄,不能使用selectOne
如果使用selectOne報錯:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4
6. MyBatis和Hibernate本質差別和應用場景
-
Hibernate:是一個标準ORM架構(對象關系映射)
入門門檻較高的,不需要程式寫Sql,Sql語句自動生成,對sql語句進行優化、修改比較困難的
應用場景:适用與需求變化不多的中小型項目,比如:背景管理系統,erp、crm、oa…
-
MyBatis:專注是Sql本身,需要程式員自己編寫Sql語句,Sql修改、優化比較友善
MyBatis是一個不完全的ORM架構,雖然程式員自己寫Sql,MyBatis也可以實作映射(輸入映射、輸出映射)
應用場景:适用與需求變化較多的項目,比如:網際網路項目
- 企業進行技術選型,以低成本高回報作為技術選型的原則,根據項目組的技術力量進行選擇
二、MyBatis開發DAO
1. MyBatis API
1.1 SqlSessionFactoryBuilder
SqlSessionFactoryBuilder用于建立SqlSessionFacoty,SqlSessionFacoty一旦建立完成就不需要SqlSessionFactoryBuilder了,因為SqlSession是通過SqlSessionFactory生産,是以可以将SqlSessionFactoryBuilder當成一個工具類使用,最佳使用範圍是方法範圍即方法體内局部變量
1.2 SqlSessionFactory
SqlSessionFactory是一個接口,接口中定義了openSession的不同重載方法,SqlSessionFactory的最佳使用範圍是整個應用運作期間,一旦建立後可以重複使用,通常以單例模式管理SqlSessionFactory
1.3 SqlSession
SqlSession是一個面向使用者(程式員)的接口,其中提供了很多操作資料庫的方法。如:selectOne(傳回單個對象)、selectList(傳回單個或多個對象)、insert、update、delete。
SqlSession的執行個體不能共享使用,它是線程不安全的,每個線程都應該有它自己的SqlSession執行個體,是以最佳的範圍是請求或方法範圍。絕對不能将SqlSession執行個體的引用放在一個類的靜态字段或執行個體字段中。
2. MyBatis工具類
為了簡化MyBatis的開發,可将MyBatis進一步封裝
public class MybatisUtil {
/**
* 不讓使用者在外界建立工具類對象
*/
private MybatisUtil(){}
/**
* 初始化工廠
*/
private static SqlSessionFactory factory;
static {
try {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 擷取SqlSession對象的方法
*/
public static SqlSession openSession(){
return factory.openSession();
}
}
3. 原始DAO開發方式
原始Dao開發方法需要程式員編寫Dao接口和Dao實作類
接口:
public interface DeptDao {
public List<Dept> findDept();
public Dept findDeptById(Integer deptno);
public void insertDept(Dept dept);
public void updateDept(Dept dept);
public void deleteDept(Integer deptno);
}
實作類:
public class DeptDaoImpl implements DeptDao {
@Override
public List<Dept> findDept() {
SqlSession session = MybatisUtil.openSession();
List<Dept> list = session.selectList("dept.findDept");
session.close();
return list;
}
@Override
public Dept findDeptById(Integer deptno) {
SqlSession session = MybatisUtil.openSession();
Dept dept = session.selectOne("dept.findDeptById",deptno);
session.close();
return dept;
}
@Override
public void insertDept(Dept dept) {
SqlSession session = MybatisUtil.openSession();
session.insert("dept.insertDept",dept);
session.commit();
session.close();
}
@Override
public void updateDept(Dept dept) {
SqlSession session = MybatisUtil.openSession();
session.update("dept.updateDept",dept);
session.commit();
session.close();
}
@Override
public void deleteDept(Integer deptno) {
SqlSession session = MybatisUtil.openSession();
session.delete("dept.deleteDept",deptno);
session.commit();
session.close();
}
}
原始DAO開發問題
- dao接口實作類方法中存在大量模闆方法,設想能否将這些代碼提取出來,大大減輕程式員的工作量
- 調用SqlSession方法時将Statement的id寫死了
- 調用SqlSession方法時傳入的變量,由于SqlSession方法使用泛型,即使變量類型傳入錯誤,在編譯階段也不報錯,不利于程式員開發
4. Mapper代理方式
Mapper代理開發方式隻需要程式員編寫Mapper接口(相當于Dao接口),由MyBatis架構根據接口定義建立接口的動态代理對象,代理對象的方法體同上邊Dao接口實作類方法
程式員編寫Mapper接口需要遵循一些開發規範,MyBatis可以自動生成Mapper接口實作類代理對象
開發規範:
- 在mapper.xml中namespace等于Mapper接口的全限定名
- Mapper接口中的方法名和mapper.xml中statement的id一緻
- Mapper接口中的方法輸入參數類型和mapper.xml中parameterType指定的類型一緻
- Mapper接口中的方法傳回值類型和mapper.xml中resultType指定的類型一緻
Mapper接口:
public interface EmpMapper {
public List<Emp> findEmp();
public Emp findEmpByEmpno(Integer empno);
/**
* 增删改方法的傳回值
* 1.void 無傳回值
* 2.int 傳回操作資料庫表的記錄數
* 3.boolean 根據傳回資料庫表影響的記錄數,來判斷是否成功
* 注意:影響的記錄數大于等于1,傳回值為true,否則為false
*/
public void insertEmp(Emp emp);
public void updateEmp(Emp emp);
public void deleteEmp(Integer empno);
}
映射檔案:
<!--namespace : 與Mapper接口的全限定名保持一緻-->
<mapper namespace="com.mybatis.mapper.EmpMapper">
<!--
statementId與Mapper接口的方法名稱保持一緻
parameterType的類型必須與方法的參數類型保持一緻
resultType的類型必須與方法的傳回值類型保持一緻
-->
<select id="findEmpByEmpno" parameterType="java.lang.Integer" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp where empno=#{abc}
</select>
<!-- 2.查詢所有員工 -->
<select id="findEmp" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp order by empno desc
</select>
<!-- 4.新增員工 -->
<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" >
insert into emp(ename,job,mgr,hiredate,sal,comm)
values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm})
</insert>
<!-- 5. 修改員工-->
<update id="updateEmp" parameterType="com.mybatis.entity.Emp">
update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},
sal=#{sal},comm=#{comm} where empno=#{empno}
</update>
<!-- 6. 删除員工-->
<delete id="deleteEmp" parameterType="java.lang.Integer">
delete from emp where empno=#{empno}
</delete>
</mapper>
測試:
SqlSession session = MybatisUtil.openSession();
//通過SqlSession對象獲得到你指定Mapper接口的代理對象(就是接口的實作類對象)
EmpMapper mapper = session.getMapper(EmpMapper.class);
三、mybatis-config.xml
MyBatis的全局配置檔案mybatis-config.xml,配置内容如下:
- properties(屬性)
- settings(全局配置參數)
- typeAliases(類型别名)
- typeHandlers(類型處理器)
- objectFactory(對象工廠)
- plugins(插件)
- environments(環境集合屬性對象)
- environment(環境子屬性對象)
- transactionManager(事務管理)
- dataSource(資料源)
- environment(環境子屬性對象)
- mappers(映射器)
1. properties(屬性)
将資料庫連接配接參數單獨配置在db.properties中,隻需要在mybatis-config.xml中加載db.properties的屬性值。在mybatis-config.xml中就不需要對資料庫連接配接參數寫死
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis
mysql.username=root
mysql.password=123456
在mybatis-config.xml加載屬性檔案:
<!-- 加載外部資源檔案 -->
<properties resource="db.properties">
<!--properties中還可以配置一些屬性-->
<!--<property name="mysql.url" value="jdbc:mysql://localhost:3306/mybatis"/>-->
</properties>
注意: MyBatis将按照下面的順序來加載屬性:
- 在properties标簽體内定義的屬性首先被讀取
- 然後會讀取properties标簽中resource或url加載的屬性,它會覆寫已讀取的同名屬性
- 最後讀取parameterType傳遞的屬性,它會覆寫已讀取的同名屬性
建議:
- 不要在properties标簽體内添加任何屬性值,隻将屬性值定義在properties檔案中
- 在properties檔案中定義屬性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX
2. settings(全局配置參數)
MyBatis架構在運作時可以調整一些運作參數
比如:開啟二級緩存、開啟延遲加載
可配置參數如下:
3. typeAliases(類型别名)
在mapper.xml中,定義很多的statement,statement需要parameterType指定輸入參數的類型、需要resultType指定輸出結果的映射類型。如果在指定類型時輸入類型全路徑,不友善進行開發,可以針對parameterType或resultType指定的類型定義一些别名,在mapper.xml中通過别名定義,友善開發
3.1 MyBatis預設支援别名
别名 | 映射的類型 | 别名 | 映射的類型 |
---|---|---|---|
_byte | byte | byte | java.lang.Byte |
_short | short | short | java.lang.Short |
_int | int | int | java.lang.Integer |
_integer | int | integer | java.lang.Integer |
_long | long | long | java.lang.Long |
_float | float | float | java.lang.Float |
_double | double | double | java.lang.Double |
_boolean | boolean | boolean | java.lang.Boolean |
string | java.lang.String | date | java.util.Date |
map | java.util.Map | hashmap | java.util.HashMap |
list | java.util.List | arraylist | java.util.ArrayList |
object | java.lang.Object |
3.2 自定義别名
單個定義别名:
<typeAliases>
<!--
<typeAlias>單個别名配置
type : Java中類型的全限定名
alias : 自定義别名
-->
<typeAlias type="com.mybatis.entity.Dept" alias="abc"/>
</typeAliases>
<!--在resultType使用的abc為自定義類型别名-->
<select id="findDeptById" parameterType="int" resultType="abc">
select deptno,dname,loc from dept where deptno=#{deptno}
</select>
批量定義别名:
<typeAliases>
<!--
<package>批量别名配置
name : 需要配置别名的實體類所在包的包名
預設别名為該類的類名,其首字母大小均可
-->
<package name="com.mybatis.entity"/>
</typeAliases>
4. typeHandlers(類型處理器)
MyBatis中通過typeHandlers完成jdbc類型和Java類型的轉換,MyBatis自帶的類型處理器基本上滿足日常需求,不需要單獨定義
MyBatis支援類型處理器:
類型處理器 | Java類型 | JDBC類型 |
---|---|---|
BooleanTypeHandler | Boolean,boolean | 任何相容的布爾值 |
ByteTypeHandler | Byte,byte | 任何相容的數字或位元組類型 |
ShortTypeHandler | Short,short | 任何相容的數字或短整型 |
IntegerTypeHandler | Integer,int | 任何相容的數字和整型 |
LongTypeHandler | Long,long | 任何相容的數字或長整型 |
FloatTypeHandler | Float,float | 任何相容的數字或單精度浮點型 |
DoubleTypeHandler | Double,double | 任何相容的數字或雙精度浮點型 |
BigDecimalTypeHandler | BigDecimal | 任何相容的數字或十進制小數類型 |
StringTypeHandler | String | CHAR和VARCHAR類型 |
ClobTypeHandler | String | CLOB和LONGVARCHAR類型 |
NStringTypeHandler | String | NVARCHAR和NCHAR類型 |
NClobTypeHandler | String | NCLOB類型 |
ByteArrayTypeHandler | byte[] | 任何相容的位元組流類型 |
BlobTypeHandler | byte[] | BLOB和LONGVARBINARY類型 |
DateTypeHandler | java.util.Date | TIMESTAMP類型 |
DateOnlyTypeHandler | java.util.Date | DATE類型 |
TimeOnlyTypeHandler | java.util.Date | TIME類型 |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP類型 |
SqlDateTypeHandler | java.sql.Date | DATE類型 |
SqlTimeTypeHandler | java.sql.Time | TIME類型 |
ObjectTypeHandler | 任意 | 其他或未指定類型 |
EnumTypeHandler | Enumeration類型 | VARCHAR-任何相容的字元串類型,作為代碼存儲(而不是索引) |
5. mappers(映射器)
5.1 單個加載映射檔案
通過resource加載單個映射檔案
<mappers>
<!--
<mapper>單個加載映射檔案
resource : 通過相對路徑加載檔案(項目源目錄下的檔案)
url : 通過絕對路徑加載檔案(檔案系統中檔案)
-->
<mapper resource="com/mybatis/mapper/DeptMapper.xml"/>
<mapper resource="com/mybatis/mapper/EmpMapper.xml"/>
</mappers>
通過mapper接口加載單個映射檔案
- 前提:使用的是mapper代理方法
- 遵循規範:需要将Mapper接口類名和mapper.xml映射檔案名稱保持一緻且在一個目錄中
<mappers>
<!--
<mapper>單個加載映射檔案
class : 配置mapper接口的全限定名,通過Java中的Mapper接口來加載映射檔案
-->
<mapper class="com.mybatis.mapper.DeptMapper"/>
<mapper class="com.mybatis.mapper.EmpMapper"/>
</mappers>
5.2 批量加載映射檔案
指定Mapper接口的包名,MyBatis自動掃描包下邊所有Mapper接口進行加載
遵循規範:與mapper接口加載單個映射檔案一緻
<mappers>
<!--
<package>批量加載映射檔案
name : 存放Mapper接口與mapper.xml檔案的包名
-->
<package name="com.mybatis.mapper"/>
</mappers>
四、mapper.xml
mapper.xml映射檔案中定義了操作資料庫的Sql,每個Sql是一個statement,映射檔案是MyBatis的核心
1. parameterType輸入映射
1.1 簡單類型
<select id="findUsersByRealname" parameterType="string" resultType="Users">
select userid,username,password,realname from users where realname like #{realname}
</select>
1.2 實體類或pojo類型
開發中通過實體類或pojo類型傳遞查詢條件,查詢條件是綜合的查詢條件,不僅包括實體類中查詢條件還包括其它的查詢條件,這時可以使用包裝對象傳遞輸入參數
實體類:Users和Pagebean
//實體類
public class Users{
private Integer userid;
private String username;
private String password;
private String realname;
//get,set方法省略...
}
//頁時使用的pojo對象
public class Pagebean {
private int page;
private int pageSize;
private int maxCount;
private int maxPage;
private int offset;
//get,set方法省略...
}
複合實體類:UsersQuery
public class UsersQuery {
private Users users;
private Pagebean pagebean;
//get,set方法省略...
}
映射檔案:
<select id="findUsersByRealnameAndPage" parameterType="UsersQuery" resultType="Users">
select
userid,username,password,realname from users
where
realname like #{users.realname}
order by userid
limit #{pagebean.offset},#{pagebean.pageSize}
</select>
1.3 Map類型
<select id="findUsersWithMap" parameterType="map" resultType="Users">
select
userid,username,password,realname from users
where
realname like #{map_realname}
order by userid
limit #{map_offset},#{map_size}
</select>
1.4 多輸入參數
MyBatis中允許有多個輸入參數,可使用@Param注解來表示
/**
* @Param注解可以實作多個輸入參數
* 每個輸入參數前必須使用@Param注解
* 注解中value屬性的值為擷取此參數值的key
*
* 多參數使用了注解之後,mybatis就将這些注解中value屬性值與參數值存放一個map集合中
* 其中value屬性值為map集合的key
* 參數值為map集合value
*
* 使用此種方法可以省略paramterType的配置
*/
public Users login(@Param(value = "uname") String username, @Param("pwd") String password);
這種做法類似與Map類型的輸入參數,其中@Param注解的value屬性值為Map的key,在映射檔案中通過ognl可擷取對應的value,并且parameterType可以不指定類型
<select id="login" resultType="Users">
select userid,username,password,realname from users
where username=#{uname} and password=#{pwd}
</select>
2. resultType輸出映射
2.1 簡單類型
查詢出來的結果集隻有一行且一列,可以使用簡單類型進行輸出映射
<select id="findUsersCount" resultType="int">
select count(*) from users
</select>
2.2 實體類對象和清單
不管是輸出的實體類是單個對象還是一個清單(list中包括實體類對象),在mapper.xml中resultType指定的類型是一樣的
在原始Dao的方式中,通過selectOne和selectList方法來區分傳回值為單個對象或集合清單,而在mapper代理中,則通過接口中定義的方法傳回值來區分
public Users findUsersByUserid(Integer userid);
public List<Users> findUsers();
<select id="findUsersByUserid" parameterType="int" resultType="Users">
select userid,username,password,realname from users where userid=#{userid}
</select>
<select id="findUsers" resultType="Users">
select userid,username,password,realname from users order by userid
</select>
2.3 resultMap
- resultType可以指定将查詢結果映射為實體類,但需要實體類的屬性名和Sql查詢的列名一緻方可映射成功
- 如果Sql查詢字段名和實體類的屬性名不一緻,可以通過resultMap将字段名和屬性名作一個對應關系,resultMap實質上還會将查詢結果映射到實體類對象中
- resultMap可以實作将查詢結果映射為複合型的實體類,比如在查詢結果映射對象中包括實體類和list實作一對一查詢和一對多查詢
定義resultMap
<!--
resultType : 自動映射
resultMap : 手動映射
屬性解析:
type : 對應Java中實體類的類型,可以使用全限定名也是使用類型别名
id : <resultMap>标簽的唯一辨別,在<select>的resultMap屬性中使用
子标簽:
<id /> 配置對應表中的主鍵
<result /> 配置對應表中的普通字段
property : 實體類中的屬性名
column : 表或結果集中的字段名
javaType : 屬性類型
jdbcType : 字段類型
其中javaType與jdbcType可不配置由mybaits自動識别
-->
<resultMap id="usersResultMap" type="Users">
<id property="userid" column="id"/>
<result property="username" column="uname"/>
<result property="password" column="pwd"/>
<result property="realname" column="rname"/>
</resultMap>
使用resultMap作為statement的輸出映射類型
<select id="findUsersWithResultMap" resultMap="usersResultMap">
select userid id,username uname,password pwd,realname rname from users
</select>
3. 動态Sql
3.1 什麼是動态Sql
動态Sql是指MyBatis核心對Sql語句進行靈活操作,通過表達式進行判斷,對Sql進行靈活拼接、組裝
3.2 if标簽
将實體類不為空的屬性作為where條件
<select id="findEmpUseIf" parameterType="map" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where 1=1
<!--test:判斷條件,條件成立if标簽中的Sql語句拼接-->
<if test="ename!=null and ename!=''">
and ename like #{ename}
</if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
</if>
<if test="deptno!=null and deptno!=0">
and deptno=#{deptno}
</if>
</select>
3.2 where标簽
where标簽中包含的任意if條件如果成立,它就插入一個where關鍵字。此外,如果标簽傳回的内容是以AND 或OR 開頭的,則它會自動剔除掉
<select id="findEmpUseWhere" parameterType="map" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
<where>
<if test="ename!=null and ename!=''">
and ename like #{ename}
</if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
</if>
<if test="deptno!=null and deptno!=0">
and deptno=#{deptno}
</if>
</where>
</select>
3.3 set标簽
當在update語句中使用if标簽時,如果前面的if沒有執行,則或導緻逗号多餘錯誤。使用set标簽可以将動态的配置SET關鍵字,和剔除追加到條件末尾的任何不相關的逗号
注意:如果set包含的内容為空的話則會出錯
<update id="updateEmpUseSet" parameterType="Emp">
update emp
<set>
<if test="ename!=null">
ename=#{ename},
</if>
<if test="job!=null">
job=#{job},
</if>
<if test="mgr!=null">
mgr=#{mgr},
</if>
<if test="sal!=null">
sal=#{sal},
</if>
<if test="comm!=null">
comm=#{comm},
</if>
<if test="hiredate!=null">
hiredate=#{hiredate},
</if>
</set>
where empno=#{empno}
</update>
3.4 trim标簽
trim标簽屬性解析:
- prefix:字首,包含内容前加上某些字元
- suffix:字尾,包含内容後加上某些字元
- prefixOverrides:剔除包含内容前的某些字元
- suffixOverrides:剔除包含内容後的某些字元
trim來代替where标簽的功能
<select id="findEmpUseTrim" parameterType="Emp" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
<trim prefix="where" prefixOverrides="and|or">
<if test="ename!=null">
and ename like #{ename}
</if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
</if>
<if test="job!=null">
and job=#{job}
</if>
</trim>
</select>
trim來代替set标簽的功能
<update id="updateEmpUseTrim" parameterType="Emp">
update emp
<trim prefix="set" suffixOverrides=",">
<if test="ename!=null">
ename=#{ename},
</if>
<if test="job!=null">
job=#{job},
</if>
<if test="mgr!=null">
mgr=#{mgr},
</if>
<if test="sal!=null">
sal=#{sal},
</if>
<if test="comm!=null">
comm=#{comm},
</if>
<if test="hiredate!=null">
hiredate=#{hiredate},
</if>
</trim>
where empno=#{empno}
</update>
trim實作insert語句
<insert id="insertEmpUseTrim" parameterType="Emp">
insert into emp
<trim suffix="(" prefix=")" prefixOverrides=",">
<if test="ename!=null">
ename,
</if>
<if test="job!=null">
job,
</if>
<if test="mgr!=null">
mgr,
</if>
<if test="hiredate!=null">
hiredate,
</if>
<if test="sal!=null">
sal,
</if>
<if test="comm!=null">
comm,
</if>
</trim>
<trim prefix=" values(" suffix=")" suffixOverrides=",">
<if test="ename!=null">
#{ename},
</if>
<if test="job!=null">
#{job},
</if>
<if test="mgr!=null">
#{mgr},
</if>
<if test="hiredate!=null">
#{hiredate},
</if>
<if test="sal!=null">
#{sal},
</if>
<if test="comm!=null">
#{comm},
</if>
</trim>
</insert>
3.5 foreach标簽
- 向Sql傳遞數組或list,MyBatis使用foreach解析
- Sql隻接收一個數組參數,這時sql解析參數的名稱MyBatis固定為array
- Sql隻接收一個List參數,這時sql解析參數的名稱MyBatis固定為list
- 如果是通過一個實體類或pojo的屬性傳遞到Sql的數組或list,則參數的名稱為實體類或pojo中的屬性名
屬性解析:
- index:為數組的下标
- item:每個周遊生成對象中
- open:開始周遊時拼接的串
- close:結束周遊時拼接的串
- separator:周遊的兩個對象中需要拼接的串
public void deleteEmpUseForeachArray(int[] empnos);
public List<Emp> findEmpUseForeachList(List<Integer> empnos);
public List<Emp> findEmpUseForeachPojo(EmpQuery query);
<delete id="deleteEmpUseForeachArray" parameterType="int">
delete from emp where empno in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<select id="findEmpUseForeachList" parameterType="int" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where empno in
<foreach collection="list" open="(" close=")" separator="," item="empno">
#{empno}
</foreach>
</select>
<select id="findEmpUseForeachPojo" parameterType="EmpQuery" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where deptno in
<foreach collection="deptnos" open="(" close=")" separator="," item="deptno">
#{deptno}
</foreach>
</select>
3.6 choose,when,otherwise标簽
if-else-if判斷
<select id="">
select...
<choose>
<when test="">
</when>
<when test="">
</when>
<otherwise>
</otherwise>
</choose>
</select>
3.7 Sql片段
将實作的動态Sql判斷代碼塊抽取出來,組成一個Sql片段,其它的statement中就可以引用Sql片段,友善程式員進行開發
注意:在sql片段中不要包括where标簽
<select id="findEmpUseSql" parameterType="map" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
<where>
<!-- 引入sql片段 -->
<include refid="empSql"/>
</where>
</select>
<sql id="empSql">
<if test="ename!=null">
and ename like #{ename}
</if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
</if>
<if test="deptno!=null and deptno!=0">
and deptno=#{deptno}
</if>
</sql>
五、關聯查詢
1. 資料模型分析
表功能介紹
- 使用者表:記錄使用者的基本資訊
- 訂單表:記錄使用者所建立的訂單(購買商品的訂單)
- 訂單詳情表:記錄訂單的詳細資訊即購買商品的資訊
- 商品表:記錄商品的基本資訊
表與表之間的業務關系
-
使用者表和訂單表:
使用者表---->訂單表:一個使用者可以建立多個訂單,一對多關系
訂單表---->使用者表:一個訂單隻由一個使用者建立,一對一關系
-
訂單表和訂單詳情表:
訂單表---->訂單詳情表:一個訂單可以包含多個訂單詳情,因為一個訂單可以購買多個商品,每個商品的購買資訊在訂單詳情表中記錄,一對多關系
訂單詳情表----->訂單表:一個訂單詳情隻能包括在一個訂單中,一對一關系
-
訂單詳情表和商品表:
訂單詳情表---->商品表:一個訂單詳情隻對應一個商品資訊,一對一關系
商品表---->訂單詳情表:一個商品可以包括在多個訂單詳情,一對多關系
-
訂單表和商品表:
訂單表<---->商品表:一個訂單中包含多個商品,一個商品可以添加在多個訂單中,兩者是通過訂單詳情表建立關系,多對多關系
2. 一對一查詢
2.1 resultType
2.1.1 Sql語句
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
2.1.2 實體類
public class Users {
private Integer userid;
private String username;
private String password;
private String realname;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
//get,set方法省略...
}
原始的Orders類不能映射全部字段,需要新建立的實體類,建立一個包括查詢字段較多的實體類
OrdersUsers中包含了Orders以及Users需要查詢的屬性
public class OrdersUsers {
/**
* 對應orders表中的字段
*/
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 對象users表中的字段
*/
private Integer userid;
private String username;
private String password;
private String realname;
}
2.1.3 Mapper接口
2.1.4 mapper.xml
<select id="findOrdersUseResultType" resultType="OrdersUsers">
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
</select>
2.1.5 測試
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<OrdersUsers> list = mapper.findOrdersUseResultType();
for (OrdersUsers ou : list) {
System.out.println(ou);
}
session.close();
2.2 resultMap
2.2.1 Sql語句
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
2.2.2 實體類
在Orders類中加入Users屬性,Users屬性用于存儲關聯查詢的使用者資訊,因為訂單關聯查詢使用者是一對一關系,是以這裡使用單個Users對象存儲關聯查詢的使用者資訊
public class Users {
private Integer userid;
private String username;
private String password;
private String realname;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 一對一/多對一依賴關系屬性
*/
private Users users;
//get,set方法省略...
}
2.2.3 Mapper接口
2.2.4 mapper.xml
<resultMap id="ordersUsersResultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
<association property="users" javaType="Users">
<id column="userid" property="userid"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="realname" property="realname"/>
</association>
</resultMap>
<select id="findOrdersUseResultMap" resultMap="ordersUsersResultMap">
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
</select>
2.2.5 測試
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersUseResultMap();
for (Orders o : list) {
System.out.println(o);
}
session.close();
2.3 resultType和resultMap實作一對一查詢小結
- resultType:使用resultType實作較為簡單,如果實體類中沒有包括查詢出來的列名,需要增加列名對應的屬性,即可完成映射。如果查詢結果沒有特殊要求,建議使用resultType
- resultMap:需要單獨定義resultMap,實作有點麻煩,如果對查詢結果有特殊的要求,使用resultMap可以完成将關聯查詢映射到實體類的屬性中
- resultMap可以實作延遲加載,resultType無法實作延遲加載
3. 一對多查詢
3.1 Sql語句
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id
FROM
orders o,ordersdetail d
WHERE
o.id=d.orders_id
3.2 實體類
在Order類中加入List details屬性,details屬性用于存儲關聯查詢的訂單詳情,因為訂單關聯查詢訂單詳情是一對多關系,是以這裡使用集合對象存儲關聯查詢的訂單詳情資訊
public class OrdersDetail {
private Integer id;
private Integer amount;
private Integer goods_id;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 一對多,多對多依賴關系屬性
*/
private List<OrdersDetail> details;
//get,set方法省略...
}
3.2 Mapper接口
3.3 mapper.xml
<resultMap id="ordersAndDetailResultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
<!--
映射依賴關系屬性
<collection>用于描述一對多或多對多關系屬性
property : 關系屬性的名稱
OrdersDetail : 關系屬性集合中存放的實體類類型
-->
<collection property="details" ofType="OrdersDetail">
<id column="detailid" property="id"/>
<result column="amount" property="amount"/>
<result column="goods_id" property="goods_id"/>
</collection>
</resultMap>
<select id="findOrdersAndOrdersDetail" resultMap="ordersAndDetailResultMap">
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id
FROM
orders o,ordersdetail d
WHERE
o.id=d.orders_id
</select>
3.4 測試
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersAndOrdersDetail();
for (Orders orders : list) {
System.out.println(orders);
}
session.close();
4. 多對多查詢
4.1 訂單與商品之間的多對多關系
4.1.1 Sql語句
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id,gname,descr,price
FROM
orders o,ordersdetail d,goods g
WHERE
o.id=d.orders_id
AND
d.goods_id=g.id
4.1.2 實體類
将Orderdetail類中Integer goods_id屬性修改為Goods goods屬性,goods屬性用于存儲關聯查詢的商品資訊。訂單與訂單詳情是一對多關系,訂單詳情與商品是一對一關系,反之商品與訂單詳情是一對多關系,訂單詳情與訂單是一對一關系,是以訂單與商品之前為多對多關系
public class Goods {
private Integer id;
private String gname;
private String descr;
private Double price;
//get,set方法省略...
}
public class OrdersDetail {
private Integer id;
private Integer amount;
/**
* 一對一依賴關系屬性
*/
private Goods goods;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 一對多,多對多依賴關系屬性
*/
private List<OrdersDetail> details;
//get,set方法省略...
}
4.1.3 Mapper接口
4.1.4 mapper.xml
<resultMap id="ordersAndGoodsResultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
<collection property="details" ofType="OrdersDetail">
<id column="detailid" property="id"/>
<result column="amount" property="amount"/>
<association property="goods" javaType="Goods">
<id column="goods_id" property="id"/>
<result column="gname" property="gname"/>
<result column="descr" property="descr"/>
<result column="price" property="price"/>
</association>
</collection>
</resultMap>
<select id="findOrdersAndGoods" resultMap="ordersAndGoodsResultMap">
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id,gname,descr,price
FROM
orders o,ordersdetail d,goods g
WHERE
o.id=d.orders_id
AND
d.goods_id=g.id
</select>
4.1.5 測試
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersAndGoods();
for (Orders orders : list) {
System.out.println(orders);
}
session.close();
4.2 學生與課程之間的多對多關系
4.2.1 Sql語句
SELECT
s.id,name,gender,major,course_id,cname
FROM
student s,student_course sc,course c
WHERE
s.id=sc.student_id
AND
sc.course_id=c.id
4.2.2 實體類
public class Course {
private Integer id;
private String cname;
//get,set方法省略...
}
public class Student {
private Integer id;
private String name;
private String gender;
private String major;
/**
* 多對多的依賴關系屬性
*/
private List<Course> courses;
//get,set方法省略...
}
4.2.3 Mapper接口
4.2.4 mapper.xml
<resultMap id="studentAndCourseResultMap" type="Student">
<id column="id" property="id"/>
<result column="NAME" property="name"/>
<result column="gender" property="gender"/>
<result column="major" property="major"/>
<collection property="courses" ofType="Course">
<id column="course_id" property="id"/>
<result column="cname" property="cname"/>
</collection>
</resultMap>
<select id="findStudent" resultMap="studentAndCourseResultMap">
SELECT
s.id,name,gender,major,course_id,cname
FROM
student s,student_course sc,course c
WHERE
s.id=sc.student_id
AND
sc.course_id=c.id
</select>
4.2.5 測試
SqlSession session = MybatisUtil.openSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.findStudent();
for (Student student : list) {
System.out.println(student);
}
session.close();
5. 關聯查詢總結
5.1 resultType
作用:将查詢結果按照Sql列名與實體類屬性名一緻性映射到實體類對象中
場合:常見一些明細記錄的展示,比如使用者購買商品明細,将關聯查詢資訊全部展示在頁面時,此時可直接使用resultType将每一條記錄映射到實體類中,在前端頁面周遊list(list中是實體類)即可
5.2 resultMap
使用association和collection完成一對一和一對多進階映射(對結果有特殊的映射要求)
5.2.1 association
作用:将關聯查詢資訊映射到一個實體類對象中
場合:為了友善查詢關聯資訊可以使用association将關聯資訊映射為目前對象的一個屬性,比如:查詢訂單以及關聯使用者資訊
5.2.2 collection
作用:将關聯查詢資訊映射到一個list集合中
場合:為了友善查詢周遊關聯資訊可以使用collection将關聯資訊映射到list集合中,比如:查詢使用者權限範圍子產品及子產品下的菜單,可使用collection将子產品映射到子產品list中,将菜單清單映射到子產品對象的菜單list屬性中,這樣的作的目的也是友善對查詢結果集進行周遊查詢。如果使用resultType無法将查詢結果映射到list集合中
5.2.3 resultMap的繼承
resultMap标簽可以通過extends屬性來繼承一個已有的或公共的resultMap,避免重複配置的出現,減少配置量。例子如下:
<!-- 父resultMap标簽-->
<resultMap id="ordersRusultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
</resultMap>
<!-- 繼承父resultMap标簽中的配置,避免重複配置 -->
<resultMap id="ordersUsersResultMap" type="Orders" extends="ordersRusultMap">
<association property="users" javaType="Users">
<id column="userid" property="userid"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="realname" property="realname"/>
</association>
</resultMap>
六、延遲加載
1. 什麼是延遲加載
- 需要查詢關聯資訊時,使用MyBatis延遲加載特性可有效的減少資料庫壓力,首次查詢隻查詢主要資訊,關聯資訊等使用者擷取時再加載
- resultMap可以實作進階映射(使用association、collection實作一對一及一對多映射),association、collection具備延遲加載功能
2. 打開延遲加載開關
在MyBatis核心配置檔案中配置:lazyLoadingEnabled、aggressiveLazyLoading
設定項 | 描述 | 允許值 | 預設值 |
---|---|---|---|
lazyLoadingEnabled | 全局性設定懶加載。如果設為‘false’,則所有相關聯的都會被初始化加載 | true \ false | false |
aggressiveLazyLoading | 當設定為‘true’的時候,懶加載的對象可能被任何懶屬性全部加載。否則,每個屬性都按需加載 | true \ false | true |
<!-- 全局參數設定 -->
<settings>
<!-- 開啟延遲加載 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
3. 使用association實作延遲加載
查詢員工以及相關聯的部門資訊
3.1 Mapper接口
3.2 mapper.xml
查詢員工資訊
<select id="findEmp" resultMap="empResultMap">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
</select>
查詢關聯的部門資訊
通過上邊查詢到的員工資訊中deptno外鍵去關聯查詢部門資訊,是以需要定義一個根據ID查詢部門的語句
<select id="findDeptByDeptno" parameterType="int" resultType="Dept">
select deptno,dname,loc from dept where deptno=#{deptno}
</select>
resultMap配置
<resultMap id="empResultMap" type="Emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<!-- 關系屬性描述-->
<!--
<association>實作延遲加載
select : 執行延遲加載時關聯資料查詢的sql對應的statementId
1.執行的關聯查詢語句在同一mapper檔案中,可以直接使用statementId
2.執行的關聯查詢語句在不同的mapper檔案中,namespace.statementId
column : 在執行關聯查詢時,使用到主表的一個字段名稱(外鍵字段的名稱)
-->
<association property="dept" javaType="Dept" select="com.mybatis.mapper.DeptMapper.findDeptByDeptno" column="deptno">
</association>
</resultMap>
4. 使用collection實作延遲加載
4.1 Mapper接口
4.2 mapper.xml
查詢部門資訊
<select id="findDept" resultMap="deptResultMap">
select deptno,dname,loc from dept
</select>
查詢關聯的員工詳情資訊
通過查詢到的部門資訊中deptno去關聯查詢員工詳情,是以需要定義一個根據部門ID查詢員工詳情的語句
<select id="findEmpByDeptno" parameterType="int" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where deptno=#{deptno}
</select>
resultMap配置
<resultMap id="deptResultMap" type="Dept">
<id column="deptno" property="deptno"/>
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
<collection property="empList" ofType="Emp" select="com.mybatis.mapper.EmpMapper.findEmpByDeptno" column="deptno"/>
</resultMap>