Mybatis映射文件
增刪改查
簡單地增刪改查
<select?id="selectUser"?resultType="User">
????select?*?from?`user`?where?id?=?#{id}
</select>
<insert?id="addUser">
????insert?into?`user`?(`name`,account)?values?(#{name},#{account})
</insert>
<update?id="updateUser">
????update?`user`?set?`name`?=?#{name},?account?=?#{account}?where?id?=?#{id}
</update>
<delete?id="deleteUser">
????delete?from?`user`?where?id?=?#{id}
</delete>
使用factory.openSession()得到的sqlSession默認不會自動提交,需要手動的提交事務
使用factory.openSession(true)得到的sqlSession自動提交
select詳細屬性
查詢語句是Mybatis中用的最多的
<!--?
?id?命名空間的唯一標識,一般為方法名,命名空間+id必須唯一
??parameterType???入參類型,該參數可選,mybatis通過類型處理器TypeHandler推斷出具體傳入的參數
??resultType??????返回結果的類全限定名或別名(如果為集合,應設置為集合包含的類型,而不是集合本身的類型)
?resultMap???????結果映射(resultType和ResultMap只能同時使用一個)
??flushCache??????設置為true,該語句被調用后清空本地緩存和二級緩存,默認false
??useCache????????設置為true,該語句結果被二級緩存緩存????select語句默認true
?timeout?????????等待數據庫返回的超時時間
??fetchSize???????批量返回的行數
??statementType???可選STATEMENT/PREPARED/CALLABLE??分別對應于Statement/PreparedStatement/CallaleStatement???默認PREPARED
??resultSetType???FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE/DEFAULT
??databaseId??????數據庫廠商id
??resultOrdered???只針對于嵌套結果select語句:如果為true,將會假設包含了嵌套結果集或是分組,當返回一個主結果行時,就不會產生對前面結果集的引用??確保了在獲取嵌套的結果集的時候不至于導致內存不足?默認false
??resultSets??????針對于多結果集的情況。將列出語句執行后返回的結果集并賦予每個結果集一個名稱,多個名稱逗號隔開
sql語句中使用#{id}?則表示使用的是PreparedStatement預處理語句,此時mybatis會創建一個PreparedStatement,在sql中會使用?來標識??select?*?from?`user`?where?id?=???,然后在進行賦值??ps.setInt(1,id)
-->
<select
??id="selectUser"????
??parameterType="int"
??resultType="hashmap"
??resultMap="personResultMap"
??flushCache="false"
??useCache="true"
??timeout="10"
??fetchSize="256"
??statementType="PREPARED"
??resultSetType="FORWARD_ONLY">
??select?*?from?`user`?where?id?=?#{id}
</select>
insert/update/delete詳細屬性
<!--?
?id?命名空間的唯一標識,一般為方法名
??parameterType???入參類型,該參數可選,mybatis通過類型處理器TypeHandler推斷出具體傳入的參數
??flushCache??????設置為true,該語句被調用后清空本地緩存和二級緩存,?insert、update、delete語句默認false
?timeout?????????等待數據庫返回的超時時間
??statementType???可選STATEMENT/PREPARED/CALLABLE??分別對應于Statement/PreparedStatement/CallaleStatement???默認PREPARED
??databaseId??????數據庫廠商id
??useGeneratedKeys??使用JDBC的getGeneratedKeys方法來獲取數據庫生成的主鍵,僅對insert有用,默認false
??keyProperty?????指定對象的主鍵屬性,將getGeneratedKeys的返回值賦給該屬性,如果生成列不止一個,使用逗號隔開,僅對insert有用
??keyColumn???????指定生成鍵值在數據庫中的列名,如果生成列不止一個,用逗號隔開
-->
<insert
??id="insertAuthor"
??parameterType="domain.blog.Author"
??flushCache="true"
??statementType="PREPARED"
??keyProperty=""
??keyColumn=""
??useGeneratedKeys=""
??timeout="20">
??
??<update
??id="updateAuthor"
??parameterType="domain.blog.Author"
??flushCache="true"
??statementType="PREPARED"
??timeout="20">
????
??<delete
??id="deleteAuthor"
??parameterType="domain.blog.Author"
??flushCache="true"
??statementType="PREPARED"
??timeout="20">
插入擴展
獲取自增id
默認情況下,插入數據后無法獲取自增屬性的主鍵id
<!--
????自增主鍵,mybatis利用statement.getGeneratedKeys()來獲取
????useGeneratedKeys="true"?使用自增主鍵獲取主鍵值策略
????keyProperty??指定對應的主鍵屬性,mybatis獲取到主鍵值后,將值賦給該屬性
?-->
<insert?id="addUserReturnGeneratedKey"?useGeneratedKeys="true"?keyProperty="id">
????insert?into?`user`?(`name`,account)?values?(#{name},#{account})
</insert>
不支持自增主鍵的方式
<!--
????不支持自增主鍵的方式
?-->
<insert?id="addUserReturnGeneratedKey"?databaseId="oracle">
????<!--?使用selectKey來獲取主鍵序列值
????????keyProperty?指定對應的主鍵屬性,mybatis獲取到主鍵值后,將值賦給該屬性
????????order?before表示當前sql在插入sql之前
??????????????after表示當前sql在插入sql之后
????????resultType?查出來的數據返回值類型
?????-->
????<selectKey?keyProperty="id"?order="BEFORE"?resultType="Integer">
????????select?user_seq.nextval?from?dual
????</selectKey>
????insert?into?`user`?(id,`name`,account)?values?(#{id},#{name},#{account})
</insert>
參數處理
普通的數據類型
User?selectUserByIdAndName(@Param("id")?int?id,@Param("name")?String?name);
<!--?測試多個參數取值
????mybatis默認將多個參數封裝為一個map
?????????map的key為param1~paramN
?????????map的value為傳入的參數值
?????????#{}使用的是map的key來取值
?????可以使用命名參數來明確指定封裝成map時的key?@Param("id")?@Param("name")
????????map的key為@Param注解指定的名稱
????????map的value為傳入的參數值
?-->
<select?id="selectUserByIdAndName"?resultType="User">
????select?*?from?user?where?id?=?#{id}?and?name?=?#{name}
</select>
自定義的java對象數據類型
對于很多入參的情況,不希望方法的入參那么多,而且需要指定@Param參數,可以將這些入參封裝為一個對象.
對于對象,可以直接使用字段來進行獲取
User?selectUserByCondition(User?user);
<select?id="selectUserByCondition"?resultType="User">
????????select?*?from?user
????????<where>
????????????<if?test="id?!=?null?and?id?!=?0">
??????????????and?id?=?#{id}
????????????</if>
????????????<if?test="name?!=?null">
????????????????and?name?=?#{name}
????????????</if>
????????????<if?test="account?!=?null?and?account?!=?0">
????????????????and?account?=?#{account}
????????????</if>
????????</where>
????</select>
集合屬性
對于List,mybatis會映射為list,可以通過list來獲取集合中的值
List<User>?selectByIds(List<Integer>?ids);
<select?id="selectByIds"?resultType="User">
????select?*?from?user
????<where>
????????id?in
????????<foreach?collection="list"?index="index"?item="item"?open="("?separator=","?close=")">
????????????#{item}
????????</foreach>
????</where>
</select>
結果映射
resultMap和resultType都是作為結果集返回映射
ResultType
使用map
很多情況下使用map作為返回是可以支持的,但是map不是一個很好的領域模型,在獲取到數據庫結果之后,還需要再去人工的從map中取值給業務需要的字段去賦值,是一件痛苦而繁瑣的事情
<select?id="selectUser"?resultType="map">
??select?*?from?user?where?id?=?#{id}
</select>
使用PO
使用PO進行接收結果集時,考慮到數據庫中的列名可能與po中的字段名不一致,需要為每個字段起別名,sql寫起來就變長了很多
<select?id="selectUser"?resultType="User">
??select?user_id?as?id,user_name?as?userName,
??from?user?where?id?=?#{id}
</select>
ResultMap
由于在使用ResultType時有一些的問題,而且ResultType對于一些復雜的查詢結果來說處理起來也并不友好,ResultMap自定義映射的好處就凸顯出來了。
<resultMap?id="user"?type="com.zhanghe.study.mybatis.model.User">
????<!--
?????????id定義主鍵
?????????????column?指定數據庫的列名
?????????????property?指定java的屬性名
???????javaType?配置java的類型
???????jdbcType?配置數據庫類型
?????????????typeHandler??類型處理器
?????-->
????<id?column="id"?property="id"/>
????<!--?普通的列?-->
????<result?column="name"?property="name"/>
????<result?column="account"?property="account"/>
</resultMap>
?<select?id="selectUserReturnResultMap"?resultMap="user">
?????select?*?from?`user`?where?id?=?#{id}
?</select>
resultMap是支持繼承的
????<resultMap?id="base"?type="com.zhanghe.study.mybatis.model.User">
????????<id?column="id"?property="id"/>
????????<result?column="name"?property="name"/>
????</resultMap>
????<resultMap?id="user01"?type="com.zhanghe.study.mybatis.model.User"?extends="base">
????????
????????<result?column="account"?property="account"/>
????</resultMap>
關聯查詢一對一
association代表一對一關系
public?class?Employee?{
????private?Integer?id;
????private?String?name;
????private?double?salary;
????private?Department?department;
}
public?class?Department?{
????private?Integer?id;
????private?String?name;
}
級聯屬性封裝
<!--?級聯查詢?-->
<resultMap?id="emp1"?type="com.zhanghe.study.mybatis.model.Employee">
????<id?column="id"?property="id"/>
????<result?column="name"?property="name"/>
????<result?column="salary"?property="salary"/>
???<!--?使用屬性.屬性來獲取?-->
????<result?column="did"?property="department.id"/>
????<result?column="dname"?property="department.name"/>
</resultMap>
<select?id="getEmpAndDep"?resultMap="emp1">
????select?emp.id?id,emp.name?name,emp.salary?salary,emp.dep_id?did,dep.name?dname?from?employee?emp?join?department?dep?on??emp.dep_id?=?dep.id
????where?emp.id?=?#{id}
</select>
使用association進行join查詢
<resultMap?id="emp2"?type="com.zhanghe.study.mybatis.model.Employee">
????<id?column="id"?property="id"/>
????<result?column="name"?property="name"/>
????<result?column="salary"?property="salary"/>
????<!--?指定該字段的類型?-->
????<association?property="department"?javaType="com.zhanghe.study.mybatis.model.Department">
????????<id?column="did"?property="id"/>
????????<result?column="dname"?property="name"/>
????</association>
</resultMap>
<select?id="getEmpAndDep"?resultMap="emp2">
????????select?emp.id?id,emp.name?name,emp.salary?salary,emp.dep_id?did,dep.name?dname?from?employee?emp?join?department?dep?on??emp.dep_id?=?dep.id
????????where?emp.id?=?#{id}
</select>
使用association進行分步查詢
使用分步查詢會執行多條sql語句,先查詢出主表,之后將關聯列作為條件去通過select來查詢子表信息
EmployeeMapper的映射文件
<resultMap?id="emp3"?type="com.zhanghe.study.mybatis.model.Employee">
????<id?column="id"?property="id"/>
????<result?column="name"?property="name"/>
????<result?column="salary"?property="salary"/>
????<!--?select?當前屬性使用select調用的方法
?????????column?指定將那一列的值作為參數傳入select語句
????????-->
????<association?property="department"?column="dep_id"
?????????????????select="com.zhanghe.study.mybatis.mapper.DepartmentMapper.selectDepById">
????????<id?column="did"?property="id"/>
????????<result?column="dname"?property="name"/>
????</association>
</resultMap>
<select?id="getEmpAndDep"?resultMap="emp3">
???select?*?from?employee?where?id?=?#{id}
</select>
DepartmentMapper的映射文件
<resultMap?id="dep"?type="com.zhanghe.study.mybatis.model.Department">
????<id?column="id"?property="id"/>
????<result?column="name"?property="name"/>
</resultMap>
<select?id="selectDepById"?resultMap="dep">
????select?*?from?department?where?id?=?#{id}
</select>
分步查詢延遲加載
在使用子表信息的時候在進行查詢
在全局配置中開啟延遲加載
<settings>
??<setting?name="logImpl"?value="STDOUT_LOGGING"/>
??<!--?延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。?特定關聯關系中可通過設置?fetchType?屬性來覆蓋該項的開關狀態。?-->
??<setting?name="lazyLoadingEnabled"?value="true"/>
??<!--?開啟時,任一方法的調用都會加載該對象的所有延遲加載屬性。?否則,每個延遲加載屬性會按需加載?-->
??<setting?name="aggressiveLazyLoading"?value="false"/>
</settings>
關聯查詢一對多
使用collection標簽代表一對多關系
DepartmentMapper的映射文件
<resultMap?id="dep1"?type="com.zhanghe.study.mybatis.model.Department">
??<id?column="id"?property="id"/>
??<result?column="name"?property="name"/>
??<!--?select?當前屬性使用select調用的方法
?????????column?指定將那一列的值作為參數傳入select語句(如果需要多個條件使用{key1=value1,key2=value2})
????????-->
??<collection?property="employeeList"?select="com.zhanghe.study.mybatis.mapper.EmployeeMapper.getEmployeeByDid"
??????????????column="id">
????<id?column="id"?property="id"/>
????<result?column="name"?property="name"/>
????<result?column="salary"?property="salary"/>
????<result?column="did"?property="department.id"/>
??</collection>
</resultMap>
<select?id="getDepAndEmps"?resultMap="dep1">
????select?*?from?department?where?id?=?#{id}
</select>
EmployeeMapper的映射文件
<resultMap?id="emp"?type="com.zhanghe.study.mybatis.model.Employee">
?<id?column="id"?property="id"/>
?<result?column="name"?property="name"/>
?<result?column="salary"?property="salary"/>
</resultMap>
<select?id="getEmployeeByDid"?resultMap="emp">
????select?*?from?employee?where?dep_id?=?#{did}
</select>
鑒別器
discriminator鑒別器可以根據某個字段的不同值來進行不同的操作,就像是java中的switch和sql中的case
<resultMap?id="baseResultMap"?type="Vehicle">
?<id?property="id"?column="id"/>
??<result?property="name"?column="name"/>
??<result?property="color"?column="color"/>
??<discriminator?javaType="int"?column="type">
????<case?value="1"?resultType="Car">
?????<result?property="doorCount"?column="door_count"/>
????</case>
????<case?value="2"?resultMap="vanResult">
?????<result?property="powerSlidingDoor"?column="power_sliding_door"/>
????</case>
??</discriminator>
</resultMap>
${}和#{}之間的區別
{}直接替換成變量的值,不做任何轉換,這種是取值以后再去編譯SQL語句
#{}:預編譯處理,sql中的#{}替換成?,補全預編譯語句,調用PreparedStatement的set方法來賦值,有效的防止Sql語句注入,這種取值是編譯好SQL語句再取值
sql塊
可重用的sql塊,可以被其他語句引用
<sql?id="userColumns">id,username,password</sql>
<select?id="selectUsers"?parameterType="int"?resultMap="baseResultMap">
?select?<include?refid="userColumns"/>
??from?users
??where?id?=?#{id}
</select>
緩存
默認情況下是沒有開啟二級緩存的,如果要開啟二級緩存,則需要使用<cache/>
-
cache 配置給定命名空間的緩存
<!--
????eviction:?緩存回收策略
????????-?LRU??最近最少使用:移除最長時間不被使用的,默認
????????-?FIFO??先進先出,按照對象進入緩存的順序移除
????????-?SOFT??軟引用,移除基于垃圾回收器狀態和軟引用規則的對象
????????-?WEAK??弱引用,積極地移除基于垃圾收集器狀態和弱引用規則的對象
?????flushInterval:?緩存刷新間隔
????????緩存多長時間清空一次,默認不清空,單位毫秒
?????readOnly???默認false
????????-?true??只讀,mybatis認為所有從緩存中獲取數據的操作都是只讀操作,不會修改數據。mybatis為了加快獲取速度,
????????????????直接將數據在緩存中的引用交給用戶,速度快,但是不安全
????????-?false?非只讀,mybatis會認為獲取到的數據可能會被修改,會利用序列化和反序列化機制克隆一份新的數據
?????size:?緩存多少元素
?????type:?指定自定義緩存的全類名,需要實現Cache接口
???blocking:?若緩存中找不到對應的key,是否會一直阻塞,知道對應的數據進入緩存
?-->
<cache?eviction="FIFO"?flushInterval="60000"?readOnly="true"?size="1024"/> -
cache-ref 從其他命名空間引用緩存配置
<cache-ref?namespace="com.someone.application.data.SomeMapper">
https://zhhll.icu/2021/框架/mybatis/基礎/3.mybatis映射文件/
本文由 mdnice 多平臺發布