-
什么是MyBatis存筏?
MyBatis 是一款優(yōu)秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射瑟曲。MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作士鸥。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型闲孤、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數(shù)據(jù)庫中的記錄烤礁。
-
MyBatis中的主要組成部分
- Resources:用于讀取配置文件讼积,并返回輸入流。
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
- SqlSessionFactoryBuilder(工廠構(gòu)造器):根據(jù)配置文件來生成SqlSessionFactory
生命周期:這個類可以被實例化脚仔、使用和丟棄勤众,一旦創(chuàng)建了 SqlSessionFactory,就不再需要它了鲤脏。因此 SqlSessionFactoryBuilder實例的最佳作用域是方法作用域(也就是局部方法變量)们颜。你可以重用SqlSessionFactoryBuilder來創(chuàng)建多個SqlSessionFactory實例吕朵,但最好還是不要一直保留著它,以保證所有的 XML 解析資源可以被釋放給更重要的事情窥突。
- SqlSessionFactory(SqlSession工廠):用于創(chuàng)建SqlSession對象努溃。
生命周期:SqlSessionFactory 一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運行期間一直存在,沒有任何理由丟棄它或重新創(chuàng)建另一個實例阻问。 使用 SqlSessionFactory 的最佳實踐是在應(yīng)用運行期間不要重復(fù)創(chuàng)建多次梧税,多次重建 SqlSessionFactory 被視為一種代碼“壞習(xí)慣”。因此 SqlSessionFactory 的最佳作用域是應(yīng)用作用域称近。 有很多方法可以做到第队,最簡單的就是使用單例模式或者靜態(tài)單例模式。
private static SqlSessionFactory sqlSessionFactory; sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
- SqlSession(會話):用于完成對數(shù)據(jù)庫的連接煌茬、操作以及對結(jié)果集的處理等斥铺。
生命周期:每個線程都應(yīng)該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的坛善,因此是不能被共享的晾蜘,所以它的最佳的作用域是請求或方法作用域。 絕對不能將 SqlSession 實例的引用放在一個類的靜態(tài)域眠屎,甚至一個類的實例變量也不行剔交。 也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession改衩。 如果你現(xiàn)在正在使用一種 Web 框架岖常,考慮將 SqlSession 放在一個和 HTTP 請求相似的作用域中。 換句話說葫督,每次收到 HTTP 請求竭鞍,就可以打開一個 SqlSession,返回一個響應(yīng)后橄镜,就關(guān)閉它偎快。 這個關(guān)閉操作很重要,為了確保每次都能執(zhí)行關(guān)閉操作洽胶,你應(yīng)該把這個關(guān)閉操作放到 finally 塊中晒夹。 下面的示例就是一個確保 SqlSession 關(guān)閉的標準模式:
try (SqlSession session = sqlSessionFactory.openSession()) { // 你的應(yīng)用邏輯代碼 }
-
MyBatis配置
- properties
主要作用:加載外部的properties文件
properties代碼示例:
<properties resource="jdbc.properties"/>
- 設(shè)置(settings)
主要作用:MyBatis框架運行規(guī)則配置
設(shè)置(settings)代碼示例:
<settings> <!-- 開啟日志 --> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
- 類型別名(typeAliases)
主要作用:設(shè)置別名(為實體類設(shè)置別名)
類型別名(typeAliases)代碼示例:
<typeAliases> <!-- 為指定的實體類設(shè)置別名 --> <typeAlias type="com.apesource.entity.Employee" alias="Employee"/> <!-- 設(shè)置實體類包,為該package中的每個實體類自動設(shè)置別名 --> <package name="com.apesource.entity"/> </typeAliases>
- 環(huán)境配置(environments)
主要作用:配置事務(wù)管理和連接池
環(huán)境配置(environments)代碼示例:
<environments default="development"> <!-- 環(huán)境1(開發(fā)) --> <environment id="development"> <!-- 事務(wù)管理器:采用JDBC事務(wù) --> <transactionManager type="JDBC" /> <!-- 數(shù)據(jù)源(數(shù)據(jù)庫連接池) --> <!-- type設(shè)置為pooled,啟動數(shù)據(jù)庫連接池 --> <dataSource type="POOLED"> <!-- 數(shù)據(jù)庫連接參數(shù) --> <property name="driver" value="${driver_class}" /> <property name="url" value="${jdbc_url}" /> <property name="username" value="${db_username}" /> <property name="password" value="${db_password}" /> </dataSource> </environment> </environments>
- 映射器(mappers)
主要作用:配置映射器姊氓,這些映射器的 XML 映射文件包含了SQL代碼和映射定義信息
映射器(mappers)代碼示例:
<mappers> <!-- SQL映射文件 --> <mapper resource="com/apesource/dao/mapper/AnswerRecordMapper.xml"/> </mappers>
-
MyBatis XML 映射器
1.常用節(jié)點作用總結(jié)
- select:映射查詢SQL語句
- update:映射修改SQL語句
- delete:映射刪除SQL語句
- insert:映射插入SQL語句
2.常用屬性作用總結(jié)
- id 屬性:為當前映射的SQL語句進行命名
- resultType 屬性:設(shè)置查詢結(jié)果使用的類型名稱
- parameterType 屬性:設(shè)置參數(shù)使用的類型名稱
- useGeneratedKeys屬性:開啟主鍵回填
- keyProperty屬性:設(shè)置用于保存主鍵值的屬性名稱
3.常見SQL映射示例
示例1:普通增加
<insert id="insertAnswerRecord" parameterType="AnswerRecord" useGeneratedKeys="true" keyProperty="recordId"> insert into answer_record (respondent,question,right_answer,submit_answer,submit_datetime) values(#{respondent},#{question},#{rightAnswer},#{submitAnswer},now()) </insert>
// 接口方法定義 int insertAnswerRecord(AnswerRecord answerRecord);
示例2:批量增加
<!-- 批量添加新答題記錄 --> <insert id="insertAnswerRecordBatch" parameterType="list" useGeneratedKeys="true" keyProperty="recordId"> insert into answer_record(respondent,question,right_answer,submit_answer,submit_datetime) values <foreach collection="list" item="record" separator=","> ( #{record.respondent}, #{record.question}, #{record.rightAnswer}, #{record.submitAnswer}, now() ) </foreach> </insert>
// 接口方法定義 int insertAnswerRecordBatch(List<AnswerRecord> answerRecordList);
示例3:普通刪除
<delete id="deleteAnswerRecord" > delete from answer_record where record_id = #{id} </delete>
// 接口方法定義 int deleteAnswerRecord(int recordId);
示例4:批量刪除
<delete id="deleteAnswerRecordBatch" parameterType="list"> DELETE FROM answer_record WHERE record_id IN <foreach collection="list" item="id" separator="," open="(" close=")" > #{id} </foreach> </delete>
// 接口方法定義 int deleteAnswerRecordBatch(List<Integer> recordIdList);
示例5:動態(tài)修改
<!-- set節(jié)點用于動態(tài)處理update語句中的set --> <!-- if節(jié)點用于條件判斷 --> <update id="updateAnswerRecord" parameterType="AnswerRecord"> update answer_record <set> <if test="respondent != null">respondent = #{respondent},</if> <if test="question != null">question = #{question},</if> <if test="rightAnswer != null">right_answer = #{rightAnswer},</if> <if test="submitAnswer != null">submit_answer = #{submitAnswer},</if> submit_datetime = now() </set> where record_id = #{recordId} </update>
// 接口方法定義 int updateAnswerRecord(AnswerRecord answerRecord);
示例6:動態(tài)查詢
<!-- where節(jié)點:處理where子句和條件之間的關(guān)系 --> <select id="listAnswerRecordByCondition" resultType="AnswerRecord" parameterType="AnswerRecord"> SELECT record_id AS recordId, respondent, question, right_answer AS rightAnswer, submit_answer AS submitAnswer, submit_datetime AS submitDatetime FROM answer_record <where> <if test="respondent != null">AND respondent = #{respondent}</if> <if test="question != null">AND question LIKE concat('%',#{question},'%')</if> <if test="rightAnswer != null">AND right_answer = #{rightAnswer}</if> <if test="submitAnswer != null">AND submit_answer = #{submitAnswer}</if> </where> </select>
// 接口方法定義 List<AnswerRecord> listAnswerRecordByCondition(AnswerRecord ar);
示例7:查詢結(jié)果封裝為Map
<select id="countAnswerRecordDataByRespondent" resultType="Map"> select count(record_id) as '總答題數(shù)目', (select count(record_id) from answer_record where respondent = #{name} and right_answer = submit_answer) as '正確題目數(shù)目', (select count(record_id) from answer_record where respondent = #{name} and right_answer != submit_answer) as '錯誤題目數(shù)目' from answer_record where respondent = #{name} </select>
// 接口方法定義 Map<String,Integer> countAnswerRecordDataByRespondent(String respondent);