在實際開發中,都會使用鏈接池,由於它能夠減小獲取鏈接縮消耗的時間。所謂鏈接池,就是存儲數據庫鏈接的容器。鏈接池中存儲必定數量的數據庫鏈接,當線程須要使用到鏈接時,就從鏈接池中獲取數據庫鏈接,線程使用完數據庫鏈接會還回鏈接池中。java
鏈接池:其實就是一個集合對象,該集合必須是線程安全的;並且線程必須實現對列,知足 」 先進先出 「 的特性。web
三種配置方式sql
配置位置:MyBatis主配置文件中,<dataSource>
元素;type屬性的值表示採用何種鏈接池;數據庫
POOLED:採用傳統的 javax.sql.DataSource
接口規範中的鏈接池,MyBatis中有該規範的實現;緩存
UNPOOLED:採用傳統獲取數據庫鏈接的方式,雖然實現了 javax.sql.DataSource
接口,但沒有鏈接池的思想——即須要時才建立數據庫鏈接;安全
JNDI:採用服務器提供的 JNDI 技術實現,來獲取 DataSource 對象,不一樣服務器的拿到的 DataSource 對象是不一樣的;服務器
注意:不是 web 或 maven 工程,是不能使用的。Tomcat 服務器中,採用鏈接池是 dbcp 鏈接池。session
什麼是事務?mybatis
事物的四大特性ACIDapp
不考慮隔離性會產生的3個問題
解決方法:四種隔離級別
MyBatis 中的事務控制默認沒有開啓自動提交,可使用 SqlSessionFactory.opensession(boolean autoCommit)
方法建立設置是否開啓自動提交事務的 Sqlsession
對象。但有一點須要注意的是:開啓了自動提交事務,MyBatis是對一個數據庫操做(並不是多個)進行事務提交。沒有開啓自動提交事務時,是使用 SqlSession
對象的 commit 方法 和 rollback 方法進行事務的提交的回滾。
單參數——定義傳入參數的類型,能夠是基本類型、引用類型、映射;
多參數——須要在接口類中的抽象方法的參數前使用註解 @Param("")
指定參數名;
<!--接口方法:User findUser(String username, String password); --> <select id="findUser" resultType="*.user"> select * from user where username=#{0} and password=#{1} </select>
<!--User findUser(@Param("username") String username, @Param("password") String password);--> <select id="findUser" resultType="user"> select * from user where username=#{username} and password=#{password} </select>
if 標籤:用於進行條件判斷, test 屬性用於指定判斷條件。爲了拼接條件, 在 SQL 語句後強行添加 1=1 的恆成立條件
<select id="sel" resultType="user"> select * from user where 1=1 <if test="username != null and username != ''"> and username=#{username} </if> <if test="password != null and password != ''"> and password=#{password} </if> </select>
choose(when otherwise)標籤:這是一套標籤, 功能相似於 switch...case...
<select id="sel" resultType="user"> select * from user <where> <choose> <when test="username != null and username != ''"> and username = #{username} </when> <when test="password != null and password != ''"> and password = #{password} </when> <otherwise> and 1=1 </otherwise> </choose> </where> </select>
用於管理 where 子句,有以下功能:
<select id="sel" resultType="user"> select * from user <where> <if test="username != null and username != ''"> and username=#{username} </if> <if test="password != null and password != ''"> and password=#{password} </if> </where> </select>
用於維護 update 語句中的 set 子句,功能以下:
<update id="updUser" parameterType="user"> update user <set> id=#{id}, <!-- 防止全部條件不成立時的語法錯誤 --> <if test="username != null and username != ''"> username=#{username}, </if> <if test="password != null and password != ''"> password=#{password}, </if> </set> where id=#{id} </update>
trim() 標籤:用於在先後添加或刪除一些內容
<update id="updUser" parameterType="user"> update user <!-- prefix: 前綴, 表示向前面添加內容 prefixOverrides: 從前面刪除內容 suffix: 後綴, 表示向後面添加內容 suffixOverrides: 從後面刪除內容 --> <trim prefix="set" prefixOverrides="user" suffix="hahah" suffixOverrides=","> username=#{username}, </trim> where id=#{id} </update>
bind標籤:用於對數據進行再加工。好比,模糊查詢中對數據的拼接
<select id="sel" resultType="user"> select * from user <where> <if test="username!=null and username!=''"> <bind name="username" value="'%' + username + '%'"/> and username like #{username} </if> </where> </select>
foreach標籤:用於在 SQL 語句中遍歷集合參數, 在 in 查詢中使用
<select id="selIn" parameterType="list" resultType="user"> select * from user <where> <foreach collection="list" open="id in (" separator="," close=")" item="item"> #{item} </foreach> </where> </select>
sql/include標籤: <sql>
用於提取 SQL 語句, <include>
用於引用 SQL 語句
<sql id="mySql"> select * from user </sql> <select id="selIn" parameterType="list" resultType="user"> <include refid="mySql"/> from t_user where id in <foreach collection="list" open="(" separator="," close=")" item="item"> #{item} </foreach> </select>
問題:在一對多中,當咱們有一個用戶,它有100個帳戶。1)當查詢用戶時,要不要把關聯的帳戶查出來?2)當查詢帳戶時,要不要把關聯的用戶查出來?
一對多的關係中,Java 中是使用集合來存儲多的一方,若是,僅僅只想查詢用戶信息,並不關心其帳戶的信息,這時,若是還將該用戶下的全部帳戶查詢出來,不只影響效率,也佔用內存。
什麼是延時加載(懶加載)?——在真正使用數據時才發起查詢,不使用時不查詢,也就是:按需查詢。
什麼是當即加載?——無論用不用,只要一調用方法,就發起查詢。
什麼時候使用延時加載,什麼時候使用當即加載?——一對多、多對多:一般採用延時加載;多對一,一對一:一般採用當即加載;
在 mapping 配置文件中,配置 resultMap
元素,在須要使用延遲加載的對象使用 <association>
元素或 collection
元素關聯;並經過如下屬性,引用查詢語句和傳遞查詢條件,MyBatis會將查詢結果封裝到延遲加載的對象:
但這尚未啓用懶加載方式。須要啓用懶加載方式,在主配置文件 <settings>
元素中配置如下 setting 子元素:
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
在沒有啓用延遲加載時,MyBatis會加載全部查詢數據;啓用延遲加載時,當延遲加載的對象被調用,纔會加載;
什麼是緩衝?——存儲在內存中的臨時數據;
爲何使用緩衝?——減小和數據庫的交互次數,提升執行效率;
什麼數據能使用緩存,什麼數據不能?
一級緩存和二級緩存
指的是 MyBatis 中 SqlSession 對象的緩存。
當執行查詢以後,查詢結果會同時存入到 SqlSession 提供的一個 Map 區域中;當再次查詢相同的數據時,MyBatis 會先去 Map 區域中查找,沒有找到在執行查詢操做。當 SqlSession 對象消失或清空緩存操做時,一級緩存也就消失了。
如何保證數據庫數據和一級緩存數據保持一致(數據同步)?
若是 sqlSession 執行 commit 操做(執行插入、更新、刪除),會清空 SqlSession 中的一級緩存,這樣作的目的爲了讓緩存中存儲的是最新的信息,避免髒讀。
指的是 MyBatis 中 SqlSessionFactory 對象的緩存,有同一個 SqlSessionFactory 對象建立並共享緩存。
二級緩存的使用步驟
讓 MyBatis 支持二級緩存(在主配置文件中配置);
<settings> <setting name="cacheEnabled" value="true"/> </settings>
讓當前映射文件支持二級緩存(在 mapper 配置文件配置);
<cache/>
讓當前操做支持二級緩存(select 元素中配置)
<select id="findAll"resultMap="user" useCache="true"> select * from class </select>
二級緩存中存放的內容是數據,而不是對象。
當使用註解開發時,相同包名下不能有 mapper 配置文件,會發生配置文件解析衝突錯誤。
@Select()
@Delete()
@Update()
@Insert()
定義屬性名與列名映射
@Results(id="UserMap",value={ @Result(id=true,column="",property=""), @Result(column="",property=""), @Result(column="",property=""), })
引用映射,引用 @Results
中的 ID 值
@ResultMap(value={"UserMap"})
一對一
@Results(id="UserMap",value={ @Result(id=true,column="",property=""), @Result(column="",property=""), @Result(column="",property=""), @Result(column="做爲查詢的列名",property="屬性名", one=@One( select="全限定查詢方法" fetchType=FetchType.EAGER )) })
使用 @One
註解定義查詢方法,根據 column 中的屬性做爲查詢條件,返回一條數據;
LAZY(延遲加載)、EAGER(當即加載)、DEFAULT
;一對多
@Results(id="UserMap",value={ @Result(id=true,column="",property=""), @Result(column="",property=""), @Result(column="",property=""), @Result(column="做爲查詢的列名",property="屬性名", many=@Many( select="全限定查詢方法" fetchType=FetchType.LAZY )) })
在主配置文件中配置開啓二級緩存;
<settings> <setting name="cacheEnabled" value="true"/> </settings>
在接口類級別上使用 @CacheNamespace(blocking= true)
;