目錄
xml映射文件
與mapper接口的對應關係
- namespace和接口名一致(xml文件名不需要和接口名一致)
- id和接口中的方法名一致
- 參數類型、返回值類型與接口方法中的一致
parameterType、resultType
- 如果是基本類型,一律使用包裝類型
- 別名規則:類名全小寫
- 如果返會的結果集中有多條記錄(List),resultType不能寫成list,和返回單條記錄一樣都是寫元素類型,eg. List<User> => user ,如果返回了多條記錄,會自動映射爲指定類型的List。
參數問題
如果使用了parameterType,只能傳入一個參數,如果要傳入多個參數,可以放到list、map中傳入
<!-- 傳入list -->
<select id="xxx" parameterType="list" resultType="xxx">
<!-- 默認的列表名是list,通過下標取值 -->
SELECT * FROM tb_user WHERE name=#{list[2]}
</select>
<!-- 傳入對象 -->
<select id="xxx" parameterType="user" resultType="xxx">
<!-- 通過成員變量名直接取,會自動調用對應的getter方法 -->
SELECT * FROM tb_user WHERE name=#{name}
</select>
<!-- 傳入map -->
<select id="xxx" parameterType="map" resultType="xxx">
<!-- 通過key直接取 -->
SELECT * FROM tb_user WHERE name=#{name}
</select>
不使用parameterType,可直接傳入多個參數
public interface UserMapper{
User findUser(Integer id, String name);
}
<!-- 不要parameterType -->
<select id="findUser" resultType="user">
SELECT * FROM tb_user WHERE id=#{id} and name=#{name}
</select>
@Param可解決mapper接口、xml映射文件參數名不同的問題
public interface UserMapper{
// 通過@Param綁定xml中的name變量
User findUser(Integer id, @Param("name") String username);
}
<select id="findUser" resultType="user">
SELECT * FROM tb_user WHERE id=#{id} and name=#{name}
</select>
#{ }、${ }的區別
#{ }用於取值,${ }除了有#{ }的功能,還可以拼接字符串,但使用${ }拼接字符串有sql注入的風險。
以模糊查詢爲例
<select id="xxx" parameterType="string" resultType="user">
SELECT * FROM tb_user WHERE name LIKE '%${name}%'
</select>
<select id="xxx" parameterType="string" resultType="user">
<!-- 使用sql的concat()函數拼接字符串,使用#{}取值 -->
SELECT * FROM tb_user WHERE name LIKE concat('%',#{name},'%')
</select>
resultMap的使用
<resultMap> 用於自定義結果集映射
<!-- resultType不能和resultMap同時使用,fetchSize指定返回的記錄數,未指定時默認返回所有滿足要求的記錄 -->
<select id="" parameterType="" resultMap="resultMap" resultType="user" fetchSize="10">
</select>
<!-- type指定po -->
<resultMap id="userMap" type="user">
<!-- 默認映射規則是同名映射,我們只需指定名稱不一致的字段,主鍵字段用id指定,普通字段用result指定 -->
<id property="id" column="user_id"/>
<result property="username" column="user_name"/>
</resultMap>
<!-- resultMap屬性指定要使用的<resultMap> -->
<select id="" parameterType="" resultMap="userMap">
</select>
此外,<resultMap>還有2個常用子元素<association>、<collection>,用於關聯映射。
關聯映射
關係數據庫中,多表之間有三種關聯關係
- 一對一:一張身份證對應一個人 <=> 一個人也只對應一張身份證
- 一對多:一個用戶可以有多個訂單 <=> 這多個訂單都屬於同一個用戶
- 多對多:一個訂單可以包含多種商品 <=> 一種商品可以屬於多個訂單
設計數據庫時如何處理三種關聯關係?
- 一對一:在一方引入另一方的主鍵作爲外鍵
- 一對多:在多的一方,引入一的一方的主鍵作爲外鍵
- 多對多:新建一張中間表,引入2張表的主鍵作爲外鍵,可以使用這2個外鍵作爲中間表的聯合主鍵,也可以新建id字段作爲中間表的主鍵
java如何處理、描述三種關聯關係?
// 一對一
class A{
B b;
}
class B{
A a;
}
// 一對多,A是一,B是多
class A{
List<B> b;
}
class B{
A a;
}
// 多對多
class A{
List<B> b;
}
class B{
List<A> a;
}
如果多表查詢返回的結果集中包含另一方的字段,如何映射?
<select id="findStudentById" parameterType="integer" resultMap="studentWithScoreMap">
<!-- 一對一、一對多都是根據關聯外鍵來查2張表,多對多是根據中間表來查2張表、是3表聯查 -->
SELECT st.*,sc.* FROM tb_student st ,tb_score sc WHERE st.id=#{id} AND st.id=sc.student_id
</select>
<resultMap id="studentWithScoreMap" type="student">
<!-- 如果其它字段名稱不一致,手動映射 -->
<id property="" column=""/>
<result property="" column=""/>
<!-- 一對一用association,javaType指定成員變量類型 -->
<association property="score" javaType="score" />
<!-- 如果名稱不匹配,手動指定映射 -->
<association property="score" javaType="score">
<id property="" column="" />
<result property="" column=""/>
</association>
<!-- 一對多、多對多用collection。注意是ofType,指定List元素類型 -->
<collection property="" ofType="" />
<!-- 如果名稱不匹配,手動指定映射 -->
<collection property="" ofType="">
<id property="" column="" />
<result property="" column=""/>
</collection>
</resultMap>
動態sql
動態sql是mybatis的強大特性之一,可以實現sql語句的動態組裝。
<where>、<if>
where:如果有內容就添加關鍵字WHERE
if:如果條件爲true就添加內容
常用於多條件查詢,一個輸入框指定一個條件,有的輸入框可能沒填
<select id="findUser" resultType="user">
SELECT * FROM tb_user
<where>
<if test="name!=null and name!=''">
name=#{name}
</if>
<if test="gender!=null and gender!=''">
AND tel=#{gender}
</if>
</where>
</select>
<choose>、<when>、<otherwise>
相當於switch語句,<when>相當於case,<otherwise>相當於default,條件爲true就加上對應的sql語句
<select id="findStudent" resultType="student">
SELECT * FROM tb_student WHERE dep=#{dep}
<choose>
<when test="englishLevel=='cet4'">
AND english_level='cet4'
</when>
<when test="englishLevel=='cet6'">
AND english_level='cet6'
</when>
<otherwise>
AND english_level<>'cet4' AND english_level<>'cet6'
</otherwise>
</choose>
</select>
<set>
傳入pojo類型,更新多個字段,但對象的部分字段可能沒有值,不能用jvm賦的初值null、0去覆蓋表中原來的值,需要先判斷。
<set>用於更新操作,可更新一個對象、也可批量更新(list)。如果有內容,會自動加關鍵字SET,並自動去除內容中多餘的逗號。
<select id="updateUser" parameterType="user">
UPDATE tb_user
<set>
<if test="name!=null and name!=''">
<!-- 如果後面的內容都爲false,會自動去掉這個逗號 -->
name=#{name},
</if>
<if test="age!=0">
age=#{age},
</if>
<if test="tel!=null and tel!=''">
tel=#{tel},
</if>
</set>
where id=#{id}
</select>
update語句至少要有一個字段更新,不然會報:語法錯誤。
<foreach>
<foreach>用於迭代集合,常配合sql關鍵字in使用,批量操作記錄。
- collection 要迭代的集合的數據類型,List=>list,Map=>key的數據類型
- index 當前迭代次數,從0開始
- item 當前迭代元素,map是key
- open 拼接這整段字符串時以什麼開頭
- close 拼接這整段字符串時以什麼結尾
- separator 迭代添加的元素之間用什麼分隔
collection必需,其餘均可選。
<select id="findStudent" parameterType="list" resultType="student">
SELECT * FROM tb_student WHERE dep IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<bind>
${ }可拼接字符串,但有sql注入的風險。
使用數據庫自帶的方式拼接字符串沒有sql注入的風險,mysql可以使用concat()拼接字符串,oracle可以使用 || 拼接字符串,但都只能針對特定的數據庫使用,不利於項目移植。
<bind>可拼接字符串,沒有sql注入的風險,所有數據庫都可用。
<!-- 模糊查詢 -->
<select id="queryUser" parameterType="string" resultType="user">
<bind name="pattern_name" value="'%'+name+'%'"/>
SELECT * FROM user_tb WHERE name LIKE #{pattern_name}
</select>
說明
1、在元素屬性中訪問參數,不加#{ }、${ },直接訪問;在標籤體中訪問參數,要加#{ }、${ }
2、test屬性
- 相等判斷:==,!=
- 邏輯與:只能用and,不能用&&
- 邏輯或:or、||均可
BindingException: Invalid bound statement (not found)
檢查以下方面
1、xml映射文件的namespace和接口名是否一致,namespace要是接口名的全路徑,id和接口中的函數名是否一致,參數類型、返回值類型是否一致
2、application.properties中mybatis的配置是否正確
3、xml映射文件是否忘寫了後綴.xml
第二個纔是對的