MyBatis連接池的深入和動(dòng)態(tài)SQL詳解
一,Mybatis 連接池與事務(wù)深入
1.1 Mybatis 的連接池技術(shù)
Mybatis 中連接池技術(shù),它采用的是自己的連接池技術(shù)。在 Mybatis 的 SqlMapConfig.xml 配置文件中,通過(guò)來(lái)實(shí)現(xiàn) Mybatis 中連接池的配置。
1.1.1 Mybatis 連接池的分類
在 Mybatis 中我們將它的數(shù)據(jù)源 dataSource 分為以下幾類:
可以看出 Mybatis 將它自己的數(shù)據(jù)源分為三類:
UNPOOLED
不使用連接池的數(shù)據(jù)源POOLED
使用連接池的數(shù)據(jù)源JNDI
使用 JNDI 實(shí)現(xiàn)的數(shù)據(jù)源
具體結(jié)構(gòu)如下:
相應(yīng)地,MyBatis 內(nèi)部分別定義了實(shí)現(xiàn)了 java.sql.DataSource 接口的 UnpooledDataSource,PooledDataSource 類來(lái)表示 UNPOOLED、POOLED 類型的數(shù)據(jù)源。
在這三種數(shù)據(jù)源中,我們一般采用的是 POOLED 數(shù)據(jù)源(很多時(shí)候我們所說(shuō)的數(shù)據(jù)源就是為了更好的管理數(shù)據(jù)庫(kù)連接,也就是我們所說(shuō)的連接池技術(shù))。
1.1.2 Mybatis 中數(shù)據(jù)源的配置
MyBatis 在初始化時(shí),根據(jù)的 type 屬性來(lái)創(chuàng)建相應(yīng)類型的的數(shù)據(jù)源 DataSource,即:
- type=”POOLED”:MyBatis 會(huì)創(chuàng)建 PooledDataSource 實(shí)例
- type=”UNPOOLED” : MyBatis 會(huì)創(chuàng)建 UnpooledDataSource 實(shí)例
- type=”JNDI”:MyBatis 會(huì)從 JNDI 服務(wù)上查找 DataSource 實(shí)例,然后返回使用
我們的數(shù)據(jù)源配置就是在 SqlMapConfig.xml 文件中,具體配置如下:
<!-- 配置數(shù)據(jù)源(連接池)信息 -->? <dataSource type="POOLED">? ?? ?<property name="driver" value="${jdbc.driver}"/> ?? ?<property name="url" value="${jdbc.url}"/> ?? ?<property name="username" value="${jdbc.username}"/> ?? ?<property name="password" value="${jdbc.password}"/> </dataSource>
1.2 Mybatis 的事務(wù)控制
1.2.1 JDBC 中事務(wù)的回顧
在 JDBC 中我們可以通過(guò)手動(dòng)方式將事務(wù)的提交改為手動(dòng)方式,通過(guò) setAutoCommit()方法就可以調(diào)整。
通過(guò) JDK 文檔,我們找到該方法如下:
那么我們的 Mybatis 框架因?yàn)槭菍?duì) JDBC 的封裝,所以 Mybatis 框架的事務(wù)控制方式,本身也是用 JDBC 的setAutoCommit()方法來(lái)設(shè)置事務(wù)提交方式的。
1.2.2 Mybatis 中事務(wù)提交方式
Mybatis 中事務(wù)的提交方式,本質(zhì)上就是調(diào)用 JDBC 的 setAutoCommit()來(lái)實(shí)現(xiàn)事務(wù)控制。
我們運(yùn)行之前所寫的代碼:
@Test public void testSaveUser() throws Exception { User user = new User(); user.setUsername("mybatis user09"); //6.執(zhí)行操作 int res = userDao.saveUser(user); System.out.println(res); System.out.println(user.getId()); } @Before//在測(cè)試方法執(zhí)行之前執(zhí)行 public void init()throws Exception { //1.讀取配置文件 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.創(chuàng)建構(gòu)建者對(duì)象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //3.創(chuàng)建 SqlSession 工廠對(duì)象 factory = builder.build(in); //4.創(chuàng)建 SqlSession 對(duì)象 session = factory.openSession(); //5.創(chuàng)建 Dao 的代理對(duì)象 userDao = session.getMapper(IUserDao.class); } @After//在測(cè)試方法執(zhí)行完成之后執(zhí)行 public void destroy() throws Exception{ //7.提交事務(wù) session.commit(); //8.釋放資源 session.close(); in.close(); }
默認(rèn) setAutoCommit()方法,在執(zhí)行時(shí)它的值被設(shè)置為 false 了,所以我們?cè)?CUD 操作中,必須通過(guò) sqlSession.commit()方法來(lái)執(zhí)行提交操作。
1.2.3 Mybatis 自動(dòng)提交事務(wù)的設(shè)置
通過(guò)上面的研究和分析,現(xiàn)在我們一起思考,為什么 CUD 過(guò)程中必須使用 sqlSession.commit()提交事務(wù)?主要原因就是在連接池中取出的連接,都會(huì)將調(diào)用 connection.setAutoCommit(false)方法,這樣我們就必須使用 sqlSession.commit()方法,相當(dāng)于使用了 JDBC 中的 connection.commit()方法實(shí)現(xiàn)事務(wù)提交。
明白這一點(diǎn)后,我們現(xiàn)在一起嘗試不進(jìn)行手動(dòng)提交,一樣實(shí)現(xiàn) CUD 操作。
@Before//在測(cè)試方法執(zhí)行之前執(zhí)行 public void init()throws Exception { //1.讀取配置文件 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.創(chuàng)建構(gòu)建者對(duì)象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //3.創(chuàng)建 SqlSession 工廠對(duì)象 factory = builder.build(in); //4.創(chuàng)建 SqlSession 對(duì)象 **session = factory.openSession(true);** //5.創(chuàng)建 Dao 的代理對(duì)象 userDao = session.getMapper(IUserDao.class); } @After//在測(cè)試方法執(zhí)行完成之后執(zhí)行 public void destroy() throws Exception{ //7.釋放資源 session.close(); in.close(); }
事務(wù)就設(shè)置為自動(dòng)提交了,同樣可以實(shí)現(xiàn)CUD操作時(shí)記錄的保存。雖然這也是一種方式,但就編程而言,設(shè)置為自動(dòng)提交方式為 false 再根據(jù)情況決定是否進(jìn)行提交,這種方式更常用。因?yàn)槲覀兛梢愿鶕?jù)業(yè)務(wù)情況來(lái)決定提交是否進(jìn)行提交。
二.Mybatis 的動(dòng)態(tài) SQL 語(yǔ)句
Mybatis 的映射文件中,前面我們的 SQL 都是比較簡(jiǎn)單的,有些時(shí)候業(yè)務(wù)邏輯復(fù)雜時(shí),我們的 SQL 是動(dòng)態(tài)變化的,此時(shí)在前面的學(xué)習(xí)中我們的 SQL 就不能滿足要求了。
參考的官方文檔,描述如下:
2.1 動(dòng)態(tài) SQL 之標(biāo)簽
我們根據(jù)實(shí)體類的不同取值,使用不同的 SQL 語(yǔ)句來(lái)進(jìn)行查詢。比如在 id 如果不為空時(shí)可以根據(jù) id 查詢,如果 username 不同空時(shí)還要加入用戶名作為條件。這種情況在我們的多條件組合查詢中經(jīng)常會(huì)碰到。
2.1.1 持久層 Dao 接口
/** * 根據(jù)用戶信息,查詢用戶列表 * @param user * @return */ List<User> findByUser(User user);
2.1.2 持久層 Dao 映射配置
<select id="findByUser" resultType="user" parameterType="user"> select * from user where 1=1 <if test="username!=null and username != '' "> and username like #{username} </if> <if test="address != null"> and address like #{address} </if> </select>
注意:<if>標(biāo)簽的 test 屬性中寫的是對(duì)象的屬性名,如果是包裝類的對(duì)象要使用 OGNL 表達(dá)式的寫法。
另外要注意 where 1=1 的作用~!
2.1.3 測(cè)試
@Test public void testFindByUser() { User u = new User(); u.setUsername("%王%"); u.setAddress("%順義%"); //6.執(zhí)行操作 List<User> users = userDao.findByUser(u); for(User user : users) { System.out.println(user); } }
2.2 動(dòng)態(tài) SQL 之標(biāo)簽
為了簡(jiǎn)化上面 where 1=1 的條件拼裝,我們可以采用標(biāo)簽來(lái)簡(jiǎn)化開發(fā)。
2.2.1 持久層 Dao 映射配置
<!-- 根據(jù)用戶信息查詢 --> <select id="findByUser" resultType="user" parameterType="user"> <include refid="defaultSql"> </include> <where> <if test="username!=null and username != '' "> and username like #{username} </if> <if test="address != null"> and address like #{address} </if> </where> </select>
2.3 動(dòng)態(tài)標(biāo)簽之標(biāo)簽
需求
傳入多個(gè) id 查詢用戶信息,用下邊兩個(gè) sql 實(shí)現(xiàn):
SELECT * FROM USERS WHERE username LIKE ‘%張%' AND (id =10 OR id =89 OR id=16) SELECT * FROM USERS WHERE username LIKE ‘%張%' AND id IN (10,89,16)
這樣我們?cè)谶M(jìn)行范圍查詢時(shí),就要將一個(gè)集合中的值,作為參數(shù)動(dòng)態(tài)添加進(jìn)來(lái)。
這樣我們將如何進(jìn)行參數(shù)的傳遞?
2.3.1 在 QueryVo 中加入一個(gè) List 集合用于封裝參數(shù)
/** * * <p>Title: QueryVo</p> * <p>Description: 查詢的條件</p> * <p>Company: http://www.itheima.com/ </p> */ public class QueryVo implements Serializable { private List<Integer> ids; public List<Integer> getIds() { return ids; } public void setIds(List<Integer> ids) { this.ids = ids; } }
2.3.2 持久層 Dao 接口
/** * 根據(jù) id 集合查詢用戶 * @param vo * @return */ List<User> findInIds(QueryVo vo);
2.3.3 持久層 Dao 映射配置
<!-- 查詢所有用戶在 id 的集合之中 --> ?<select id="findInIds" resultType="user" parameterType="queryvo"> <!-- select * from user where id in (1,2,3,4,5); --> ?<include refid="defaultSql"></include>? ?<where> ? ? ? ? ? ? <if test="list != null and list.size() > 0"> ? ? ? ? ? ? ? ? <foreach collection="list" open="id in ( " close=")" item="uid" ? ? ? ? ? ? ? ? ? ? ? ? ?separator=","> ? ? ? ? ? ? ? ? ? ? #{uid} ? ? ? ? ? ? ? ? </foreach> ? ? ? ? ? ? </if> ? ? ? ? </where> </select>
SQL 語(yǔ)句:
select 字段 from user where id in (?)
<foreach>標(biāo)簽用于遍歷集合,它的屬性:
collection
:代表要遍歷的集合元素,注意編寫時(shí)不要寫#{}open
:代表語(yǔ)句的開始部分close
:代表結(jié)束部分item
:代表遍歷集合的每個(gè)元素,生成的變量名sperator
:代表分隔符
2.3.4 編寫測(cè)試方法
@Test public void testFindInIds() { QueryVo vo = new QueryVo(); List<Integer> ids = new ArrayList<Integer>(); ids.add(41); ids.add(42); ids.add(43); ids.add(46); ids.add(57); vo.setIds(ids); //6.執(zhí)行操作 List<User> users = userDao.findInIds(vo); for(User user : users) { System.out.println(user); } }
2.4 Mybatis 中簡(jiǎn)化編寫的 SQL 片段
Sql 中可將重復(fù)的 sql 提取出來(lái),使用時(shí)用 include 引用即可,最終達(dá)到 sql 重用的目的。
2.4.1 定義代碼片段
<!-- 抽取重復(fù)的語(yǔ)句代碼片段 --> <sql id="defaultSql"> select * from user </sql>
2.4.2 引用代碼片段
<!-- 配置查詢所有操作 --> <select id="findAll" resultType="user"> <include refid="defaultSql"></include> </select> <!-- 根據(jù) id 查詢 --> <select id="findById" resultType="UsEr" parameterType="int"> <include refid="defaultSql"></include> where id = #{uid} </select>
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Mybatis在注解上如何實(shí)現(xiàn)動(dòng)態(tài)SQL
- Mybatis超級(jí)強(qiáng)大的動(dòng)態(tài)SQL語(yǔ)句大全
- MyBatis深入解讀動(dòng)態(tài)SQL的實(shí)現(xiàn)
- MyBatis?超詳細(xì)講解動(dòng)態(tài)SQL的實(shí)現(xiàn)
- 關(guān)于mybatis遇到Integer類型的參數(shù)時(shí)動(dòng)態(tài)sql需要注意條件
- mybatis的動(dòng)態(tài)SQL以及連接池詳解
- MyBatis動(dòng)態(tài)SQL如何實(shí)現(xiàn)前端指定返回字段
- 一篇文章帶你了解mybatis的動(dòng)態(tài)SQL
- Mybatis詳解動(dòng)態(tài)SQL以及單表多表查詢的應(yīng)用
相關(guān)文章
Maven實(shí)現(xiàn)項(xiàng)目構(gòu)建工具
本文主要介紹了Maven實(shí)現(xiàn)項(xiàng)目構(gòu)建工具,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Java數(shù)據(jù)結(jié)構(gòu)二叉樹難點(diǎn)解析
樹是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹中稱為結(jié)點(diǎn))按分支關(guān)系組織起來(lái)的結(jié)構(gòu),很象自然界中的樹那樣。樹結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會(huì)的族譜和各種社會(huì)組織機(jī)構(gòu)都可用樹形象表示2021-10-10Java程序中實(shí)現(xiàn)調(diào)用Python腳本的方法詳解
這篇文章主要介紹了Java程序中實(shí)現(xiàn)調(diào)用Python腳本的方法,結(jié)合實(shí)例形式分析了eclipse環(huán)境中使用Java調(diào)用Python腳本的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-03-03一文詳解Java如何創(chuàng)建和銷毀對(duì)象
Java由Sun Microsystems發(fā)明并在1995年發(fā)布,是世界上使用最廣泛的編程語(yǔ)言之一。本文主要和大家介紹一下Java是如何創(chuàng)建和銷毀對(duì)象的,希望對(duì)大家有所幫助2022-11-11Java找出兩個(gè)大數(shù)據(jù)量List集合中的不同元素的方法總結(jié)
本文將帶大家了解如何快速的找出兩個(gè)相似度非常高的List集合里的不同元素。主要通過(guò)Java API、List集合雙層遍歷比較不同、借助Map集合查找三種方式,需要的可以參考一下2022-10-10簡(jiǎn)單了解Java關(guān)鍵字throw和throws的區(qū)別
這篇文章主要介紹了簡(jiǎn)單了解Java關(guān)鍵字throw和throws的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Java利用POI實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel表格示例代碼
最近工作中遇到一個(gè)需求,是需要導(dǎo)出數(shù)據(jù)到Excel表格里,所以寫個(gè)Demo測(cè)試一下,還是比較簡(jiǎn)單的,現(xiàn)在分享給大家,有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-10-10springboot程序啟動(dòng)慢-未配置hostname的解決
這篇文章主要介紹了springboot程序啟動(dòng)慢-未配置hostname的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08