MyBatis 是支持定製化 SQL、存儲過程以及高級映射的優秀的持久層框架,其主要就完成2件事情:
-
- 封裝JDBC操作
-
- 利用反射打通Java類與SQL語句之間的相互轉換
MyBatis的主要設計目的就是讓我們對執行SQL語句時對輸入輸出的數據管理更加方便,所以方便地寫出SQL和方便地獲取SQL的執行結果纔是MyBatis的核心競爭力。
接口映射
在使用MyBatis的時候,都用的是Dao接口和XML文件裏的SQL一一對應來進行使用的。那你是否思考過二者是如何建立關係的?
MyBatis會先解析這些XML文件,通過XML文件裏面的命名空間(namespace)跟DAO建立關係;然後XML中的每段SQL會有一個id跟DAO中的接口進行關聯。
Dao接口裏的方法,是不能重載的,因爲是全限名+方法名的保存和尋找策略
通常一個Xml映射文件,都會寫一個Dao接口與之對應。Dao接口,就是人們常說的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法內的參數,就是傳遞給sql的參數。Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串作爲key值,可唯一定位一個MappedStatement。
如果配置了namespace,那麼id是可以重複的,因爲我們的Statement實際上就是namespace+id
舉例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace爲com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一個<select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MappedStatement對象。
#{}和${}的區別是什麼?
- #{}解析傳遞進來的參數數據
- ${}對傳遞進來的參數原樣拼接在SQL中
- Mybatis 在處理#{}時,會將 sql 中的#{}替換爲?號,調用 PreparedStatement 的 set 方法來賦值;
Mybatis 在處理 美元符號{} 時,就是把${}替換成變量的值 - #{}是預編譯處理,${}是字符串替換。
- 使用#{}可以有效的防止SQL注入,提高系統安全性。
select * from ${tableName} where name = #{name}
在這個例子中,如果表名爲
user; delete user; –
則動態解析之後 sql 如下:
select * from user; delete user; – where name = ?;
--之後的語句被註釋掉,而原本查詢用戶的語句變成了查詢所有用戶信息+刪除用戶表的語句,會對數據庫造成重大損傷,極大可能導致服務器宕機。
'#‘相當於對數據 加上 雙引號,’$'相當於直接顯示數據
'#'將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。
'$'將傳入的數據直接顯示生成在sql中。
- #{} 用於CRUD語句
${} 則用於模糊查詢(記得加%%哦),}一般用在order by, limit, group by等場所。
如何獲取自動生成的(主)鍵值?
如果我們一般插入數據的話,如果我們想要知道剛剛插入的數據的主鍵是多少(一般這個主鍵是自增ID),一般情況下我們可能在以某個唯一字段與數據庫進行一次查詢交互,獲取到自增id,但是這樣相對比較麻煩,我們可以通過對mybatis進行配置。
<insert id="insert" parameterType="com.qufenqi.pay.settlement.dao.po.SettleBasicData" useGeneratedKeys="true"
keyProperty="id" keyColumn="id">
insert into sett_basic_data (id, biz_order_no, biz_type,
fund_type, trade_mode, merchant_id, merchant_name,
create_time, update_time)
values (#{id,jdbcType=BIGINT}, #{bizOrderNo,jdbcType=VARCHAR}, #{bizType,jdbcType=VARCHAR},
#{fundType,jdbcType=VARCHAR}, #{tradeMode,jdbcType=VARCHAR}, #{merchantId,jdbcType=VARCHAR}, #{merchantName,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
</insert>
在上述方法中添加useGeneratedKeys="true" keyProperty="id" keyColumn="id"
settleBasicDataMapper.insert(settleBasicData); settleBasicData.getId();
代碼親測有效
在mapper中如何傳遞多個參數?
-
使用佔位符的思想
其中,#{0}代表接收的是dao層中的第一個參數,#{1}代表dao層中第二參數,更多參數一致往後加即可。
-
採用Map傳多參數 parameterType=“hashmap”
-
Dao層的函數方法,和佔位符有些類似,目前單個參數用的主流方法(使用@Param註解)
-
通過註解的方法查詢(配合@Param註解)
-
採用javaBean(一般應用於更新和查詢情況)
這種方法很直觀,但需要建一個實體類,擴展不容易,需要加屬性,看情況使用。
附帶一個批量更新數據庫的sql
對SettleBasicData集合中的每條數據進行更新
int updateBatch(@Param(value = "list") List<SettleBasicData> list);
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update sett_basic_data
set
status = #{item.status,jdbcType=VARCHAR},
callback_status = #{item.callbackStatus,jdbcType=VARCHAR},
update_time = #{item.updateTime,jdbcType=TIMESTAMP}
where biz_order_no = #{item.bizOrderNo,jdbcType=VARCHAR}
and biz_type = #{item.bizType,jdbcType=VARCHAR}
and fund_type = #{item.fundType,jdbcType=VARCHAR}
</foreach>
</update>
在jdbc鏈接數據庫時添加一下配置
?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
親手採過的坑。
這事因爲原來mysql的批量更新是要我們主動去設置的, 就是在數據庫的連接url上設置一下,加上* &allowMultiQueries=true *即可。
字段映射
將表中的字段與我們建立的entity實體進行建立關聯
通過resultMap來映射字段名和實體類屬性名的一一對應的關係
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
//type對對應的實體類
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id屬性來映射主鍵字段–>
<id property=”id” column=”order_id”/>
<!–用result屬性來映射非主鍵字段,property爲實體類屬性名,column爲數據表中的屬性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>