MyBatis教程3【對映檔案和動態sql】
1.logj
在程式的執行的過程中為了便於查詢sql的輸出,需要引入logj新增依賴
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
新增log4j.properties檔案
log4j.rootCategory=DEBUG, stdout , R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n log4j.appender.R=org.apache.log4j.DailyRollingFileAppender log4j.appender.R.File=C:\\tools\\logs\\dpb.log log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
效果
2.傳入引數【$和#】
由於MyBatis底層還是Jdbc,而Jdbc在操作資料庫傳遞引數時,有兩種方式,一種是使用Statement,還有一種是使用PreparedStatement: 使用statement時,存在SQL注入問題,PreparedStatement則通過預編譯解決了SQL注入問題。 在MyBatis中,引入引數有兩種方式,一種是使用#,還有一種是使用$,其中,使用#對應了Jdbc種的PreparedStatement,而使用$則對應了Jdbc種的Statement,因此在MyBatis種,推薦使用#。
#的使用
$的使用
加入可以使用$替換#,注意,如果使用$,需要在Mapper種指定引數名字
包裝物件
javabean
public class UserWrapper {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
對映檔案
<!-- 從包裝物件中獲取資訊 包裝物件的別名. 取資訊 -->
<insert id="addUser4" parameterType="UserWrapper">
insert into t_user(name,age,favorites)values(#{user.name},#{user.age}
,#{user.favorites})
</insert>
測試
3.返回資料
ResultType
對於簡單資料型別,例如查詢總記錄數、查詢某一個使用者名稱這一類返回值是一個基本資料型別的,直接寫Java中的基本資料型別即可。 如果返回的是一個物件或者集合,並且物件中的屬性和查詢的欄位名是一一對應的,那麼resultType也可以直接寫一個物件。
ResultMap
resultMap主要用來解決屬性名和欄位名不一致以及一對多、一對一查詢等問題 欄位名不一致時,首先可以通過取別名解決,例如Bean的定義如下:
User物件
private int id;
// 該型別和欄位不一致
private String username;
private int age;
對映檔案
解決方式一:給欄位取別名,這裡講解解決方式二:
<resultMap type="com.sxt.bean.User" id="baseMap">
<id column="id" property="id"/>
<result property="username" column="name"/>
<result property="age" column="age"/>
</resultMap>
<select id="getUserById" resultMap="baseMap"
resultType="com.sxt.bean.User">
select id ,name ,age from t_user where id=${id}
</select>
主鍵回寫
一般情況下,主鍵有兩種生成方式:
主鍵自增長
自定義主鍵(一般可以使用UUID)
如果是第二種,主鍵一般是在Java程式碼中生成,然後傳入資料庫執行,如果是第一個主鍵自增長,此時,Java可能需要知道資料新增成功後的主鍵。 在MyBatis中,可以通過主鍵回填來解決這個問題(推薦)。
主鍵回填
<insert id="add" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into t_user(username,password) values (#{name},#{password})
</insert>
selectKey
另外,可以利用MySQL自帶的==last_insert_id()==函式查詢剛剛插入的id
<insert id="add1" parameterType="user">
<selectKey keyProperty="id" resultType="int" >
select LAST_INSERT_ID()
</selectKey>
insert into t_user(username,password) values (#{name},#{password})
</insert>
動態sql語句
MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。 雖然在以前使用動態 SQL 並非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 對映語句中的強大的動態 SQL 語言得以改進這種情形。 動態 SQL 元素和 JSTL 或基於類似 XML 的文字處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。MyBatis 採用功能強大的基於 OGNL 的表示式來淘汰其它大部分元素。
if語句
動態 SQL 通常要做的事情是根據條件包含 where 子句的一部分。比如
<select id="queryUser" resultMap="baseMap"
resultType="com.sxt.bean.User" parameterType="user">
select id ,name ,age from t_user
where 1 =1
<if test="username!=null">
and name = #{username}
</if>
</select>
// 介面
public List<User> queryUser(User user);
測試
where語句
在使用if語句做動態條件處理的時候如果所有條件都不滿足,那麼得到的SQL語句如下:
select * from t_user where
在這種情況下,我們一般會加一個1=1來匹配語法規則
<select id="queryUser" resultMap="baseMap"
resultType="com.sxt.bean.User" parameterType="user">
select id ,name ,age from t_user
where 1 =1
<if test="username!=null">
and name = #{username}
</if>
</select>
此時可以使用標籤來處理這種情況
<select id="queryUser" resultMap="baseMap"
resultType="com.sxt.bean.User" parameterType="user">
select id ,name ,age from t_user
<where>
<if test="username!=null">
and name = #{username}
</if>
</where>
</select>
set語句
set主要也是用來解決更新問題的。
<update id="updateBookById">
update t_book
<set>
<if test="author!=null"> author=#{author},</if>
<if test="name!=null"> b_name=#{name},</if>
<if test="price!=null"> price=#{price},</if>
</set>
where id=#{id};
</update>
foreach語句
foreach用來遍歷,遍歷的物件可以是陣列,也可以是集合
dao層介面
mapper對映檔案
<select id="query1" resultType="User" resultMap="basemap">
select * from t_user
where id in
<foreach collection="ids" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</select>
<insert id="add2" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into t_user(username,password) values
<foreach collection="users" separator="," item="user">
(#{user.name},#{user.password})
</foreach>
</insert>
bind元素
bind 元素可以從 OGNL 表示式中建立一個變數並將其繫結到上下文。
<select id="getUserById" resultMap="baseMap" resultType="com.sxt.bean.User">
<!-- 聲明瞭一個引數aaa 在後面就可以使用了 -->
<bind name="aaa" value="12"/>
select
id ,name ,age from t_user where id=${aaa}
</select>
sql塊
sql片段一般用來定義sql中的列
關聯關係
在關係型資料庫中,表與表之間很少是獨立與其他表沒關係的。所以在實際開發過程中我們會碰到很多複雜的關聯關係。在此我們來分析下載mybatis中怎麼處理這些關係
1對1
我們有一張員工表(T_EMP),一張部門表(T_DEPT)。員工表中的一條記錄對應於部門表中有且僅有一條記錄。這就是一對一的關聯關係。
查詢每個員工的資訊及對應的部門資訊
部門物件
package com.sxt.bean;
public class Dept {
private Integer deptid;
private String deptname;
private String deptdesc;
public Integer getDeptid() {
return deptid;
}
public void setDeptid(Integer deptid) {
this.deptid = deptid;
}
public String getDeptname() {
return deptname;
}
public void setDeptname(String deptname) {
this.deptname = deptname;
}
public String getDeptdesc() {
return deptdesc;
}
public void setDeptdesc(String deptdesc) {
this.deptdesc = deptdesc;
}
@Override
public String toString() {
return "Dept [deptid=" + deptid + ", deptname=" + deptname + ", deptdesc=" + deptdesc + "]";
}
}
員工物件
package com.sxt.bean;
public class Emp {
private Integer id;
private String name;
private Dept dept;
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 Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp [id=" + id + ", name=" + name + ", dept=" + dept + "]";
}
}
對映檔案處理
<?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">
<mapper namespace="com.sxt.dao.EmpDao">
<resultMap type="Emp" id="basemap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="dept" javaType="Dept">
<id property="deptid" column="deptid"/>
<result property="deptname" column="deptname"/>
<result property="deptdesc" column="deptdesc"/>
</association>
</resultMap>
<select id="query" resultMap="basemap">
SELECT t.*,t1.*
FROM t_emp t LEFT JOIN t_dept t1
on t.deptid=t1.deptid
</select>
</mapper>
1對多關係
查詢出所有的部門資訊及該部門下所有員工的資訊
對映檔案
<?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">
<mapper namespace="com.sxt.dao.DeptDao">
<resultMap type="Dept" id="basemap">
<id property="deptid" column="deptid"/>
<result property="deptname" column="deptname"/>
<result property="deptdesc" column="deptdesc"/>
<collection property="emps" ofType="Emp">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="deptid" column="deptid"/>
</collection>
</resultMap>
<select id="query" resultMap="basemap">
SELECT t.*,t1.*
FROM t_dept t LEFT JOIN t_emp t1
on t.deptid=t1.deptid
</select>
</mapper>