Mybatis複習整理
阿新 • • 發佈:2018-12-31
Mybatis 知識點整理,有些問題不是不會,也不是不懂,只是沒有見過!
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="mapper.BlogMapper"> <!--單獨的cache作用: 所有的對映檔案裡的select都會被快取 所有的對映檔案裡的insert、update和delete語句執行都會被清空快取 快取使用最近最少使用演算法LRU來回收 快取不會被設定的時間所清空 每個快取可以儲存1024個列表或物件的引用(不管查詢方法返回的是什麼) 快取將作為“讀/寫”快取,意味著檢索的物件不是共享裡的且可以被呼叫者安全的修改,而不會被其他呼叫者或執行緒干擾 --> <cache/> <!-- eviction:快取回收演算法 LRU:最近最少使用:移出最近最長事件內都沒有被使用的物件 FIFO:先進先出:移出最先進入快取的物件 SOFI:軟引用:基於垃圾回收機制和軟引用規則來移除物件(空間記憶體不足時才回收物件) WEAK:弱引用:基於垃圾回收機制和弱引用規則來移除物件(垃圾回收器掃描到才進行回收) flushInterval:重新整理時間間隔? size:快取物件的大小以及環境中的可用記憶體空間 readOnly:只讀快取將對所有呼叫者返回同一個例項。 因此這些物件都不能被修改,這可以極大的提高效能。 可寫的快取將通過序列化來返回一個快取物件的拷貝。這會比較慢,但是比較安全。所以預設值都是false --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" /> <!-- 引用另外一個名稱空間配置的快取 --> <cache-ref namespace=""/> <!-- 使用自定義快取==>如果想實現自定義快取,必須實現org.mybatis.cache.Cache這個介面 可以通過自己的快取實現來完全重寫快取行為,或者通過建立第三方快取解決方案的介面卡 --> <cache type="something.MyBlogCache"> <!-- 要配置自己的快取,簡單的新增一個公共的JavaBeans屬性到快取實現中,然後通過cache元素設定屬性進行傳遞 --> <property name="cacheFile" value="/tmp/my-blog-cache.tmp"/> </cache> <!-- 描述如何從資料庫結果集裡面載入物件 --> <resultMap type="Blog" id="blog"></resultMap> <!-- 能夠被其他語句重用的sql塊 --> <sql id="columns"> ID as id, AUTHOR as author, TITLE as title, CONTENT as content, CLICKTIMES as clicktimes </sql> <!-- 根據主鍵查詢 --> <select id="selectBlogById" parameterType="int" resultType="Blog"> select <include refid="columns"/> from Blog where id = #{id} </select> <!--parameterType:引數型別 resultType:返回值型別的具體類名 resultMap:返回值型別的結果集 flushCache:如果為true,每次該語句呼叫都會清空快取 useCache:如果為true,則該語句的結果集將被快取 timeout:請求超時時間 fetchSize:從資料庫獲得記錄條數 statementType:STATEMENT/~PREPARED/CALLABLE resultSetType:FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE --> <select id="exampleSelect" parameterType="引數型別" resultType="Blog" resultMap="Blog" flushCache="true" useCache="true" timeout="1000" fetchSize="256" statementType="STATEMENT" resultSetType="FORWARD_ONLY"></select> <!-- useGeneratedKeys : 資料庫自動生成主鍵 keyProperty : 主鍵欄位 --> <insert id="exampleInsert" useGeneratedKeys="true" keyProperty="id"></insert> <insert id="add" parameterType="Blog"> insert into blog (id,author,title,content) values (#{id} , #{author} , #{title} , #{content} , #{clicktimes}) </insert> <!-- 自定義資料型別轉換,並指定轉換類 numericScale:指定小數位精度 --> <insert id="add2" parameterType="Blog"> insert into blog (id,author,title,content) values ( #{id , javaType=int , jdbcType=NUMERIC , typeHandler=ExampleTypeHandler } , #{author} , #{title} , #{content}, #{clicktimes,javaType=int,jdbcType=NUMERIC,numericScale=0}) </insert> <!-- 這種申明結果集的方法可以解決列名不匹配的問題,和columns的效果相同 --> <resultMap type="Blog" id="blogs"> <!-- 各屬性解釋 property:對映資料庫列的欄位或屬性(對應javaBean) column:資料庫中的列名或者列標籤的別名(對應資料庫列) javaType:完整的java類名或者列標籤名 jdbcType:資料庫中該列的欄位型別(這個屬性在insert、update或delete的時候針對允許空的列有用) typeHandler:資料型別處理器 --> <id column="ID" property="id" /> <result column="AUTHOR" property="author"/> <result column="TITLE" property="title"/> <result column="CONTENT" property="content"/> <result column="CLICKTIMES" property="clicktimes"/> </resultMap> <!-- 一個多表關聯的複合查詢 --> <select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap"> select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio, A.favourite_section as author_favourite_section, P.id as post_id, P.blog_id as post_blog_id, P.author_id as post_author_id, P.created_on as post_created_on, P.section as post_section, P.subject as post_subject, P.draft as draft, P.body as post_body, C.id as comment_id, C.post_id as comment_post_id, C.name as comment_name, C.comment as comment_text, T.id as tag_id, T.name as tag_name from Blog B left outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_id left outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.id left outer join Tag T on PT.tag_id = T.id where B.id = #{id} </select> <!-- 將上一步的多表關聯查詢對映到一個智慧的物件模型中 --> <resultMap id="detailedBlogResultMap" type="Blog"> <!-- 例項化的時候通過構造器將結果注入到類中 --> <constructor> <!-- idArg:將結果集標記為ID,以方便全域性呼叫 arg:注入構造器的結果集 使用構造器將主表資料注入類中 --> <idArg column="blog_id" javaType="int"/> </constructor> <!-- 注入一個欄位或者javaBean屬性的結果 主表資料單獨用result申明 --> <result property="title" column="blog_title"/> <!-- 複雜型別聯合:許多查詢結果合成這個型別 使用blog_author_id外來鍵關聯author表中需要查詢的欄位 --> <association property="author" column="blog_author_id" javaType=" Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> <result property="password" column="author_password"/> <result property="email" column="author_email"/> <result property="bio" column="author_bio"/> <result property="favouriteSection" column="author_favourite_section"/> </association> <!-- 複雜型別集合 使用post_id外來鍵關聯post表中需要的欄位 --> <collection property="posts" ofType="Post"> <!-- post.id --> <id property="id" column="post_id"/> <!-- post.subject --> <result property="subject" column="post_subject"/> <!-- post與author表關聯的欄位 --> <association property="author" column="post_author_id" javaType="Author"/> <!-- comment_id作為外來鍵與post關聯,所以申明在post的關聯物件中 --> <collection property="comments" column="post_id" ofType=" Comment"> <id property="id" column="comment_id"/> </collection> <!-- tag_id 作為外來鍵與post關聯 --> <collection property="tags" column="post_id" ofType=" Tag" > <id property="id" column="tag_id"/> </collection> <!-- 使用一個結果值,以確定使用哪個resultMap --> <discriminator javaType="int" column="draft"> <!-- 基於不同的結果對映 --> <case value="1" resultType="DraftPost"/> </discriminator> </collection> </resultMap> <!-- 一對一關聯配置 --> <!-- 使用association和select屬性做巢狀查詢 使用這種配置方法會導致N+1選擇問題的產生 執行單條sql語句獲得一個表的記錄 對獲得的列表中的每條記錄,在執行一次聯合查詢用以載入詳細資訊 這樣會導致成千上萬條sql執行,並非可取 --> <resultMap type="Blog" id="blogResult"> <association property="author" column="blog_author_id" javaType="Author" select="selectAuthor" /> </resultMap> <select id="selectBlog" resultMap="blogResult" parameterType="int"> select * from blog where id = #{id} </select> <select id="selectAuthor" resultMap="author" parameterType="int"> select * from author where id = #{id} </select> <!-- 以上的結果相當於sql: select b.*,a.* from blog b left join author a on b.blog_author_id = a.id where b.id = #{id} --> <!-- 第二種對映結果集的方式 --> <select id="selectBlog" parameterType="int" resultMap="blogResult"> select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio from Blog B left outer join Author A on B.author_id = A.id where B.id = #{id} </select> <resultMap id="blogResult" type="Blog"> <id property="id" column=" blog_id" /> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/> <!-- lable209 --> </resultMap> <!-- 這樣寫便於查詢結果集重用,如果只要用一次的話,直接將resultMap標籤中的內容移動到lable209 --> <resultMap id="authorResult" type="Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> <result property="password" column="author_password"/> <result property="email" column="author_email"/> <result property="bio" column="author_bio"/> </resultMap> <!-- 一對多關聯配置 --> <resultMap id="blogResult" type="Blog"> <collection property="posts" javaType="ArrayList" column="blog_id" ofType="Post" select="selectPostsForBlog"/> </resultMap> <select id="selectBlog" parameterType="int" resultMap="blogResult"> SELECT * FROM BLOG WHERE ID = #{id} </select> <select id="selectPostsForBlog" parameterType="int" resultType="Author"> SELECT * FROM POST WHERE BLOG_ID = #{id} </select> <!-- Discriminator:識別器~switch --> <resultMap id="vehicleResult" type="Vehicle"> <id property="id" column="id" /> <result property="vin" column="vin"/> <result property="year" column="year"/> <result property="make" column="make"/> <result property="model" column="model"/> <result property="color" column="color"/> <discriminator javaType="int" column="vehicle_type"> <!-- 每當匹配中一個case,其餘case將被忽略 --> <case value="1" resultMap="carResult"/> <case value="2" resultMap="truckResult"/> <case value="3" resultMap="vanResult"/> <case value="4" resultMap="suvResult"/> </discriminator> </resultMap> <!-- 動態sql --> <!-- if --> <select id="findBlogTitleLike" parameterType="Blog"> select * from blog where 1=1 <if test="title != null"> and title like #{title} </if> </select> <!-- choose --> <select id="findBlogLike" parameterType="Blog"> select * from blog where 1=1 <choose> <when test="title != null"> and title like #{title} </when> <when test="author != null and author.name != null"> and title like #{author.name} </when> <otherwise> and featured = 1 </otherwise> </choose> </select> <!-- where : 如果第一個條件不滿足,但是第二個條件滿足,則會忽略第二個條件的and --> <select id="findBlogWithWhere" parameterType="Blog"> select * from blog <where> <if test="title != null"> title like #{title} </if> <if test="author != null and author.name != null"> and author like #{author.name} </if> </where> </select> <!-- trim==>where : 使用trim實現where同樣的功能 --> <select id="findBlogWithTrim" parameterType="Blog"> select * from blog <trim prefix="where" prefixOverrides="and/or"> <if test="title != null"> title like #{title} </if> <if test="author != null and author.name != null"> and author like #{author.name} </if> </trim> </select> <!-- set --> <update id="updateWithSet" parameterType="Blog"> update blog <set> <if test="author != null">author = #{author},</if> <if test="content != null">content = #{content}</if> </set> where id = #{id} </update> <!-- trim==>set --> <update id="updateWithTrim" parameterType="Blog"> update blog <trim prefix="set" prefixOverrides=","> <if test="author != null">author = #{author},</if> <if test="content != null">content = #{content}</if> </trim> where id = #{id} </update> <!-- foreach --> <!-- 注意:當傳遞一個集合給mybatis時,mybatis會自動將引數包裝成map並且以名字作為key list==》list,array==》array --> <select id="selectBlogIn"> select * from blog where id in <foreach collection="list" item="item" index="index" open="(" close=")" separator=","> #{item} </foreach> </select> </mapper>
使用註解方式繫結sql
public interface BlogMapper { @Select("select * from Blog where id = #{id}") public Blog selectBlogById(int id); public void update(Blog blog); }
自定義的型別處理器
/** * @author Administrator * 自己的資料型別處理器 */ public class ExampleTypeHandler implements TypeHandler{ @Override public Object getResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public Object getResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } @Override public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, (String) parameter); } }
自定義外掛
@Intercepts( {@Signature(type = Executor.class, method = "update", args = {BlogMapper.class,Object.class})} ) public class ExamplePlugin implements Interceptor{ @Override public Object intercept(Invocation arg0) throws Throwable { return arg0.proceed(); } @Override public Object plugin(Object arg0) { return Plugin.wrap(arg0, this); } @Override public void setProperties(Properties arg0) { } }
自定義ObjectFactory
public class ExampleObjectFactory extends DefaultObjectFactory{ @Override public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } @Override public Object create(Class type) { return super.create(type); } /* 用來配置ExampleObjectFactory * 在初始化ExampleObjectFactory例項後,定義在ExampleObjectFactory元素主體中的屬性會以引數的形式傳遞到此方法中 * @see org.apache.ibatis.reflection.factory.DefaultObjectFactory#setProperties(java.util.Properties) */ @Override public void setProperties(Properties properties) { super.setProperties(properties); } }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入配置檔案 -->
<properties resource="config/config.properties">
<!-- 如果config.properties檔案中有username和password屬性,再次配置將會覆蓋檔案中的值 -->
<property name="username" value="bikeeverywhere"/>
<property name="password" value="bikeeverywhere"/>
</properties>
<!-- 設定和改變Mybatis執行中的行為 -->
<settings>
<!-- 全域性性的啟用或者禁用所有在mapper配置檔案中配置的快取 -->
<setting name="cacheEnable" value="true"/>
<!-- 全域性性的啟用或禁用延遲載入。當禁用時,所有關聯的配置都會立即載入 -->
<setting name="lazyLoadingEnable" value="true"/>
<!-- 當啟用時,一個有延遲載入屬性的物件的任何一個延遲屬性被載入時,該物件的所有的屬性都會被載入。
否則所有屬性都是按需載入 -->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- 允許或禁止從單一的語句返回多個結果集(需要驅動程式相容) -->
<setting name="multipleResultSetsEnable" value="true"/>
<!-- 使用列的標籤而不是列的名稱 -->
<setting name="userColumnLable" value="true"/>
<!-- 允許JDBC自動生成主鍵(需要驅動程式相容) -->
<setting name="userGeneratedKeys" value="false"/>
<!-- 指定mybatis是否以及如何自動將列對映到欄位/屬性
partial:自動對映簡單的、非巢狀的結果集
full:自動對映任何複雜的(巢狀或非巢狀的結果集) -->
<setting name="autoMappingBehavior" value="partial"/>
<!-- 配置預設的執行器(executor)
simple:簡單的執行器
reuse:重用prepared statements的執行器
batch:重用statements並且進行批量更新的執行器 -->
<setting name="defaultExecutorType" value="simple"/>
<!-- 設定資料庫查詢超時時間 -->
<setting name="defaultStatementTimeout" value="10000"/>
</settings>
<!-- 實體類設定別名 -->
<typeAliases>
<typeAlias type="entity.Author" alias="author"/>
<typeAlias type="entity.Blog" alias="blog"/>
<typeAlias type="entity.Comment" alias="comment"/>
<typeAlias type="entity.Post" alias="post"/>
<typeAlias type="entity.Section" alias="section"/>
<typeAlias type="entity.Tag" alias="tag"/>
</typeAliases>
<!-- 資料庫資料與java資料做型別轉換使用 -->
<typeHandlers>
<!-- 可以重寫型別處理器,或者建立自己的型別處理器去處理沒有被支援的或非標準的型別
要做到這一點,只要實現TypeHandler介面(org.mybatis.type),
並且將TypeHandler類對映到java型別和可選的JDBC型別即可 -->
<!-- 指定自己的資料型別轉換,將VARCHAR轉成String -->
<typeHandler handler="handler.ExampleTypeHandler" javaType="String" jdbcType="VARCHAR"/>
</typeHandlers>
<!-- Mybatis每次建立一個結果物件都會使用objectFactory例項。
使用預設的objectFactory和使用預設的建構函式來例項化目標類並沒有什麼區別 -->
<objectFactory type="factory.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>
<!-- 自定義外掛,在對映語句執行的某個時間點攔截方法呼叫 -->
<plugins>
<!-- 允許攔截的方法 -->
<!-- Executor:
query,update,flushStatements,commit,rollback,getTransaction,close,isClosed -->
<!-- ParameterHandler:
getParameterObject,setParameters -->
<!-- ResultSetHandler:
handlerResultSets,handlerOutputParameters -->
<!-- StatementHandler:
prepare,parameterize,batch,update,query -->
<plugin interceptor="plugin.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
<!-- 配置執行環境
可能出現一個sql語句向兩個資料庫發起請求,所以要配置多個數據源
但是:每個sqlsessionFactory只能選擇一個執行環境
所以如果連線多個數據庫,就要配置多個sqlsessionFactory-->
<environments default="development">
<environment id="development">
<!-- 事物管理:JDBC/MANAGED -->
<!-- JDBC:直接使用JDBC的提交和回滾功能,它依賴於從資料來源獲得連線來管理事物的生命週期 -->
<transactionManager type="JDBC" />
<!-- 只有使用了延遲載入才需要資料來源? -->
<!-- Mybatis內建了3種資料來源型別 -->
<!--UNPOOLED:每次需要的時候簡單的開啟和關閉連線
雖然有點慢,但是對於不需要立即響應的簡單的應用來說,不失為一種好的選擇-->
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="product">
<!-- MANAGED:什麼都不做,而是讓容器來管理事務的生命週期
如果需要通過關閉連線來停止事務,將屬性closeConnection設定為false-->
<transactionManager type="MANAGED" >
<property name="closeConnection" value="false"/>
</transactionManager>
<!-- POOLED:這個資料來源的實現快取了JDBC連線物件(池化技術) -->
<dataSource type="POOLED">
<property name="driver" value="${driver1}"/>
<property name="url" value="${url1}"/>
<property name="username" value="${username1}"/>
<property name="password" value="${password1}"/>
<!-- 池化技術相關引數設定 -->
<!-- 最大使用數量,預設為10 -->
<property name="poolMaximumActiveConnections" value="10"/>
<!-- 在特定時間內空閒的連線數(當沒有人訪問的時候也保持一定數量的連線) -->
<property name="poolMaximumIdleConnections" value="5"/>
<!-- 在連線池被強行返回前,一個連線能夠“檢出”的總時間,預設是20000ms -->
<property name="poolMaximumCheckoutTime" value="20000"/>
<!-- 這是一個比較底層的設定,如果連線佔用了很長的時間,能夠給連線池一個去列印日誌的機會,並嘗試重新連線,預設是20000ms -->
<property name="poolTimeToWait" value="2000"/>
<!-- ping query 是傳送給資料庫的ping資訊,測試資料庫是否良好和是否準備好了接受請求
預設值是 NO PING QUERY SET,讓大部分資料庫都不適用ping,返回一個友好的錯誤資訊 -->
<property name="poolPingQuery" value=""/>
<!-- ping query 的開關,如果允許,需要設定一條可用的(最高效的)sql語句來設定pingquery的值 -->
<property name="poolPingEnable" value="false"/>
<!-- 這個屬性設定ping query的間隔時間。通常設定為資料庫連線的超時時間,避免不必要的ping
只有poolPingEnable=true時才生效 -->
<property name="poolPingConnectionsNotUsedFor" value="0"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC" />
<dataSource type="JNDI">
<property name="driver" value="${driver2}"/>
<property name="url" value="${url2}"/>
<property name="username" value="${username2}"/>
<property name="password" value="${password2}"/>
<!-- 這個屬性用來從InitalContext中查詢一個上下文 -->
<property name="initial_context" value=""/>
<!-- 這個屬性是引用一個能夠被找到的資料來源例項的上下文路徑
它會查詢根據 initial_context 從 initialContext 中搜尋返回的上下文。
或者在initial_context 沒有提供的情況下直接在 InitialContext 中進行查詢。 -->
<property name="data_source" value=""/>
</dataSource>
</environment>
</environments>
<!-- 此處用於配置sql對映 -->
<mappers>
<!-- 引入根目錄下的配置檔案 -->
<mapper resource="mapper/BlogMapper.xml"/>
<!-- 使用資源路徑引入 -->
<mapper url="file:///var/sqlmaps/AuthorMapper.xml"/>
</mappers>
</configuration>