摘要:相關(guān)閱讀通過(guò)項(xiàng)目逐步深入了解一通過(guò)項(xiàng)目逐步深入了解二通過(guò)項(xiàng)目逐步深入了解三本項(xiàng)目所有代碼及文檔都托管在地址延遲加載什么是延遲加載可以實(shí)現(xiàn)高級(jí)映射使用實(shí)現(xiàn)一對(duì)一及一對(duì)多映射,具備延遲加載功能。一級(jí)緩存是級(jí)別的緩存。
相關(guān)閱讀:
1、通過(guò)項(xiàng)目逐步深入了解Mybatis<一>
2、通過(guò)項(xiàng)目逐步深入了解Mybatis<二>
3、通過(guò)項(xiàng)目逐步深入了解Mybatis<三>
本項(xiàng)目所有代碼及文檔都托管在 Github地址:https://github.com/zhisheng17/mybatis
延遲加載 什么是延遲加載?resultMap可以實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一及一對(duì)多映射),association、collection具備延遲加載功能。
需求:
如果查詢訂單并且關(guān)聯(lián)查詢用戶信息。如果先查詢訂單信息即可滿足要求,當(dāng)我們需要查詢用戶信息時(shí)再查詢用戶信息。把對(duì)用戶信息的按需去查詢就是延遲加載。
延遲加載:先從單表查詢、需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高 數(shù)據(jù)庫(kù)性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。
打開(kāi)延遲加載開(kāi)關(guān)在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading
設(shè)置項(xiàng) | 描述 | 允許值 | 默認(rèn)值 |
---|---|---|---|
lazyLoadingEnabled | 全局性設(shè)置懶加載。如果設(shè)為‘false’,則所有相關(guān)聯(lián)的都會(huì)被初始化加載。 | true false | false |
aggressiveLazyLoading | 當(dāng)設(shè)置為‘true’的時(shí)候,懶加載的對(duì)象可能被任何懶屬性全部加載。否則,每個(gè)屬性都按需加載。 | true false | true |
使用 association 實(shí)現(xiàn)延遲加載
需求:查詢訂單并且關(guān)聯(lián)查詢用戶信息
Mapper.xml需要定義兩個(gè) mapper 的方法對(duì)應(yīng)的 statement。
1、只查詢訂單信息
SQL 語(yǔ)句: select * from orders
在查詢訂單的 statement 中使用 association 去延遲加載(執(zhí)行)下邊的 statement (關(guān)聯(lián)查詢用戶信息)
2、關(guān)聯(lián)查詢用戶信息
通過(guò)上面查詢訂單信息中的 user_id 來(lái)關(guān)聯(lián)查詢用戶信息。使用 UserMapper.xml 中的 findUserById
SQL語(yǔ)句:select * from user where id = user_id
上邊先去執(zhí)行 findOrdersUserLazyLoading,當(dāng)需要去查詢用戶的時(shí)候再去執(zhí)行 findUserById ,通過(guò) resultMap的定義將延遲加載執(zhí)行配置起來(lái)。也就是通過(guò) resultMap 去加載 UserMapper.xml 文件中的 select = findUserById
延遲加載的 resultMapOrderMapperCustom.java
public List測(cè)試代碼:findOrdersUserLazyLoading() throws Exception;
@Test public void testFindOrdersUserLazyLoading() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建OrdersMapperCustom對(duì)象,mybatis自動(dòng)生成代理對(duì)象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); //查詢訂單信息 List測(cè)試結(jié)果:list = ordersMapperCustom.findOrdersUserLazyLoading(); //遍歷所查詢的的訂單信息 for (Orders orders : list) { //查詢用戶信息 User user = orders.getUser(); System.out.println(user); } sqlSession.close(); }
整個(gè)延遲加載的思路:
1、執(zhí)行上邊mapper方法(findOrdersUserLazyLoading),內(nèi)部去調(diào)用cn.zhisheng.mybatis.mapper.OrdersMapperCustom 中的 findOrdersUserLazyLoading 只查詢 orders 信息(單表)。
2、在程序中去遍歷上一步驟查詢出的 List
3、延遲加載,去調(diào)用 UserMapper.xml 中 findUserbyId 這個(gè)方法獲取用戶信息。
思考:不使用 mybatis 提供的 association 及 collection 中的延遲加載功能,如何實(shí)現(xiàn)延遲加載??
實(shí)現(xiàn)方法如下:
定義兩個(gè)mapper方法:
1、查詢訂單列表
2、根據(jù)用戶id查詢用戶信息
實(shí)現(xiàn)思路:
先去查詢第一個(gè)mapper方法,獲取訂單信息列表
在程序中(service),按需去調(diào)用第二個(gè)mapper方法去查詢用戶信息。
總之:
使用延遲加載方法,先去查詢 簡(jiǎn)單的 sql(最好單表,也可以關(guān)聯(lián)查詢),再去按需要加載關(guān)聯(lián)查詢的其它信息。
一對(duì)多延遲加載上面的那個(gè)案例是一對(duì)一延遲加載,那么如果我們想一對(duì)多進(jìn)行延遲加載呢,其實(shí)也是很簡(jiǎn)單的。
一對(duì)多延遲加載的方法同一對(duì)一延遲加載,在collection標(biāo)簽中配置select內(nèi)容。
延遲加載總結(jié):作用:
當(dāng)需要查詢關(guān)聯(lián)信息時(shí)再去數(shù)據(jù)庫(kù)查詢,默認(rèn)不去關(guān)聯(lián)查詢,提高數(shù)據(jù)庫(kù)性能。
只有使用resultMap支持延遲加載設(shè)置。
場(chǎng)合:
查詢緩存 什么是查詢緩存?當(dāng)只有部分記錄需要關(guān)聯(lián)查詢其它信息時(shí),此時(shí)可按需延遲加載,需要關(guān)聯(lián)查詢時(shí)再向數(shù)據(jù)庫(kù)發(fā)出sql,以提高數(shù)據(jù)庫(kù)性能。
當(dāng)全部需要關(guān)聯(lián)查詢信息時(shí),此時(shí)不用延遲加載,直接將關(guān)聯(lián)查詢信息全部返回即可,可使用resultType或resultMap完成映射。
mybatis提供查詢緩存,用于減輕數(shù)據(jù)壓力,提高數(shù)據(jù)庫(kù)性能。
mybaits提供一級(jí)緩存,和二級(jí)緩存。
一級(jí)緩存是SqlSession級(jí)別的緩存。在操作數(shù)據(jù)庫(kù)時(shí)需要構(gòu)造 sqlSession對(duì)象,在對(duì)象中有一個(gè)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲(chǔ)緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。
二級(jí)緩存是mapper級(jí)別的緩存,多個(gè)SqlSession去操作同一個(gè)Mapper的sql語(yǔ)句,多個(gè)SqlSession可以共用二級(jí)緩存,二級(jí)緩存是跨SqlSession的。
為什么要用緩存?
如果緩存中有數(shù)據(jù)就不用從數(shù)據(jù)庫(kù)中獲取,大大提高系統(tǒng)性能。
一級(jí)緩存工作原理:
第一次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒(méi)有,從數(shù)據(jù)庫(kù)查詢用戶信息。
得到用戶信息,將用戶信息存儲(chǔ)到一級(jí)緩存中。
如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。
第二次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
一級(jí)緩存測(cè)試
Mybatis 默認(rèn)支持一級(jí)緩存,不需要在配置文件中配置。
所以我們直接按照上面的步驟進(jìn)行測(cè)試:
//一級(jí)緩存測(cè)試 @Test public void testCache1() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建UserMapper對(duì)象,mybatis自動(dòng)生成代理對(duì)象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //查詢使用的是同一個(gè)session //第一次發(fā)起請(qǐng)求,查詢Id 為1的用戶信息 User user1 = userMapper.findUserById(1); System.out.println(user1); //第二次發(fā)起請(qǐng)求,查詢Id 為1的用戶信息 User user2 = userMapper.findUserById(1); System.out.println(user2); sqlSession.close(); }
通過(guò)結(jié)果可以看出第二次沒(méi)有發(fā)出sql查詢請(qǐng)求,
所以我們需要在中間執(zhí)行 commit 操作
//如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除), // 清空SqlSession中的一級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。 //更新user1的信息, user1.setUsername("李飛"); //user1.setSex("男"); //user1.setAddress("北京"); userMapper.updateUserById(user1); //提交事務(wù),才會(huì)去清空緩存 sqlSession.commit();
測(cè)試
一級(jí)緩存應(yīng)用
正式開(kāi)發(fā),是將 mybatis 和 spring 進(jìn)行整合開(kāi)發(fā),事務(wù)控制在 service 中。
一個(gè) service 方法中包括很多 mapper 方法調(diào)用。
service{
//開(kāi)始執(zhí)行時(shí),開(kāi)啟事務(wù),創(chuàng)建SqlSession對(duì)象 //第一次調(diào)用mapper的方法findUserById(1) //第二次調(diào)用mapper的方法findUserById(1),從一級(jí)緩存中取數(shù)據(jù) //方法結(jié)束,sqlSession關(guān)閉
}
如果是執(zhí)行兩次service調(diào)用查詢相同的用戶信息,不走一級(jí)緩存,因?yàn)閟ession方法結(jié)束,sqlSession就關(guān)閉,一級(jí)緩存就清空。
二級(jí)緩存原理
首先開(kāi)啟mybatis的二級(jí)緩存。
sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會(huì)將查詢數(shù)據(jù)存儲(chǔ)到二級(jí)緩存中。
如果SqlSession3去執(zhí)行相同 mapper下sql,執(zhí)行commit提交,清空該 mapper下的二級(jí)緩存區(qū)域的數(shù)據(jù)。
sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)。
二級(jí)緩存與一級(jí)緩存區(qū)別,二級(jí)緩存的范圍更大,多個(gè)sqlSession可以共享一個(gè)UserMapper的二級(jí)緩存區(qū)域。
UserMapper有一個(gè)二級(jí)緩存區(qū)域(按namespace分) ,其它mapper也有自己的二級(jí)緩存區(qū)域(按namespace分)。
每一個(gè)namespace的mapper都有一個(gè)二緩存區(qū)域,兩個(gè)mapper的namespace如果相同,這兩個(gè)mapper執(zhí)行sql查詢到數(shù)據(jù)將存在相同的二級(jí)緩存區(qū)域中。
開(kāi)啟二級(jí)緩存:
mybaits的二級(jí)緩存是mapper范圍級(jí)別,除了在SqlMapConfig.xml設(shè)置二級(jí)緩存的總開(kāi)關(guān),還要在具體的mapper.xml中開(kāi)啟二級(jí)緩存
在 SqlMapConfig.xml 開(kāi)啟二級(jí)開(kāi)關(guān)
然后在你的 Mapper 映射文件中添加一行:
調(diào)用 pojo 類(lèi)實(shí)現(xiàn)序列化接口:
二級(jí)緩存需要查詢結(jié)果映射的pojo對(duì)象實(shí)現(xiàn)java.io.Serializable接口實(shí)現(xiàn)序列化和反序列化操作(因?yàn)槎?jí)緩存數(shù)據(jù)存儲(chǔ)介質(zhì)多種多樣,在內(nèi)存不一樣),注意如果存在父類(lèi)、成員pojo都需要實(shí)現(xiàn)序列化接口。
public class Orders implements Serializable public class User implements Serializable
測(cè)試
//二級(jí)緩存測(cè)試 @Test public void testCache2() throws Exception { SqlSession sqlSession1 = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); SqlSession sqlSession3 = sqlSessionFactory.openSession(); //創(chuàng)建UserMapper對(duì)象,mybatis自動(dòng)生成代理對(duì)象 UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); //sqlSession1 執(zhí)行查詢 寫(xiě)入緩存(第一次查詢請(qǐng)求) User user1 = userMapper1.findUserById(1); System.out.println(user1); sqlSession1.close(); //sqlSession3 執(zhí)行提交 清空緩存 UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class); User user3 = userMapper3.findUserById(1); user3.setSex("女"); user3.setAddress("山東濟(jì)南"); user3.setUsername("崔建"); userMapper3.updateUserById(user3); //提交事務(wù),清空緩存 sqlSession3.commit(); sqlSession3.close(); //sqlSession2 執(zhí)行查詢(第二次查詢請(qǐng)求) UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = userMapper2.findUserById(1); System.out.println(user2); sqlSession2.close(); }
結(jié)果:
useCache 配置
在 statement 中設(shè)置 useCache=false 可以禁用當(dāng)前 select 語(yǔ)句的二級(jí)緩存,即每次查詢都會(huì)發(fā)出sql去查詢,默認(rèn)情況是true,即該sql使用二級(jí)緩存。
總結(jié):針對(duì)每次查詢都需要最新的數(shù)據(jù)sql,要設(shè)置成useCache=false,禁用二級(jí)緩存。
刷新緩存(清空緩存)
在mapper的同一個(gè)namespace中,如果有其它insert、update、delete操作數(shù)據(jù)后需要刷新緩存,如果不執(zhí)行刷新緩存會(huì)出現(xiàn)臟讀。
設(shè)置statement配置中的flushCache="true" 屬性,默認(rèn)情況下為true即刷新緩存,如果改成false則不會(huì)刷新。使用緩存時(shí)如果手動(dòng)修改數(shù)據(jù)庫(kù)表中的查詢數(shù)據(jù)會(huì)出現(xiàn)臟讀。
如下:
一般下執(zhí)行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數(shù)據(jù)庫(kù)臟讀。
Mybatis Cache參數(shù)flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個(gè)合理的毫秒形式的時(shí)間段。默認(rèn)情況是不設(shè)置,也就是沒(méi)有刷新間隔,緩存僅僅調(diào)用語(yǔ)句時(shí)刷新。
size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對(duì)象數(shù)目和你運(yùn)行環(huán)境的可用內(nèi)存資源數(shù)目。默認(rèn)值是1024。
readOnly(只讀)屬性可以被設(shè)置為true或false。只讀的緩存會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例。因此這些對(duì)象不能被修改。這提供了很重要的性能優(yōu)勢(shì)??勺x寫(xiě)的緩存會(huì)返回緩存對(duì)象的拷貝(通過(guò)序列化)。這會(huì)慢一些,但是安全,因此默認(rèn)是false。
如下例子:
這個(gè)更高級(jí)的配置創(chuàng)建了一個(gè) FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對(duì)象或列表的 512 個(gè)引用,而且返回的對(duì)象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會(huì)導(dǎo)致沖突??捎玫氖栈夭呗杂? 默認(rèn)的是 LRU:
LRU – 最近最少使用的:移除最長(zhǎng)時(shí)間不被使用的對(duì)象。
FIFO – 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來(lái)移除它們。
SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象。
WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對(duì)象。
Mybatis 整合 ehcacheehcache 是一個(gè)分布式緩存框架。
分布緩存
我們系統(tǒng)為了提高系統(tǒng)并發(fā),性能、一般對(duì)系統(tǒng)進(jìn)行分布式部署(集群部署方式)
不使用分布緩存,緩存的數(shù)據(jù)在各各服務(wù)多帶帶存儲(chǔ),不方便系統(tǒng) 開(kāi)發(fā)。所以要使用分布式緩存對(duì)緩存數(shù)據(jù)進(jìn)行集中管理。
mybatis無(wú)法實(shí)現(xiàn)分布式緩存,需要和其它分布式緩存框架進(jìn)行整合。
整合方法
mybatis 提供了一個(gè)二級(jí)緩存 cache 接口(org.apache.ibatis.cache 下的 Cache),如果要實(shí)現(xiàn)自己的緩存邏輯,實(shí)現(xiàn)cache接口開(kāi)發(fā)即可。
import java.util.concurrent.locks.ReadWriteLock; public interface Cache { String getId(); void putObject(Object var1, Object var2); Object getObject(Object var1); Object removeObject(Object var1); void clear(); int getSize(); ReadWriteLock getReadWriteLock(); }
mybatis和ehcache整合,mybatis 和 ehcache 整合包中提供了一個(gè) cache 接口的實(shí)現(xiàn)類(lèi)(org.apache.ibatis.cache.impl 下的 PerpetualCache)。
package org.apache.ibatis.cache.impl; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import org.apache.ibatis.cache.Cache; import org.apache.ibatis.cache.CacheException; public class PerpetualCache implements Cache { private String id; private Map
通過(guò)實(shí)現(xiàn) Cache 接口可以實(shí)現(xiàn) mybatis 緩存數(shù)據(jù)通過(guò)其它緩存數(shù)據(jù)庫(kù)整合,mybatis 的特長(zhǎng)是sql操作,緩存數(shù)據(jù)的管理不是 mybatis 的特長(zhǎng),為了提高緩存的性能將 mybatis 和第三方的緩存數(shù)據(jù)庫(kù)整合,比如 ehcache、memcache、redis等。
引入依賴包
ehcache-core-2.6.5.jar 和 mybatis-ehcache-1.0.2.jar
引入緩存配置文件
classpath下添加:ehcache.xml
內(nèi)容如下:
屬性說(shuō)明:
diskStore:指定數(shù)據(jù)在磁盤(pán)中的存儲(chǔ)位置。
defaultCache:當(dāng)借助 CacheManager.add("demoCache") 創(chuàng)建Cache時(shí),EhCache 便會(huì)采用
以下屬性是必須的:
maxElementsInMemory - 在內(nèi)存中緩存的element的最大數(shù)目
maxElementsOnDisk - 在磁盤(pán)上緩存的element的最大數(shù)目,若是0表示無(wú)窮大
eternal - 設(shè)定緩存的elements是否永遠(yuǎn)不過(guò)期。如果為true,則緩存的數(shù)據(jù)始終有效,如果為false那么還要根據(jù)timeToIdleSeconds,timeToLiveSeconds判斷
overflowToDisk- 設(shè)定當(dāng)內(nèi)存緩存溢出的時(shí)候是否將過(guò)期的element緩存到磁盤(pán)上
以下屬性是可選的:
timeToIdleSeconds - 當(dāng)緩存在EhCache中的數(shù)據(jù)前后兩次訪問(wèn)的時(shí)間超過(guò)timeToIdleSeconds的屬性取值時(shí),這些數(shù)據(jù)便會(huì)刪除,默認(rèn)值是0,也就是可閑置時(shí)間無(wú)窮大
timeToLiveSeconds - 緩存element的有效生命期,默認(rèn)是0.,也就是element存活時(shí)間無(wú)窮大
diskSpoolBufferSizeMB 這個(gè)參數(shù)設(shè)置DiskStore(磁盤(pán)緩存)的緩存區(qū)大小.默認(rèn)是30MB.每個(gè)Cache都應(yīng)該有自己的一個(gè)緩沖區(qū).
diskPersistent- 在VM重啟的時(shí)候是否啟用磁盤(pán)保存EhCache中的數(shù)據(jù),默認(rèn)是false。
diskExpiryThreadIntervalSeconds - 磁盤(pán)緩存的清理線程運(yùn)行間隔,默認(rèn)是120秒。每個(gè)120s,相應(yīng)的線程會(huì)進(jìn)行一次EhCache中數(shù)據(jù)的清理工作
memoryStoreEvictionPolicy - 當(dāng)內(nèi)存緩存達(dá)到最大,有新的element加入的時(shí)候, 移除緩存中element的策略。默認(rèn)是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進(jìn)先出)
開(kāi)啟ehcache緩存
EhcacheCache 是ehcache對(duì)Cache接口的實(shí)現(xiàn);修改mapper.xml文件,在cache中指定EhcacheCache。
根據(jù)需求調(diào)整緩存參數(shù):
測(cè)試 :(這命中率就代表成功將ehcache 與 mybatis 整合了)
應(yīng)用場(chǎng)景對(duì)于訪問(wèn)多的查詢請(qǐng)求且用戶對(duì)查詢結(jié)果實(shí)時(shí)性要求不高,此時(shí)可采用 mybatis 二級(jí)緩存技術(shù)降低數(shù)據(jù)庫(kù)訪問(wèn)量,提高訪問(wèn)速度,業(yè)務(wù)場(chǎng)景比如:耗時(shí)較高的統(tǒng)計(jì)分析sql、電話賬單查詢sql等。
實(shí)現(xiàn)方法如下:通過(guò)設(shè)置刷新間隔時(shí)間,由 mybatis 每隔一段時(shí)間自動(dòng)清空緩存,根據(jù)數(shù)據(jù)變化頻率設(shè)置緩存刷新間隔 flushInterval,比如設(shè)置為30分鐘、60分鐘、24小時(shí)等,根據(jù)需求而定。
局限性mybatis 二級(jí)緩存對(duì)細(xì)粒度的數(shù)據(jù)級(jí)別的緩存實(shí)現(xiàn)不好,比如如下需求:對(duì)商品信息進(jìn)行緩存,由于商品信息查詢?cè)L問(wèn)量大,但是要求用戶每次都能查詢最新的商品信息,此時(shí)如果使用 mybatis 的二級(jí)緩存就無(wú)法實(shí)現(xiàn)當(dāng)一個(gè)商品變化時(shí)只刷新該商品的緩存信息而不刷新其它商品的信息,因?yàn)?mybaits 的二級(jí)緩存區(qū)域以 mapper 為單位劃分,當(dāng)一個(gè)商品信息變化會(huì)將所有商品信息的緩存數(shù)據(jù)全部清空。解決此類(lèi)問(wèn)題需要在業(yè)務(wù)層根據(jù)需求對(duì)數(shù)據(jù)有針對(duì)性緩存。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/66318.html
摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開(kāi)發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過(guò)的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛(ài)情萌芽的模樣…… Java 進(jìn)階面試問(wèn)題列表 -...
摘要:前提好幾周沒(méi)更新博客了,對(duì)不斷支持我博客的童鞋們說(shuō)聲抱歉了。熟悉我的人都知道我寫(xiě)博客的時(shí)間比較早,而且堅(jiān)持的時(shí)間也比較久,一直到現(xiàn)在也是一直保持著更新?tīng)顟B(tài)。 showImg(https://segmentfault.com/img/remote/1460000014076586?w=1920&h=1080); 前提 好幾周沒(méi)更新博客了,對(duì)不斷支持我博客的童鞋們說(shuō)聲:抱歉了!。自己這段時(shí)...
閱讀 1977·2023-04-25 15:51
閱讀 2586·2021-10-13 09:40
閱讀 2253·2021-09-23 11:22
閱讀 3331·2019-08-30 14:16
閱讀 2731·2019-08-26 13:35
閱讀 1926·2019-08-26 13:31
閱讀 940·2019-08-26 11:39
閱讀 2817·2019-08-26 10:33