MyBatis技術(shù)總結(jié)
分類:JavaEE框架技術(shù)原創(chuàng)文章
作者:幸運(yùn)王
-
什么是MyBatis废酷?
MyBatis 是一款優(yōu)秀的持久層框架,它支持自定義 SQL犬第、存儲(chǔ)過程以及高級(jí)映射锦积。MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作。MyBatis 可以通過簡(jiǎn)單的 XML 或注解來配置和映射原始類型歉嗓、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對(duì)象)為數(shù)據(jù)庫(kù)中的記錄背蟆。
-
MyBatis中的主要組成部分
SqlSessionFactoryBuilder( 工廠構(gòu)造器鉴分,使用了建造者模式 ) :根據(jù)配置文件來生成SqlSessionFactory
生命周期及其作用域:這個(gè)類可以被實(shí)例化、使用和丟棄带膀,一旦創(chuàng)建了 SqlSessionFactory志珍,就不再需要它了。 因此 SqlSessionFactoryBuilder 實(shí)例的最佳作用域是方法作用域(也就是局部方法變量)垛叨。 你可以重用 SqlSessionFactoryBuilder 來創(chuàng)建多個(gè) SqlSessionFactory 實(shí)例伦糯,但最好還是不要一直保留著它柜某,以保證所有的 XML 解析資源可以被釋放給更重要的事情。
SqlSessionFactory(SqlSession工廠敛纲,使用到了工廠模式):創(chuàng)建SqlSession喂击。
生命周期及其作用域:SqlSessionFactory 一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在,沒有任何理由丟棄它或重新創(chuàng)建另一個(gè)實(shí)例淤翔。 使用 SqlSessionFactory 的最佳實(shí)踐是在應(yīng)用運(yùn)行期間不要重復(fù)創(chuàng)建多次翰绊,多次重建 SqlSessionFactory 被視為一種代碼“壞習(xí)慣”。因此 SqlSessionFactory 的最佳作用域是應(yīng)用作用域旁壮。 有很多方法可以做到监嗜,最簡(jiǎn)單的就是使用單例模式或者靜態(tài)單例模式。SqlSessionFactory創(chuàng)建代碼示例:
private static final String CONFIG = "mybatis-config.xml"; //配置文件 private static SqlSessionFactory sqlSessionFactory; //SqlSessionFactory對(duì)象 private static final Class<MyBatisUtils> CLASS_LOCK = MyBatisUtils.class; //類級(jí)別鎖 static { //初始化 initSqlSessionFactory(); } //私有的構(gòu)造方法抡谐,保證MyBatis工具類不會(huì)被實(shí)例化 private MyBatisUtils() { } private static SqlSessionFactory initSqlSessionFactory() { if (sqlSessionFactory == null) { synchronized (CLASS_LOCK) { try (InputStream inputStream = Resources.getResourceAsStream(CONFIG)) { sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } } return sqlSessionFactory; } public static SqlSession openSqlSession() { if (sqlSessionFactory == null) { initSqlSessionFactory(); } return sqlSessionFactory.openSession(); }
SqlSession(會(huì)話):用于執(zhí)行SQL并返回結(jié)果(創(chuàng)建數(shù)據(jù)庫(kù)連接+創(chuàng)建數(shù)據(jù)庫(kù)執(zhí)行操作對(duì)象+返回結(jié)果集)
生命周期及其作用域:每個(gè)線程都應(yīng)該有它自己的 SqlSession 實(shí)例裁奇。SqlSession 的實(shí)例不是線程安全的,因此是不能被共享的麦撵,所以它的最佳的作用域是請(qǐng)求或方法作用域刽肠。 絕對(duì)不能將 SqlSession 實(shí)例的引用放在一個(gè)類的靜態(tài)域,甚至一個(gè)類的實(shí)例變量也不行厦坛。 也絕不能將 SqlSession 實(shí)例的引用放在任何類型的托管作用域中五垮,比如 Servlet 框架中的 HttpSession。 如果你現(xiàn)在正在使用一種 Web 框架杜秸,考慮將 SqlSession 放在一個(gè)和 HTTP 請(qǐng)求相似的作用域中放仗。 換句話說,每次收到 HTTP 請(qǐng)求撬碟,就可以打開一個(gè) SqlSession诞挨,返回一個(gè)響應(yīng)后,就關(guān)閉它呢蛤。 這個(gè)關(guān)閉操作很重要惶傻,為了確保每次都能執(zhí)行關(guān)閉操作,你應(yīng)該把這個(gè)關(guān)閉操作放到 try 塊中其障。 下面的示例就是一個(gè)確保 SqlSession 關(guān)閉的標(biāo)準(zhǔn)模式:SqlSession創(chuàng)建代碼示例:
try (SqlSession session = sqlSessionFactory.openSession()) { // 應(yīng)用邏輯代碼 }
-
MyBatis配置
- 配置文件(properties)
主要作用:加載外部的properties文件
配置文件(properties)代碼示例:
<properties resource="jdbc.properties"/>
- 設(shè)置(settings)
主要作用:MyBatis框架運(yùn)行規(guī)則配置
設(shè)置(settings)代碼示例:
<settings> <!-- 開啟日志 --> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
- 類型別名(typeAliases)
主要作用:設(shè)置別名(為實(shí)體類設(shè)置別名),可以分別為每個(gè)實(shí)體類設(shè)置別名银室,也可以統(tǒng)一為package中的每個(gè)實(shí)體類自動(dòng)設(shè)置別名
類型別名(typeAliases)代碼示例:
<typeAliases> <!-- 為每一個(gè)實(shí)體設(shè)置別名 --> <!-- <typeAlias type="com.apesource.entity.Employee" alias="Employee"/> <typeAlias type="com.apesource.entity.Order" alias="Order"/> --> <!-- 設(shè)置實(shí)體類包,為該package中的每個(gè)實(shí)體類自動(dòng)設(shè)置別名 --> <package name="com.apesource.entity"/> </typeAliases>
- 環(huán)境配置(environments)
主要作用:元素體中包含了事務(wù)管理和連接池的配置
環(huán)境配置(environments)代碼示例:
<environments default="development"> <!-- 環(huán)境(開發(fā)) --> <environment id="development"> <!-- 事務(wù)管理器:采用JDBC事務(wù) --> <transactionManager type="JDBC" /> <!-- 數(shù)據(jù)源(數(shù)據(jù)庫(kù)連接池) --> <!-- type設(shè)置為pooled,啟動(dòng)數(shù)據(jù)庫(kù)連接池 --> <dataSource type="POOLED"> <!-- 數(shù)據(jù)庫(kù)連接參數(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)
主要作用:包含了一組映射器(mapper)励翼,這些映射器的 XML 映射文件包含了 SQL 代碼和映射定義信息
映射器(mappers)代碼示例:
<mappers> <!-- SQL映射文件 --> <mapper resource="com/apesource/dao/mapper/AnswerRecordMapper.xml" /> </mappers>
-
MyBatis XML 映射器
1.常用節(jié)點(diǎn)作用總結(jié)
- select:映射select查詢SQL語句
- update:映射update修改SQL語句
- delete:映射delete刪除SQL語句
- insert:映射insert增加SQL語句
2.常用屬性作用總結(jié)
- id 屬性:為當(dāng)前映射的SQL語句進(jìn)行命名蜈敢,id應(yīng)該與xxxMapper接口下的方法名一致
- resultType 屬性:設(shè)置查詢結(jié)果使用的類型名稱,
- parameterType 屬性:設(shè)置執(zhí)行操作時(shí)使用的參數(shù)類型
- useGeneratedKeys屬性:設(shè)置為true表示開啟主鍵回填(默認(rèn)為false)
- keyProperty屬性:設(shè)置用于保存主鍵值的屬性名稱
3.常見SQL映射示例
示例1:普通增加
SQL映射配置 <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:批量增加
SQL映射配置 <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:普通刪除
SQL映射配置 <delete id="deleteAnswerRecord"> delete from answer_record where record_id = #{id} </delete>
接口方法定義 int deleteAnswerRecord(@Param("id")int recordId);
示例4:批量刪除
SQL映射配置 <delete id="deleteAnswerRecordBatch" parameterType="list"> DELETE FROM answer_record WHERE record_id IN <foreach collection="list" item="rid" separator="," open="(" close=")"> #{rid} </foreach> </delete>
接口方法定義 int deleteAnswerRecordBatch(List<Integer> recordIdList);
示例5:動(dòng)態(tài)修改
SQL映射配置 <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:動(dòng)態(tài)查詢
SQL映射配置 <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 condition);
示例7:查詢結(jié)果封裝為Map
SQL映射配置 <select id="countAnswerRecordDataByRespondent" resultType="map"> SELECT count(record_id) as total, (SELECT count(record_id) FROM answer_record WHERE respondent = #{name} AND right_answer = submit_answer ) as right_count, (SELECT count(record_id) FROM answer_record WHERE respondent = #{name} AND right_answer != submit_answer ) as fail_count FROM answer_record WHERE respondent = #{name} </select>
接口方法定義 Map<String,Integer> countAnswerRecordDataByRespondent(@Param("name") String respondent);