Java EE輕量級框架應用實戰(zhàn)-SSM框架(Spring MVC+Spring+MyBatis)(第2版)課件 第5、6章 深入使用MyBatis、初識Spring_第1頁
Java EE輕量級框架應用實戰(zhàn)-SSM框架(Spring MVC+Spring+MyBatis)(第2版)課件 第5、6章 深入使用MyBatis、初識Spring_第2頁
Java EE輕量級框架應用實戰(zhàn)-SSM框架(Spring MVC+Spring+MyBatis)(第2版)課件 第5、6章 深入使用MyBatis、初識Spring_第3頁
Java EE輕量級框架應用實戰(zhàn)-SSM框架(Spring MVC+Spring+MyBatis)(第2版)課件 第5、6章 深入使用MyBatis、初識Spring_第4頁
Java EE輕量級框架應用實戰(zhàn)-SSM框架(Spring MVC+Spring+MyBatis)(第2版)課件 第5、6章 深入使用MyBatis、初識Spring_第5頁
已閱讀5頁,還剩109頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

MyBatis插件的應用——實現分頁MyBatis的緩存機制MyBatis的常用注解第5章

深入使用MyBatis2024/1/29學習目標/Target2

掌握如何使用MyBatis插件實現分頁

熟悉MyBatis的緩存機制

掌握MyBatis的常用注解及其使用方法章節(jié)概述/Summary3通過學習前面介紹的MyBatis的基本用法、關聯映射和動態(tài)SQL語句等重要知識,讀者可以了解到使用MyBatis可以很方便地通過面向對象進行數據庫訪問,本章將介紹一些Web應用程序中的分頁方式,以及合理地利用緩存來加快數據庫的查詢速度,進而有效地提升數據庫性能的方法。前面章節(jié)中介紹的MyBatis的所有配置都是使用XML文件完成的,由于大量XML文件的編寫工作非常煩瑣,因此可以使用MyBatis提供的更加簡便的注解配置。本章將介紹MyBatis的深入使用,內容包括MyBatis插件的應用——實現分頁、MyBatis的緩存機制,以及MyBatis的常用注解。目錄/CONTENTSMyBatis插件的應用——實現分頁MyBatis的常用注解MyBatis的緩存機制4132MyBatis插件的應用

——實現分頁01第5章深入使用MyBatis實現分頁功能6分頁方式分為兩種前端分頁一次性請求數據表格中的所有記錄(Ajax),然后在前端緩存并且計算count和分頁邏輯,一般前端組件(例如dataTable)會提供分頁動作。特點是:簡單,很適合小規(guī)模的web平臺;當數據量大的時候會產生性能問題,在查詢和網絡傳輸的時間會很長。后端分頁在Ajax請求中指定頁碼(pageNum)和每頁的大小(pageSize),后端查詢出當頁的數據返回,前端只負責渲染。特點是:復雜一些;性能瓶頸在MySQL的查詢性能,這個當然可以調優(yōu)解決。一般來說,WEB開發(fā)使用的是這種方式。借助SQL語句進行分頁7通過SQL語句實現分頁也是非常簡單的,只是需要改變我們查詢的語句就能實現了,即在SQL語句后面添加limit分頁語句。簡單來說MySQL對分頁的支持是通過limit子句。請看下面的例子。limit關鍵字的用法是offset是相對于首行的偏移量(首行是0),rows是返回條數。MySQL的分頁功能是基于內存的分頁查出來所有記錄,再按起始位置和頁面容量取出結果。LIMIT[offset,]rows#每頁10條記錄,取第一頁,返回的是前10條記錄select*fromtableAlimit0,10;#每頁10條記錄,取第二頁,返回的是第11條記錄,到第20條記錄select*fromtableAlimit10,10;借助SQL語句進行分頁需求說明:為用戶管理之查詢用戶列表功能增加分頁實現列表結果按照創(chuàng)建時間降序排列分頁-DAO層實現limit(起始位置,頁面容量)查詢用戶列表的方法增加2個參數frompageSize8演示示例:MyBatis分頁功能實現-用戶列表分析publicList<User>getUserList( @Param("userName")StringuserName, @Param("userRole")IntegerroleId,

@Param("from")IntegercurrentPageNo, @Param("pageSize")IntegerpageSize);<!--查詢用戶列表(分頁顯示)--><selectid="getUserList"resultMap="userList"> SELECTu.*,r.roleNameuserRoleName FROMtb_useru,dsscm_roler WHEREu.userRole=r.id <iftest="userRole!=null"> andu.userRole=#{userRole} </if> <iftest="userName!=nullanduserName!=''"> andu.userNamelikeCONCAT('%',#{userName},'%') </if> orderbycreationDateDESClimit#{from},#{pageSize}</select>分頁參數RowBounds9分頁原理通過RowBounds實現分頁和通過數組方式分頁原理差不多,都是一次獲取所有符合條件的數據,然后在內存中對大數據進行操作,實現分頁效果。只是數組分頁需要我們自己去實現分頁邏輯,這里更加簡化而已。RowBounds:在接口中的方法中傳入RowBounds對象。

RowBounds存在問題:一次性從數據庫獲取的數據可能會很多,對內存的消耗很大,可能導致性能變差,甚至引發(fā)內存溢出。以對于大量的數據查詢,它的性能并不佳,此時可以通過分頁插件去處理。適用場景:在數據量很大的情況下,建議還是適用攔截器實現分頁效果。RowBounds建議在數據量相對較小的情況下使用。提示分頁參數RowBounds需求說明:為用戶管理之查詢用戶列表功能增加分頁實現列表結果按照創(chuàng)建時間降序排列10publicList<User>getUserList2( @Param("userName")StringuserName, @Param("userRole")IntegerroleId, RowBoundsrowBounds);<!--查詢用戶列表(分頁顯示--RowBounds)--><selectid="getUserList2"resultType="User"> SELECTu.*,r.roleNameuserRoleName FROMtb_useru,tb_roler WHEREu.userRole=r.id <iftest="userRole!=null"> andu.userRole=#{userRole} </if> <iftest="userName!=nullanduserName!=''"> andu.userNamelikeCONCAT('%',#{userName},'%') </if> orderbycreationDateDESC</select>UserMapper.xml的getUserList查詢SQL語句,不需要limit關鍵字,mappep.xml里面正常配置,不用對rowBounds任何操作。MyBatis的攔截器自動操作rowBounds進行分頁使用PageHelper插件實現分頁11PageHelperPageHelper是一個MyBatis的分頁插件,負責將已經寫好的sql語句,進行分頁加工jar文件pagehelper-4.1.4.jarjsqlparser-1.1.jar使用PageHelper插件實現分頁12PageHelper的配置<!--com.github.pagehelper為PageHelper類所在包名--><plugininterceptor="com.github.pagehelper.PageHelper"><propertyname="dialect"value="mysql"/><!--該參數默認為false--><!--設置為true時,會將RowBounds第一個參數offset當成pageNum頁碼使用

和startPage中的pageNum效果一樣--><propertyname="offsetAsPageNum"value="false"/><!--該參數默認為false,

設置為true時,使用RowBounds分頁會進行count查詢--><propertyname="rowBoundsWithCount"value="true"/>

<!--設置為true時,如果pageSize=0或者RowBounds.limit=0就會查詢出全部的結果--><!--(相當于沒有執(zhí)行分頁查詢,但是返回結果仍然是Page類型)<propertyname="pageSizeZero"value="true"/>-->

<!--3.3.0版本可用-分頁參數合理化,默認false禁用--><!--啟用合理化時,如果pageNum<1會查詢第一頁,如果pageNum>pages會查詢最后一頁--><!--禁用合理化時,如果pageNum<1或pageNum>pages會返回空數據--><propertyname="reasonable"value="true"/><!--3.5.0版本可用-為了支持startPage(Objectparams)方法--><!--增加了一個`params`參數來配置參數映射,用于從Map或ServletRequest中取值--><!--可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默認值--><!--不理解該含義的前提下,不要隨便復制該配置<propertyname="params"value="pageNum=start;pageSize=limit;"/>--></plugin>使用PageHelper插件實現分頁13PageHelper中Page的APItrue表示需要統(tǒng)計總數,這樣會多進行一次請求selectcount(0);省略掉true參數只返回分頁數據。對于統(tǒng)計總數(將SQL語句變?yōu)閟electcount(0)fromxxx,只對簡單SQL語句其效果,復雜SQL語句需要自己寫)。Pagepage=PageHelper.startPage(pageNum,pageSize,true);Page<?>page=PageHelper.startPage(1,-1);longcount=page.getTotal();使用PageHelper插件實現分頁14PageHelper中Page的API在分頁參數中,pageNum表示第N頁,pageSize表示每頁M條數。只分頁不統(tǒng)計(每次只執(zhí)行分頁語句)分頁并統(tǒng)計(每次執(zhí)行2條語句,一條selectcount語句,一條分頁語句)適用于查詢分頁時數據發(fā)生變動,需要將實時的變動信息反映到分頁結果上。在使用PageHelper查全部(不分頁)。Pagepage=PageHelper.startPage(pageNum,pageSize,true);PageHelper.startPage([pageNum],[pageSize]);List<?>pagelist=queryForList(xxx.class,"queryAll",param);//pagelist就是分頁之后的結果Page<?>page=PageHelper.startPage([pageNum],[pageSize],[iscount]);List<?>pagelist=queryForList(xxx.class,"queryAll",param);longcount=page.getTotal();//也可以List<?>pagelist=page.getList();獲取分頁后的結果集PageHelper.startPage(1,0);List<?>alllist=queryForList(xxx.class,"queryAll",param);使用PageHelper插件實現分頁需求說明:為用戶管理之查詢用戶列表功能增加分頁實現列表結果按照創(chuàng)建時間降序排列15publicList<User>getUserList3(@Param("userName")StringuserName, @Param("userRole")IntegerroleId);<!--查詢用戶列表(分頁顯示)--><selectid="getUserList3"resultType="User"> SELECTu.*,r.roleNameuserRoleName FROMtb_useru,tb_roler WHEREu.userRole=r.id <iftest="userRole!=null"> andu.userRole=#{userRole} </if> <iftest="userName!=nullanduserName!=''"> andu.userNamelikeCONCAT('%',#{userName},'%') </if> orderbycreationDateDESC</select>List<User>userList=newArrayList<User>();StringuserName="";IntegerroleId=null;IntegerpageNum=1;IntegerpageSize=5;//開啟分頁PageHelper.startPage(pageNum,pageSize);//獲取查詢數據放入分頁對象、//查詢時無需關注查詢的條數不需要向Dao層中的方法傳入limit后邊的兩個參數(limit1,5)//調用Dao層方法userList=sqlSession.getMapper(UserMapper.class).getUserList3(userName,roleId);//封裝pageInfo對象并返回PageInfo可以看到源碼你就明白所有意思PageInfo<User>pageInfo=newPageInfo<User>(userList);for(Useruser:pageInfo.getList()){ logger.debug(user);}logger.debug("當前頁數:"+pageInfo.getPageNum());logger.debug("每頁條數:"+pageInfo.getPageSize());logger.debug("總頁數:"+pageInfo.getPages());logger.debug("總條數:"+pageInfo.getTotal());分頁顯示供應商列表和訂單列表16需求說明:為供應商管理之查詢供應商列表功能增加分頁實現為訂單管理之查詢訂單列表功能增分頁實現列表結果按照創(chuàng)建時間降序排列分頁-DAO層實現limit(起始位置,頁面容量)查詢的方法增加2個參數frompageSize完成時間:20分鐘練習指導共性問題集中講解17常見問題及解決辦法代碼規(guī)范問題調試技巧共性問題集中講解MyBatis的緩存機制02第5章深入使用MyBatisMyBatis緩存19MyBatis緩存MyBatis提供了默認下基于JavaHashMap的緩存實現,以及用于與OSCache、Ehcache、Hazelcast和Memcached連接的默認連接器。重點的那句話就是:MyBatis執(zhí)行SQL語句之后,這條語句就是被緩存,以后再執(zhí)行這條語句的時候,會直接從緩存中拿結果,而不是再次執(zhí)行SQL。MyBatis將數據緩存設計成兩級結構:一級緩存,一級緩存的作用域scope是SqlSession。二級緩存,也稱作全局緩存,作用域globalscope。一級緩存20一級緩存是Session會話級別的緩存,位于表示一次數據庫會話的SqlSession對象之中,又被稱之為本地緩存。一級緩存是MyBatis內部實現的一個特性,用戶不能配置,默認情況下自動支持的緩存,用戶沒有定制它的權利(不過這也不是絕對的,可以通過開發(fā)插件對它進行修改)?!壘彺媸腔赑erpetualCache(MyBatis自帶)的HashMap本地緩存,作用范圍為session域內,當sessionflush或者close之后,該session中所有的cache就會被清空。STEP01

MyBatis的一級緩存是SqlSession級別的緩存。如果同一個SqlSession對象多次執(zhí)行完全相同的SQL語句時,在第一次執(zhí)行完成后,MyBatis會將查詢結果寫入到一級緩存中,此后,如果程序沒有執(zhí)行插入、更新、刪除操作,當第二次執(zhí)行相同的查詢語句時,MyBatis會直接讀取一級緩存中的數據,而不用再去數據庫查詢,從而提高了數據庫的查詢效率。STEP03MyBatis的一級緩存級別一級緩存21STEP01

例如,存在數據表tb_book,從表中多次查詢id為1的圖書信息,當程序第一次查詢id為1的圖書信息時,程序會將查詢結果寫入MyBatis一級緩存,當程序第二次查詢id為1的圖書信息時,MyBatis直接從一級緩存中讀取,不再訪問數據庫進行查詢。當程序對數據庫執(zhí)行了插入、更新、刪除操作,MyBatis會清空一級緩存中的內容以防止程序誤讀。STEP03舉例說明MyBatis的一級緩存級別一級緩存22MyBatis如何防止程序誤讀

當程序對數據庫執(zhí)行了插入、更新、刪除操作后,MyBatis會清空一級緩存中的內容,以防止程序誤讀。MyBatis一級緩存被清空之后,再次使用SQL查詢語句訪問數據庫時,MyBatis會重新訪問數據庫。例如上面的例子,首先查詢id為1的圖書信息,然后使用更新語句對數據庫中的圖書信息進行更改,更改之后,再次對id為1的圖書信息進行查詢時,MyBatis依然會從數據庫中查詢。一級緩存23二級緩存24二級緩存是mapper級別的緩存。使用二級緩存時,多個SqlSession使用同一個Mapper的SQL語句去操作數據庫,得到的數據會存在二級緩存區(qū)域,它同樣是使用HashMap進行數據存儲。相比一級緩存SqlSession,二級緩存的范圍更大,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。二級緩存是多個SqlSession共享的,其作用域是mapper的同一個namespace。不同的SqlSession兩次執(zhí)行相同的namespace下的SQL語句,且向SQL中傳遞的參數也相同,即最終執(zhí)行相同的SQL語句,則第一次執(zhí)行完畢會將數據庫中查詢的數據寫到緩存(內存),第二次查詢時會從緩存中獲取數據,不再去底層數據庫查詢,從而提高查詢效率。STEP01

由5.2節(jié)的內容可知,相同的Mapper類,相同的SQL語句,如果SqlSession不同,則兩個SqlSession查詢數據庫時,會查詢數據庫兩次,這樣也會降低數據庫的查詢效率。為了解決這個問題,就需要用到MyBatis的二級緩存。MyBatis的二級緩存是Mapper級別的緩存,與一級緩存相比,二級緩存的范圍更大,多個SqlSession可以共用二級緩存,并且二級緩存可以自定義緩存資源。STEP03使用二級緩存的好處二級緩存25STEP01在MyBatis中,一個Mapper.xml文件通常稱為一個Mapper,MyBatis以namespace區(qū)分Mapper,如果多個SqlSession對象使用同一個Mapper的相同查詢語句去操作數據庫,在第一個SqlSession對象執(zhí)行完后,MyBatis會將查詢結果寫入二級緩存,此后,如果程序沒有執(zhí)行插入、更新、刪除操作,當第二個SqlSession對象執(zhí)行相同的查詢語句時,MyBatis會直接讀取二級緩存中的數據。STEP03MyBatis二級緩存的執(zhí)行過程二級緩存26STEP01STEP03MyBatis二級緩存的執(zhí)行過程圖解二級緩存27STEP01

與MyBatis的一級緩存不同的是,MyBatis的二級緩存需要手動開啟,開啟二級緩存通常要完成以下兩個步驟。STEP03二級緩存與一級緩存的不同點二級緩存28二級緩存29二級緩存的配置MyBatis的全局cache配置在MapperXML文件中設置緩存,默認情況下是沒有開啟緩存的在MapperXML文件配置支持cache后,如果需要對個別查詢進行調整,可以單獨設置cache<settings><settingname="cacheEnabled"value="true"/></settings><cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/><selectid="selectAll"resultType="Emp"useCache="true">STEP01

與使用二級緩存前,需要在MyBatis的核心配置mybatis-config.xml文件中通過<settings>元素開啟二級緩存的全局配置。STEP03a.開啟二級緩存的全局配置<settings> <settingname="cacheEnabled"value="true"/></settings>二級緩存30STEP01

開啟當前Mapper的namespace下的二級緩存,可以通過MyBatis映射文件中的<cache>元素來完成。

STEP03b.開啟當前Mapper的namespace下的二級緩存<!--開啟當前Mapper的namespace下的二級緩存--><cache></cache>二級緩存31STEP01(1)映射文件中所有select語句將會被緩存。(2)映射文件中的所有insert、update和delete語句都會刷新緩存。(3)緩存會使用LRU算法回收。(4)沒有刷新間隔,緩存不會以任何時間順序來刷新。(5)緩存會存儲列表集合或對象的1024個引用。(6)緩存是可讀/可寫的緩存,這意味著對象檢索不是共享的,緩存可以安全的被調用者修改,而不干擾其他調用者或線程所做的潛在修改。

STEP03默認狀態(tài)的二級緩存可實現的功能二級緩存32<cache>元素的屬性屬性說明flushInterval刷新間隔。該屬性可以被設置為任意的正整數,而且它們代表一個合理的毫秒形式的時間段。默認情況下是不設置值。size引用數目。該屬性可以被設置為任意正整數,默認值為1024。readOnly只讀。該屬性可以被設置為true或者false。當緩存設置為只讀時,緩存對象不能被修改,但此時緩存性能較高。當緩存設置為可讀寫時,性能較低,但安全性高。

eviction回收策略。該屬性有4個可選值。以上是二級緩存在默認狀態(tài)下的特性,如果需要調整上述特性,可通過<cache>元素的屬性來實現。LRU:最近最少使用的策略。移除最長時間不被使用的對象。FIFO:先進先出策略。按對象進入緩存的順序來移除它們。SOFT:軟引用策略。移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象。WEAK:弱引用策略。更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象.二級緩存33STEP01

在實際開發(fā)中,經常會遇到多個SqlSession在同一個Mapper中執(zhí)行操作,例如,SqlSession1執(zhí)行查詢操作,SqlSession2執(zhí)行插入、更新、刪除操作,SqlSession3又執(zhí)行和SqlSession1相同的查詢操作。當SqlSession1執(zhí)行查詢操作時,程序會將查詢結果寫入MyBatis二級緩存,當SqlSession2對數據庫執(zhí)行了插入、更新、刪除操作后,MyBatis會清空二級緩存中的內容,以防止程序誤讀。當SqlSession3執(zhí)行和SqlSession1相同的查詢操作時,MyBatis會重新訪問數據庫。STEP03多個SqlSession在同一個Mapper中執(zhí)行二級緩存34MyBatis緩存機制35STEP01

終端用戶訪問緩存時,如果在緩存中查找到了要被訪問的數據,就叫做命中。如果緩存中沒有查找到要被訪問的數據,就是沒有命中。當多次執(zhí)行查詢操作時,緩存命中次數與總的查詢次數(緩存命中次數+緩存沒有命中次數)的比,就叫作緩存命中率,即緩存命中率=緩存命中次數/總的查詢次數。當MyBatis開啟二級緩存后,第一次查詢數據時,由于數據還沒有進入緩存,所以需要在數據庫中查詢而不是在緩存中查詢,此時,緩存命中率為0。第一次查詢過后,MyBatis會將查詢到的數據寫入緩存中,當第二次再查詢相同的數據時,MyBatis會直接從緩存中獲取這條數據,緩存將命中,此時的緩存命中率為0.5(1/2)。當第三次查詢相同的數據,則緩存命中率為0.66666(2/3),以此類推。STEP03多學一招:CacheHitRatio(緩存命中率)二級緩存36MyBatis的常用注解03第5章深入使用MyBatis常用注解38MyBatis的注解位于org.apache.ibatis.annotations包下。常用的注解如下:Select映射查詢的SQL語句。Insert映射插入的SQL語句。Update映射更新的SQL語句。Delete映射刪除的SQL語句。Param當映射器方法需要多個參數時,這個注解可以被應用于映射器方法參數來給每個參數取一個名字。否則,多參數將會以它們的順序位置和SQL語句中的表達式進行映射,這是默認的。使用@Param("id"),SQL中參數應該被命名為#{id}。映射注解39屬性描述SelectProviderSelect語句的動態(tài)SQL映射。允許指定一個類名和一個方法在執(zhí)行時返回運行的查詢語句。有兩個屬性:type和method,type屬性是類的完全限定名,method是該類中的那個方法名。InsertProviderInsert語句的動態(tài)SQL映射。允許指定一個類名和一個方法在執(zhí)行時返回運行的插入語句。有兩個屬性:type和method,type屬性是類的完全限定名,method是該類中的那個方法名。UpdateProviderUpdate語句的動態(tài)SQL映射。允許指定一個類名和一個方法在執(zhí)行時返回運行的更新語句。有兩個屬性:type和method,type屬性是類的完全限定名,method是該類中的那個方法名。DeleteProviderDelete語句的動態(tài)SQL映射。允許指定一個類名和一個方法在執(zhí)行時返回運行的刪除語句。有兩個屬性:type和method,type屬性是類的完全限定名,method是該類中的那個方法名。Result在列和屬性之間的單獨結果映射。屬性包括:id、column、property、javaType、jdbcType、typeHandler、one、many。id屬性是一個布爾值,表示是否被用于主鍵映射。one屬性是單獨的聯系,和XML配置中的<association>相似,而many屬性是對集合而言的,和XML配置的<collection>相似。Results多個結果映射(Result)列表。Options提供配置選項的附加值,它們通常在映射語句上作為附加功能配置出現。One復雜類型的單獨屬性值映射。必須指定select屬性,表示己映射的SQL語句的完全限定名。Many復雜類型的集合屬性映射。必須指定select屬性,表示已映射的SQL語句的完全限定名。增刪改查注解的使用40@select、@insert、@update和@delete可以完成常見的CRUD(增刪改查)SQL語句映射。//查詢所有User@Select("select*fromtb_useru")publicList<User>findAllUser();//根據id查詢User@Select("select*fromtb_useruwhereu.id=#{id}")publicUserfindUserById(@Param("id")Integerid);//添加用戶@Insert("insertintotb_user(userCode,userName,userPassword,gender,birthday,phone,email,address,userDesc,userRole,createdBy,creationDate,imgPath)values(#{userCode},#{userName},#{userPassword},#{gender},#{birthday},#{phone},#{email},#{address},#{userDesc},#{userRole},#{createdBy},#{creationDate},#{imgPath})")publicintadd(Useruser);//修改用戶@Update("updatetb_usersetuserCode=#{userCode},userName=#{userName},userPassword=#{userPassword},gender=#{gender},birthday=#{birthday},phone=#{phone},email=#{email},address=#{address},userDesc=#{userDesc},userRole=#{userRole},modifyBy=#{modifyBy},modifyDate=#{modifyDate},imgPath=#{imgPath}whereid=#{id}")publicintmodify(Useruser);//根據id刪除User@Delete("deletefromtb_userwhereid=#{id}")publicintdeleteUserById(@Param("id")Integerid);關聯注解的使用41一對一一對多@Select("SELECT*FROMtb_userWHEREid=#{id}")@Results({ @Result(id=true,column="id",property="id"), @Result(column="userCode",property="userCode"), @Result(column="userName",property="userName"), @Result(column="userPassword",property="userPassword"), @Result(column="userRole",property="role",

one=@One(select="cn.dsscm.dao.UserMapper.getRoleById"))})publicUsergetUserById(@Param("id")Integerid);//根據id查詢商品類別信息@Select("SELECT*FROMtb_product_categoryWHEREID=#{id}ORDERBYid")@Results({ @Result(id=true,column="id",property="id"), @Result(column="name",property="name"), @Result(column="id",property="products",

many=@Many(select="cn.dsscm.dao.ProductMapper.getProduct"))})publicList<ProductCategory>selectById(@Param("id")Integerid);(1)property屬性用來指定關聯屬性。(2)column屬性用來指定關聯的數據庫表中的字段。(3)one屬性用來指定數據表之間屬于哪種關聯關系,通過@One注解表明數據表之間是一對一關聯關系。@Result注解的三個屬性及含義一對一查詢42動態(tài)SQL43查詢用戶列表——使用字符串拼接@SelectProvider(type=UserDynaSqlProvider.class,method="getUserList")publicList<User>getUserList(@Param("userName")StringuserName,@Param("userRole")IntegerroleId); publicStringgetUserList(Map<String,Object>para){ Stringsql="SELECT*FROMtb_userWHERE1=1"; if(null!=para.get("userName")&&!"".equals(para.get("userName"))){ sql+="ANDuserNamelikeCONCAT('%',#{userName},'%')"; } if(null!=para.get("userRole")){ sql+="ANDuserRole=#{userRole}"; } returnsql; }注解動態(tài)SQL類44方法說明TSELECT(Stringcolumns)開始或追加SELECT子句,參數通常是一個逗號分隔的列表的列TFROM(Stringtable)啟動或追加FROM子句,可以調用超過一次,這些參數通常是一個表名TJOIN(Stringjoin)向JOIN子句添加一個新的查詢條件,該參數通常是一個表,也可以包括一個標準的連接返回的結果集TINNER_JOIN(Stringjoin)同JOIN子句,連接方式是內連接(INNER_JOIN)TLEFT_OUTER_JOIN(Stringjoin)同JOIN子句,連接方式是左外連接(LEFT_OUTER_JOIN)TRIGHT_OUTER_J0IN(Stringjoin)同JOIN子句,連接方式是右外連接(RIGHT_OUTER_JOIN)TWHERE(Stringconditions)追加一個新的WHERE子句條件,可以多次調用TOR()使用OR拆分當前WHERE子句條件,可以不止一次被調用TAND()使用AND拆分當前WHERE子句條件,可以不止一次被調用TGROUP_BY(Stringcolumns)追加一個新的GROUPBY子句元素THAVING(Stringconditions)追加一個新的HAVING子句條件TORDER_BY(Stringcolumns)追加一個新的ORDERBY子句元素TINSERTJNTO(StringtableName)啟動INSERT語句插入到指定表,應遵循由一個或多個VALUES()調用TVALUES(Stringcolumns,Stringvalues)追加的INSERT語句,第一個參數是要插入的列,第二個參數是插入的值TDELETE_FROM(Stringtable)啟動DELETE語句,并指定表刪除TUPDATE(Stringtable)啟動一個更新(UPDATE)語句,并指定表更新TSET(Stringsets)追加一個更新語句SET列表查詢用戶列表——使用注解動態(tài)SQL類45@SelectProvider(type=UserDynaSqlProvider.class,method="getUserList2")publicList<User>getUserList2(@Param("userName")StringuserName,@Param("userRole")IntegerroleId);publicStringgetUserList2(finalMap<String,Object>para){ returnnewSQL(){ {

SELECT("*");

FROM("tb_user"); if(null!=para.get("userName")&&!"".equals(para.get("userName"))){

WHERE("userNamelikeCONCAT('%',#{userName},'%')"); } if(null!=para.get("userRole")){

WHERE("userRole=#{userRole}"); } } }.toString();}使用注解動態(tài)SQL類——修改用戶信息46@UpdateProvider(type=UserDynaSqlProvider.class,method="modify")publicintmodify(Useruser);publicStringmodify(Useruser){ returnnewSQL(){ {

UPDATE("tb_user"); if(user.getUserCode()!=null){

SET("userCode=#{userCode}"); } if(user.getUserName()!=null){

SET("userName=#{userName}"); } if(user.getUserPassword()!=null){

SET("userPassword=#{userPassword}"); } ……

WHERE("id=#{id}"); } }.toString();}二級緩存47@CacheNamespace(eviction=LruCache.class,flushInterval=60000,size=512,readWrite=true)publicinterfaceUserMapper{

//根據id查詢User @Select("SELECT*FROMtb_userWHEREid=#{id}")

@Options(useCache=true) UserselectUserById(Integerid);

//根據id刪除User @Delete("DELETEFROMTB_USERWHEREid=#{id}") voiddeleteUserById(Integerid);

}學生表(s_student)與班級表(c_class)詳情學生idid學生姓名name學生年齡age所屬班級cid1張三1812李四1823王五1924趙六201班級idid班級名稱classname1一班2二班

現有一個學生表s_student(學生id、學生姓名、學生年齡、所屬班級)和一個班級表c_class(班級id、班級名稱),其中,班級表c_class和學生表s_student是一對多的關系?;贛yBatis注解的學生管理程序48(1)MyBatis注解實現查詢操作。根據表1和表2在數據庫分別創(chuàng)建一個學生表s_student和一個班級表c_class,并查詢id為2的學生的信息。(2)MyBatis注解實現修改操作。修改id為4的學生的姓名修改為李雷,年齡修改為21。(3)MyBatis注解實現一對多查詢。查詢出二班所有學生的信息。

使用MyBatis注解實現下列要求基于MyBatis注解的學生管理程序49共性問題集中講解50常見問題及解決辦法代碼規(guī)范問題調試技巧共性問題集中講解本章小結

本章首先介紹了不同方式實現分頁顯示功能;接著介紹了MyBatis的緩存機制,包括一級緩存SqlSessicm和二級緩存mapper。使用緩存可以最大程度地減輕數據查詢壓力,提高數據庫性能本章詳細介紹了MyBatis的常用注解,包括增刪改查和一對一、一對多、動態(tài)SQL和二級緩存的操作。

通過本章的學習,讀者可以掌握數據表的分頁顯示,

并能夠使用MyBatis框架對操作實現緩存機制進行處理。MyBatis中的常用注解熟練使用有助于提高項目的開發(fā)效率,讀者一定要多加練習。本章小結51本章作業(yè)?

本章作業(yè)簡述事務的特性。簡述MyBatis的數據緩存。?預習作業(yè)請簡述Spring框架的優(yōu)點。請簡述什么是Spring的IoC和DI。52問題及作業(yè)集中問題&課后作業(yè)Spring概述Spring的核心容器Spring的入門程序DI與IoC第6章

初識Spring2024/1/29學習目標/Target55了解Spring的基本概念和優(yōu)點

理解Spring中的DI與IoC的相關概念掌握ApplicationContext的使用方法掌握屬性setter方法注入的實現方法章節(jié)概述/Summary56Spring致力于解決JavaEE應用中的各種問題,對于一個Java開發(fā)者來說,Spring框架的熟練使用是必備的技能之一。Spring具有良好的設計和分層結構,它克服了傳統(tǒng)重量型框架臃腫、低效的劣勢,大大簡化了項目開發(fā)中的技術復雜性。本章將對Spring框架的基礎知識進行詳細地講解。

目錄/CONTENTSSpring概述DI與IoCSpring的入門程序Spring的核心容器571432Spring概述01第6章初識Spring什么是Spring?什么是Spring59Spring是分層的JavaSE/EEfull-stack輕量級開源框架,以IoC(InverseofControl控制反轉)和AOP(AspectOrientedProgramming面向切面編程)為內核,使用基本的JavaBean來完成以前只可能由EJB完成的工作,取代了EJB的臃腫、低效的開發(fā)模式。什么是Spring60

在實際開發(fā)中,通常服務器端在采用三層體系架構,分別為表示層(Web)、業(yè)務邏輯層(Service)、持久層(Dao),Spring對每一層都提供了技術支持。表示層業(yè)務邏輯層持久層在表示層提供了與Struts等框架的整合在業(yè)務邏輯層可以管理事務、記錄日志等在持久層可以整合MyBatis、Hibernate、JdbcTemplate等技術Spring的綠草叢61Spring輕量級框架,JavaEE的春天,當前主流框架目標使現有技術更加易用,推進編碼最佳實踐內容IoC容器AOP實現數據訪問支持簡化JDBC/ORM框架聲明式事務Web集成Spring體系結構62Spring的體系結構63Spring框架采用的是分層架構,它一系列的功能要素被分成20個模塊。

BeansCoreContextSpELCoreContainerTestJDBCORMOXMJMSDataAccess/IntegrationTransactionsAOPAspectsInstrumentationMessagingWebSocketServletWebPortletWebSpring的體系結構641.CoreContainer(核心容器)BeansCoreContextSpELCoreContainer

提供了BeanFactory,Spring將管理對象稱為Bean。

提供了Spring框架的基本組成部分,包括IoC和DI功能。建立在Core和Beans模塊的基礎之上,它是訪問定義和配置的任何對象的媒介。

Spring3.0后新增的模塊,是運行時查詢和操作對象圖的強大的表達式語言。Spring的體系結構65JDBCORMOXMJMSDataAccess/IntegrationTransactions提供了一個JDBC的抽象層,大幅度的減少了在開發(fā)過程中對數據庫操作的編碼。

提供了一個支持對象/XML映射的抽象層實現,如JAXB、Castor、XMLBeans、JiBX和XStream。對流行的對象關系映射API,包括JPA、JDO和Hibernate提供了集成層支持。

支持對實現特殊接口以及所有POJO類的編程和聲明式的事務管理。指Java消息傳遞服務,包含使用和產生信息的特性,自4.1版本后支持與Spring-message模塊的集成。2.DataAccess/Integration(數據訪問/集成)3.WebSpring的體系結構66WebSocketServletWebPortletWebSpring4.0以后新增的模塊,它提供了WebSocket和SockJS的實現,以及對STOMP的支持。提供了基本的Web開發(fā)集成特性,如:多文件上傳、使用Servlet監(jiān)聽器來初始化IoC容器以及Web應用上下文。也稱Spring-webmvc模塊,包含Spring模型—視圖—控制器(MVC)和RESTWebServices實現的Web程序提供了在portlet環(huán)境中使用MVC實現,類似Servlet模塊的功能。Spring的體系結構674.其他模塊AOPAspectsInstrumentationMessagingTest

提供了面向切面編程實現,允許定義方法攔截器和切入點,將代碼按照功能進行分離,以降低耦合性。提供了類工具的支持和類加載器的實現,可以在特定的應用服務器中使用。提供了與AspectJ的集成功能,AspectJ是一個功能強大且成熟的面向切面編程(AOP)框架。

提供了對單元測試和集成測試的支持。Spring4.0以后新增的模塊,它提供了對消息傳遞體系結構和協議的支持。Spring設計理念&核心技術68Spring設計理念Spring是面向Bean的編程Spring兩大核心技術控制反轉(IoC:InversionofControl)/依賴注入(DI:DependencyInjection)面向切面編程(AOP:AspectOrientedProgramming)目的:解耦合。實現每個組件時只關注組件內部的事情要點:明確定義組件間的接口控制反轉/依賴注入69將組件對象的控制權從代碼本身轉移到外部容器組件化的思想:分離關注點,使用接口,不再關注實現依賴的注入:將組件的構建和使用分開組件的使用組件的生產接口的定義運行時注入演示:使用簡單工廠Spring開發(fā)所需的jar包分為兩個部分:Spring框架包和第三方依賴包。下載地址:https://spring.io/projects/spring-framework/spring-projects/spring-framework/tree/5.3.xSpring框架包docs文件夾中包含API文檔和開發(fā)規(guī)范libs文件夾中包含JAR包和源碼Schema文件夾中包含開發(fā)所需要的schema文件Spring的下載及目錄結構70

下載后的解壓目錄如下:STEP01

docs文件夾:該文件夾下存放Spring的相關文檔,包括開發(fā)指南、API參考文檔。

libs文件夾:該文件夾下存放開發(fā)所需的jar包和源碼。整個Spring框架由21個模塊組成,libs目錄下Spring為每個模塊都提供了三個壓縮包,因此,libs文件夾下一共有63個jar包。這63個jar包分為三類。

schema文件夾:該文件夾下存放Spring各種配置文件的XMLSchema文檔。STEP03Spring目錄結構下文件夾介紹Spring的下載及目錄結構71打開libs目錄可以看到60個JAR文件,具體如下:以.jar結尾的是class文件JAR包以-javadoc.jar結尾的是API文檔壓縮包以-sources.jar結尾的是源文件壓縮包Spring的下載及目錄結構72在libs目錄中有四個Spring的基礎包,分別對應Spring核心容器的四個模塊。spring-expression-5.3.26.jar

定義了Spring的表達式語言。spring-core-5.3.26.jar

包含Spring框架的核心工具類,Spring其它組件都要用到這個包里的類。spring-beans-5.3.26.jar

所有應用都要用到的JAR包,它包含訪問配置文件、創(chuàng)建和管理Bean以及進行控制反轉或者依賴注入操作相關的所有類。spring-context-5.3.26.jar

提供了在基礎IoC功能上的擴展服務,還提供了許多企業(yè)級服務的支持Spring的下載及目錄結構73Spring的下載及目錄結構74第三方依賴包在使用Spring開發(fā)時,除了要使用自帶的JAR包外,Spring的核心容器還需要依賴commons.logging的JAR包。下載地址:/proper/commons-logging/download_logging.cgiSpring框架的優(yōu)點75Spring具有簡單、可測試和松耦合等特點。Spring不僅可以用于服務器端開發(fā),也可以應用于任何Java應用的開發(fā)中。非侵入式設計支持AOP方便解耦、簡化開發(fā)12

3支持聲明式事務處理4方便程序測試5方便集成各種優(yōu)秀框架6降低JavaEEAPI的使用難度7Spring框架的7大優(yōu)點Spring的核心容器02第6章初識SpringSpring容器會負責控制程序之間的關系,而不是由程序代碼直接控制。Spring為我們提供了兩種核心容器,分別為BeanFactory和ApplicationContext,本節(jié)將對這兩種核心容器進行簡單介紹。概述Spring的核心容器77BeanFactorybeanFactory=newXmlBeanFactory(newFileSystemResource("F:/applicationContext.xml"));

創(chuàng)建BeanFactory實例時,需要提供Spring所管理容器的詳細配置信息,這些信息通常采用XML文件形式來管理,其加載配置信息的語法如下:小提示:這種加載方式在實際開發(fā)中并不多用,讀者作為了解即可。XML配置文件的位置BeanFactory78ApplicationContext是BeanFactory的子接口,是另一種常用的Spring核心容器。它由org.springframework.context.ApplicationContext接口定義,不僅包含了BeanFactory的所有功能,還添加了對國際化、資源訪問、事件傳播等方面的支持。創(chuàng)建ApplicationContext接口實例,通常采用兩種方法,具體如下:ApplicationContextapplicationContext=newClassPathXmlApplicationContext(StringconfigLocation);

ClassPathXmlApplicationContext會從類路徑classPath中尋找指定的XML配置文件,找到并裝載完成ApplicationContext的實例化工作。通過ClassPathXmlApplicationContext創(chuàng)建

ApplicationContext79通過FileSystemXmlApplicationContext創(chuàng)建

ApplicationContextapplicationContext=newFileSystemXmlApplicationContext(StringconfigLocation);

FileSystemXmlApplicationContext會從指定的文件系統(tǒng)路徑(絕對路徑)中尋找指定的XML配置文件,找到并裝載完成ApplicationContext的實例化工作。在Java項目中,會通過ClassPathXmlApplicationContext類來實例化ApplicationContext容器。而在Web項目中,ApplicationContext容器的實例化工作會交由Web服務器來完成。Web服務器實例化ApplicationContext容器時,通常會使用ContextLoaderListener來實現,此種方式只需要在web.xml中添加如下代碼:<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>ApplicationContext80

創(chuàng)建Spring容器后,就可以獲取Spring容器中的Bean。Spring獲取Bean的實例通常采用以下兩種方法:ObjectgetBean(Stringname);根據容器中Bean的id或name來獲取指定的Bean,獲取之后需要進行強制類型轉換。<T>TgetBean(Class<T>requiredType);根據類的類型來獲取Bean的實例。由于此方法為泛型方法,因此在獲取Bean之后不需要進行強制類型轉換。ApplicationContext81Spring的入門程序03第6章初識Spring創(chuàng)建工程:在IntelliJIDEA中,創(chuàng)建一個Maven項目,然后在pom.xml文件中加載需使用到的Spring的4個基礎包,即spring-core-5.3.26.jar、spring-beans-5.3.26.jar、spring-context-5.3.26.jar和spring-expression-5.3.26.jar。除此之外,還需要將Spring依賴包commons-logging-1.2.RELEASE.jar也加載到項目中。Spring的入門程序83STEP01<!--Spring的基礎包Spring-core--><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.26</version></dependency><!--Spring的基礎包Spring-beans--><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.3.26</version></dependency><!--Spring的基礎包Spring-context--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.26</version></dependency><!--Spring的基礎包Spring-expressinon--><dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>5.3.26</version></dependency><!--Spring的依賴包commons-logging--><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>創(chuàng)建HelloSpring.java在src/main/java目錄下,創(chuàng)建一個cn.springdemo包,并在包中創(chuàng)建HelloSpring.java,然后在類中定義一個print()方法publicclassHelloSpring{//定義who屬性,該屬性的值將通過Spring框架進行設置

privateStringwho=nul

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論