Mybatis(二)
Mybatis基礎操作
刪除
根據主鍵刪除
- SQL語句:
delete from emp where id = 17;
- 介面方法:
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);
注意事項
- 如果mapper介面方法形參只有一個普通型別的引數,#{…} 裡面的屬性名可以隨便寫,如:#{id}、#{value},建議保持一致以增強可讀性。
- delete、create、remove和update方法均有返回值,代表此次操作影響到的記錄數。
- 可以在application.properties中,開啟mybatis的日誌,並指定輸出到控制檯:
#指定mybatis輸出日誌的位置,輸出控制檯
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
引數佔位符
佔位符 | 作用 | 使用時機 |
---|---|---|
# | 執行SQL時,會將#{…}替換為?,生成預編譯SQL,會自動設定引數值 | 引數傳遞都使用# |
$ | 拼接SQL。直接將引數拼接在SQL語句中,存在SQL隱碼攻擊問題 | 對錶名、列表進行動態設定時使用。 |
SQL預編譯
- 形式:SQL語句:
delete from emp where id = ?
;引數:delete方法的入參;執行:使用引數將?
替換後的SQL語句。
優勢
-
效能更高,使用Mybatis操作MySQL資料庫時,Java將SQL語句傳遞給MySQL後,MySQL會依次執行以下操作:
- 檢查快取中是否有剛才傳入的SQL語句,如果有,直接執行它(如果是預編譯的話還需要使用引數),且不用再執行後兩步。
- 依次對剛才傳入的SQL語句執行SQL語法解析檢查、最佳化SQL和編譯SQL的操作,並在編譯SQL之後將編譯好的SQL語句存入快取。
- 執行編譯好的SQL語句。
如果使用預編譯的SQL語句,則它放入快取後,能夠匹配更多新傳入的SQL語句,從而減少SQL語法解析檢查、最佳化SQL和編譯SQL的執行,提高效能。
-
更安全(防止SQL隱碼攻擊):SQL隱碼攻擊是透過操作輸入的資料來修改事先定義好的SQL語句,以達到執行程式碼對伺服器進行攻擊的方法。直接拼接字串可能會導致出現這種問題,而使用預編譯的SQL語句則不會。
插入
- SQL語句:
insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values ('songyuanqiao','宋遠橋',1,'1.jpg',2,'2012-10-09',2,'2022-10-01 10:00:00','2022-10-01 10:00:00');
- 介面方法(將變數封裝進實體物件進行傳遞):
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time," +
"update_time) values(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}," +
"#{createTime}, #{updateTime})")
public void insert(Emp emp);
主鍵返回
- 在資料新增成功後,可以獲取自動生成的插入資料庫資料的主鍵。
- 在介面方法上加一行註解即可:
@Options(keyProperty = "id", useGeneratedKeys = true) //會自動將生成的主鍵值,賦值給入參物件的id屬性
更新
- SQL語句(根據ID更新員工資訊):
update emp set username = 'songdaxia', name = '宋大俠', gender = 1 , image = '1.jpg' , job = 2, entrydate = '2012-01-01', dept_id = 2, update_time = '2022-10-01 12:12:12' where id = 19;
- 介面方法:
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, " +
"job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public void update(Emp emp);
查詢
根據ID查詢
- SQL語句
select * from emp where id = 19;
- 介面方法
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
資料封裝
- 如果實體類屬性名和資料庫表查詢返回的欄位名一致,mybatis會自動封裝。
- 如果實體類屬性名和資料庫表查詢返回的欄位名不一致,不能自動封裝。
資料封裝解決方法
- 起別名:在SQL語句中,對不一樣的列名起別名,別名和實體類屬性名一樣。
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time " +
"createTime, update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
- 手動結果對映:透過 @Results及@Result 進行手動結果對映。
@Select("select * from emp where id = #{id}")
@Results({
@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime")})
public Emp getById(Integer id);
- 開啟駝峰命名(推薦使用):如果欄位名與屬性名符合駝峰命名規則,mybatis會自動透過駝峰命名規則對映。
#application.properties檔案中
#開啟駝峰命名自動對映,即從資料庫欄位名a_column對映到Java屬性名aColumn。
mybatis.configuration.map-underscore-to-camel-case=true
條件查詢
- SQL語句:
select * from emp where name like '%張%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01' order by update_time desc;
- 介面方法一:
//在字串內部不能使用#{···},因為預編譯生成的?佔位符不能出現在引號內
//可以使用${···}代替,但是這樣做會導致效能低、不安全、存在SQL隱碼攻擊問題
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and entrydate between " +
"#{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
- 介面方法二:
//使用MySQL的concat函式代替${···},能夠避免出現那些問題,推薦使用
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
引數名說明
- 在springBoot的2.x版本中,方法入參名直接使用與佔位符中名稱相同即可完成引數傳遞。
- 在springBoot的1.x版本中或單獨使用mybatis時,方法入參之前必須加上
@Param("佔位符中名稱")
的註解,因為在這些環境下編譯生成的的位元組碼檔案中入參的名稱不會保留:
//原始碼
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
//編譯生成的位元組碼檔案
...
public List<Emp> list(String var1, Short var2, LocalDate var3, LocalDate var4);
XML對映檔案
規範
- XML對映檔案的名稱與Mapper介面名稱一致,並且將XML對映檔案和Mapper介面放置在相同包下。(同包同名)
- XML對映檔案的namespace屬性與Mapper介面的全類名保持一致。
- XML對映檔案中sql語句的id與Mapper介面中的方法名一致,並保持返回型別一致。
兩種方法的選擇
- 如果只是完成一些簡單的增刪改查功能,那麼使用Mybatis的註解比較好。
- 如果需要實現複雜的SQL功能,建議使用XML來配置對映語句,簡化Java原始碼。
MybatisX
MybatisX 是一款基於 IDEA 的快速開發Mybatis的外掛,為效率而生,在IDEA中搜尋並安裝即可。
Mybatis動態SQL
隨著使用者的輸入或外部條件的變化而變化的SQL語句,我們稱為動態SQL。
<if>
- 用於判斷條件是否成立。使用test屬性進行條件判斷,如果條件為true,則拼接SQL。
- 語法:
<if test="條件語句">
...
</if>
<where>
- where元素只會在子元素有內容的情況下才插入where子句,而且會自動去除子句的開頭的AND 或OR。
- 語法:
<!--用於替換SQL語句中的where關鍵字-->
<where>
...
</where>
<set>
- 動態地在行首插入 SET 關鍵字,並會刪掉額外的逗號。(用在update語句中)
- 語法:
<!--動態地在行首插入 SET 關鍵字,並會刪掉額外的逗號。(用在update語句中)-->
<set>
...
</set>
<foreach>
- 用於遍歷集合中的元素,拼接進SQL語句,同時還可以加上拼接的起始符、分隔符和結束符。
- 語法:
<foreach collection="集合名稱" item="集合遍歷出來的元素/項" separator="每一次遍歷使用的分隔符" open="遍歷開始前拼接的片段" close="遍歷結束後拼接的片段">
...#{集合遍歷出來的元素/項}...
</foreach>
<sql>,<include>
- <sql>:定義可重用的 SQL 片段。
- <include>:透過屬性refid,引用包含的sql片段。
- 這兩個標籤配合使用,可以提升程式碼的複用性,方便開發和維護。
- 語法:
<sql id="唯一的id">
SQL語句
</sql>
<include refid="要引用的sql片段的id"/>