Java 面試題前端
一. 容器部分vue
二. 多線程部分java
三. SpringMvc部分mysql
四. Mybatis部分面試
五. MySQL部分redis
六. Redis部分算法
七. RabbitMQ部分spring
八. JVM 虛擬機部分sql
九. 其餘面試部分數據庫
本人正在努力複習,總結面試經驗並記錄 Java 面試常見問題,歡迎留言監督
一直在更新
Collection
的子類List
、Set
List
的子類ArrayList
、LinkedList
等Set
的子類HashSet
、TreeSet
等Map
的子類HashMap
、TreeMao
等
java.util,Collection
是一個集合的頂級接口,它提供了對集合對象進行基本操做的通用接口方法,Collection 接口的意義是爲各類具體的集合提供了最大化的統一操做方式,其直接繼承接口的有 List 和 Setjava.util.Collections
是一個包裝類(工具類),它包含了各類有關集合操做的靜態多態方法。此類不能被實例化,用於對集合中元素進行排序、搜索以及線程安全等各類操做,服務於 Java 的 Collection 框架
- List、Set 都繼承 Collection 接口,而 Map 則不是
- List 是一個有序集合,元素可重複,可有多個NULL值。可使用各類循環遍歷集合,由於它是有序的
- Set 是一個無序集合,元素不可重複,重複元素會被覆蓋掉(注意:元素雖然無放入順序,但元素在 Set 中的位置是由該元素的 HashCode 決定的,其位置是固定的,加入 Set 的 Object 必須定義
equals()
方法),Set 只能用迭代,由於它是無序的- Map 是由一系列鍵值對組成的集合,提供了 key 和 value 的映射。在 Map 中保證 key 與 value 一一對應的關係。一個 key 對應一個 value ,不能存在相同的 key,但 value 能夠相同
- Set 與 List 相比較
- Set 檢索元素效率較低,刪除和插入效率高,由於刪除和插入不會引發元素的位置變化
- List 可動態增加,查找元素效率高,可是刪除和插入效率低,由於刪除或插入一條元素,會引發其餘元素位置變化
- Map 適合存儲鍵值對的數據
- 繼承的父類不一樣,但兩者都實現了 Map接口
- HashTable 繼承自
Dictionary
類- HashMap 繼承自
AbstractMap
類
- 線程安全不一樣
- HashMap 在缺省的狀況下是非Synchronize的
- HashTable 的方法是Synchronize的
- 在多線程下直接使用 HashTable 不須要本身爲它的方法實現同步。但使用 HashMap 時須要手動增長同步處理
Map m = Collections.synchronizeMap(hashMap);
- 是否提供 contains() 方法
- HashMap 把 HashTable 的 contains() 方法去掉了,改爲了 containsValue() 和 containsKey(),由於 contains 容易讓人誤解
- HashTable 則保留了 contains()、containsValue()、containsKey() 三個方法,其中 contains() 與 containsValue() 功能相同
- key 和 value 是否能夠爲 null 值
- HashTable 中,key 和 value 都不能爲 null 值
- HashMap 中,null 做爲鍵,但這樣的鍵只有一個。能夠有多個 value 爲 null 值的鍵。當 get() 方式返回 null 有多是 HashMap 中沒有該鍵,也有可能返回的 value 爲 null。因此 HashMap 用
containsKey()
方法判斷是否存在鍵
- 遍歷方式不一樣
- HashTable 與 HashMap 都是使用 Iterator 迭代器遍歷,而因爲歷史的緣由,HashTable 還使用了
Enumeration
的方式
- hash 值不一樣
- 哈希值的使用不一樣,HashTable直接使用對象的HashCode,而 HashMap 從新計算哈希值
- hashCode是jdk根據對象的地址或者字符串或者數字算出來的int類型的數值
- HashTable 使用的取模運算
- HashMap 使用的與運算,先用
hash & 0x7FFFFFFF
後,再對 length 取模,&0x7FFFFFFF
的目的是爲了將負的 hash 值轉化爲正值,由於 hash 值有可能爲負數,而&0x7FFFFFFF
後,只有符號外改變,然後面的位都不變
- 內部實現使用的數組初始化和擴容方式不一樣
- HashTable 在不指定容量的狀況下默認是11,而 HashMap 爲16,HashTable 不要求底層數組的容量必定要是2的整數次冪,而 HashMap 底層數組則必定爲2的整數次冪
- HashTable 擴容時,將容量變成原來的2倍+1 (old * 2 + 1),而 HashMap 則直接改成原來的2倍 (old * 2)
- 若是須要獲得一個有序的 Map 集合就應該使用 TreeMap (由於 HashMap 的排序順序不是固定的)除此以外,因爲 HashMap 有比 TreeMap 更好的性能,在不須要使用排序的狀況下使用 HashMap 會更好
- 利用key的hashCode從新hash計算出當前對象的元素在數組中的下標
存儲時,若是出現hash值相同的key,此時有兩種狀況。(1)若是key相同,則覆蓋原始值;(2)若是key不一樣(出現衝突),則將當前的key-value放入鏈表中
獲取時,直接找到hash值對應的下標,在進一步判斷key是否相同,從而找到對應值。
理解了以上過程就不難明白HashMap是如何解決hash衝突的問題,核心就是使用了數組的存儲方式,而後將衝突的key的對象放入鏈表中,一旦發現衝突就在鏈表中作進一步的對比。
- HashSet 其實是一個
HashMap
實例,都是一個存放鏈表的數組。它不保證存儲元素的迭代順序;此類容許使用 null 元素。HashSet 中不容許有重複元素,這是由於 HashSet 是基於 HashMap 實現的,HashSet 中的元素都存放在 HashMap 的 key 上面,而 value 中的值都是統一的一個固定對象private static final Object PRESENT = new Object();
- HashSet 中 add() 方法調用的是底層 HashMap 中的 put() 方法,而若是是在 HashMap 中調用 put() ,首先會判斷 key 是否存在,若是 key 存在則修改 value 值,若是 key 不存在這插入這個 key-value。而在 set 中,由於 value 值沒有用,也就不存在修改 value 值的說法,所以往 HashSet 中添加元素,首先判斷元素(也就是key)是否存在,若是不存在這插入,若是存在着不插入,這樣 HashSet 中就不存在重複值。因此判斷 key 是否存在就要重寫元素的類的 equals() 和 hashCode() 方法,當向 Set 中添加對象時,首先調用此對象所在類的 hashCode() 方法,計算次對象的哈希值,此哈希值決定了此對象在Set中存放的位置;若此位置沒有被存儲對象則直接存儲,若已有對象則經過對象所在類的 equals() 比較兩個對象是否相同,相同則不能被添加。
- AarrayList 是動態數組構成 LinkList 是鏈表組成
- AarrayList 經常使用於常常查詢的集合,由於 LinkList 是線性存儲方式,須要移動指針從前日後查找
- LinkList 經常使用於新增和刪除的集合,由於 ArrayList 是數組構成,刪除某個值會對下標影響,須要進行數據的移動
- AarrayList 自由度較低,須要手動設置固定的大小,可是它的操做比較方便的,①直接建立②添加對象③根據下標進行使用
- LinkList 自由度較高,可以動態的隨數組的數據量而變化
- ArrayList 主要開銷在List須要預留必定空間
- LinkList 主要開銷在須要存儲結點信息以及結點指針信息
- List to Array : 可使用 List 的
toArray()
方法,傳入一個數組的類型例如Stirng[] strs = strList.toArray(new String[strList.size()]);
- Array to List : 可使用
java.util.Arrays
的asList()
方法 例如List<String> strList = Arrays.asList(strs);
- ArrayList 是非線程安全的,而 Vector 使用了
Synchronized
來實現線程同步的- ArrayList 在性能方面要優於 Vector
- ArrayList 和 Vector 都會根據實際狀況來動態擴容的,不一樣的是 ArrayList 擴容到原大小的1.5倍,而 Vector 擴容到原大小的2倍
- Array 是數組,當定義數組時,必須指定數據類型及數組長度
- ArrayList 是動態數組,長度能夠動態改變,會自動擴容,不使用泛型的時候,能夠添加不一樣類型元素
- poll() 和 remove() 都是從隊列頭刪除一個元素,若是隊列元素爲空,remove() 方法會拋出
NoSuchElementException
異常,而 poll() 方法只會返回 null
- Vector :比 ArrayList 多了同步化機制(線程安全)
- HashTable :比 HashMap 多了線程安全
- ConcurrentHashMap :是一種高效可是線程安全的集合
- Stack :棧,繼承於 Vector 也是線程安全
Iterator
是集合專用的遍歷方式Iterator<E> iterator()
: 返回此集合中元素的迭代器,經過集合的iterator()
方法獲得,因此Iterator
是依賴於集合而存在的
Iterator 的使用方法
java.lang.Iterable
接口被java.util.Collection
接口繼承,java.util.Collection
接口的iterator()
方法返回一個Iterator
對象next()
方法獲取集合中下一個元素hasNext()
方法檢查集合中是否還有元素remove()
方法將迭代器新返回的元素刪除
Iterator 的特色
- Iterator 遍歷集合過程當中不容許線程對集合元素進行修改
- Iterator 遍歷集合過程當中能夠用
remove()
方法來移除元素,移除的元素是上一次Iterator.next()
返回的元素- Iterator 的
next()
方法是經過遊標指向的形式返回Iterator下一個元素
- 使用範圍不一樣
- Iterator 適用於全部集合, Set、List、Map以及這些集合的子類型,而 ListIterator 只適用於 List 及其子類型
- ListIterator 有 add() 方法,能夠向 List 中添加元素,而 Iterator 不能
- ListIterator 和 Iterator 都有 hasNext() 和 next() 方法,來實現順序向後遍歷。而 ListIterator 有 hasPrevious() 和 previous() 方法,能夠實現逆向遍歷,可是 Iterator 不能
- ListIterator 可使用 nextIdnex() 和 previousIndex() 方法定位到當前索引位置,而 Iterator 不能
- 它們均可以實現 remove() 刪除操做,可是 ListIterator 可使用 set() 方法實現對象修改,而 Iterator 不能
- 能夠採用
java.util.Collections
工具類Collections.unmodifiableMap(map)
Collections.unmodifiableList(list)
Collections.unmodifiableSet(set)
- 如諾修改則會報錯
java.lang.UnsupportedOperationException
- 併發:不一樣的代碼塊交替執行
- 並行:不一樣的代碼塊同時執行
- 我的理解
- 併發就是放下手頭的任務A去執行另一個任務B,執行完任務B後,再回來執行任務A,就好比說吃飯時來電話了,去接電話,打完電話後又回來吃飯
- 並行就是執行A的同時,接受到任務B,而後我一塊兒執行,就好比說吃飯時來電話了,一邊吃飯一邊打電話
- 根本區別 :進程是操做系統資源分配的基本單位,而線程是任務調度和執行的基本單位
- 在操做系統中能同時運行多個進程,進程中會執行多個線程
- 線程是操做系統可以進行運算調度的最小單位
- JVM內部的實現是若是運行的程序只剩下守護線程的話,程序將終止運行,直接結束。因此守護線程是做爲輔助線程存在的
- 繼承Thread類建立線程類
- 定義
Thread
類的子類,並重寫該類的run()
方法- 建立
Thread
子類的實例,即建立了線程對象- 調用線程對象的
start()
方法來啓動該線程
- 實現Runnable接口建立線程類
- 建立
runnable
接口的實現類,並重寫該接口的run()
方法- 建立
Runnable
實現類的實例,並依此實例做爲Thread的target
來建立Thread
對象,該Thread
對象纔是真正的線程對象- 調用線程對象的
start()
方法來啓動該線程
- 經過 Callable 和 Future 建立線程
- 建立
Callable
接口的實現類,並重寫call()
方法,該call()
方法將做爲線程執行體,而且有返回值- 建立
Callable
實現類的實例,使用FutureTask
類來包裝Callable
對象,該FutureTask
對象封裝了該Callable
對象的call()
方法的返回值- 使用
FutureTask
對象做爲Thread
對象的target
建立並啓動新線程- 調用
FutureTask
對象的get()
方法來得到子線程執行結束後的返回值
- 相同點
- 都是接口
- 均可以編寫多線程程序
- 都是採用
Thread.start()
啓動線程
- 不一樣點
Runnable
沒有返回值,Callable
能夠返回執行結果,是個泛型和Future
、FutureTask
配合能夠用來獲取異步執行的結果Callable
接口的call()
方法容許拋出異常,Runnable
的run()
方法異常只能在內部消化,不能往上繼續拋注意
Callalble
接口支持返回執行結果,須要調用FutureTask.get()
獲得,此方法會阻塞主進程的繼續往下執行,若是不調用不會阻塞
- 新建 就緒 運行 阻塞 死亡
- 最大區別是sleep() 休眠時不釋放同步對象鎖,其餘線程沒法訪問 而wait()休眠時,釋放同步對象鎖其餘線程能夠訪問
- sleep() 執行完後會自動恢復運行不須要其餘線程喚起.而 wait() 執行後會放棄對象的使用權,其餘線程能夠訪問到,須要其餘線程調用 Monitor.Pulse() 或者 Monitor.PulseAll() 來喚醒或者通知等待隊列
- start() 是來啓動線程的
- run() 只是 Thread 類中一個普通方法,仍是在主線程中執行
notify()
方法隨機喚醒對象的等待池中的一個線程,進入鎖池notifyAll()
喚醒對象的等待池中的全部線程,進入鎖池。
- 利用
Executors
建立線程池
newCachedThreadPool()
,它是用來處理大量短期工做任務的線程池newFixedThreadPool(int nThreads)
,重用指定數目nThreads
的線程newSingleThreadExecutor()
,它的特色在於工做線程數目限制爲1newSingleThreadScheduledExecutor()
和newScheduledThreadPool(int corePoolSize)
,建立的是個ScheduledExecutorService
,能夠進行定時或週期性的工做調度,區別在於單一工做線程仍是多個工做線程。newWorkStealingPool(int parallelism)
,這是一個常常被人忽略的線程池,Java 8
才加入這個建立方法,其內部會構建ForkJoinPool
,利用Work-Stealing
算法,並行地處理任務,不保證處理順序
- 運行 RUNNING:線程池一旦被建立,就處於
RUNNING
狀態,任務數爲 0,可以接收新任務,對已排隊的任務進行處理- 關閉 SHUTDOWN:不接收新任務,但能處理已排隊的任務。調用線程池的
shutdown()
方法,線程池由RUNNING
轉變爲SHUTDOWN
狀態- 中止 STOP:不接收新任務,不處理已排隊的任務,而且會中斷正在處理的任務。調用線程池的
shutdownNow()
方法,線程池由(RUNNING
或SHUTDOWN
) 轉變爲STOP
狀態- 整理 TIDYING:
SHUTDOWN
狀態下,任務數爲 0, 其餘全部任務已終止,線程池會變爲 TIDYING 狀態,會執行terminated()
方法。線程池中的terminated()
方法是空實現,能夠重寫該方法進行相應的處理- 線程池在
SHUTDOWN
狀態,任務隊列爲空且執行中任務爲空,線程池就會由 SHUTDOWN 轉變爲TIDYING
狀態- 線程池在
STOP
狀態,線程池中執行中任務爲空時,就會由STOP
轉變爲TIDYING
狀態
- 終止 TERMINATED:線程池完全終止。線程池在 TIDYING 狀態執行完 terminated() 方法就會由 TIDYING 轉變爲
TERMINATED
狀態
- 兩個方法均可以向線程池提交任務
execute()
方法的返回類型是void
,它定義在Executor
接口中- 而
submit()
方法能夠返回持有計算結果的Future
對象,它定義在ExecutorService
接口中
- 使用synchronied關鍵字
- 使用volatile 關鍵字,防止指令重排,全部對該變量讀寫都是直接操做共享內存
- lock鎖機制
lock()
與unlock()
- 使用線程安全的類 好比
StringBuffer
、HashTable
、Vector
等線程安全問題主要是:原子性,可見性,有序性
- 做用
- synchronized 表示只有一個線程能夠獲取做用對象的鎖,執行代碼,阻塞其餘線程
- volatile 表示變量在
CPU
的寄存器中是不肯定的,必須從主存中讀取。保證多線程環境下變量的可見性,禁止指令重排序
- 區別
synchronized
能夠做用於變量、方法、對象。volatile
只能做用於變量synchronized
能夠保證線程間的有序性、原子性和可見性。volatile
只保證了可見性和有序性,沒法保證原子性synchronized
線程阻塞,volatile
線程不阻塞
synchronized
是一個Java
關鍵字,在jvm
層面上,而Lock
是一個類synchronized
以獲取鎖的線程執行完同步代碼,釋放鎖,若是線程中發生異常,jvm
會讓線程釋放鎖。而Lock
必須在finally
中釋放鎖,不然容易形成線程死鎖Lock
能夠查看鎖的狀態,而synchronized
不能- 在性能上來講,若是競爭資源不激烈,二者的性能是差很少的,而當競爭資源很是激烈時(即有大量線程同時競爭),此時
Lock
的性能要遠遠優於synchronized
。因此說,在具體使用時要根據適當狀況選擇synchronized
是非公平鎖,而Lock
是可公平鎖
- 輕量
非侵入型框架
- 控制反轉
IOC
,促進了鬆耦合- 面向切面編程
AOP
- 容器 採用Java Bean 代替 沉重的
EJB
容器- 方便集成 能夠和不少框架相互集成如
Mybatis
、Shiro
- 豐富的功能 Spring 已經寫好了不少常的模板如
JDBC抽象類
、事務管理
、JMS
、JMX
、Web Service
...等
AOP
是面向切面編程,是OOP
編程的有效補充AOP
包括Aspect
切面,Join Point
鏈接點,Advice
通知,Ponitcut
切點其中
Advice
通知包括5中模式
Before advice
:方法執行前‘加強’After returning advice
:方法執行後‘加強’After throwing advice
:方法執行中拋出異常時‘加強’After finally advice
:方法執行完後‘加強’Around advice
:環繞加強‘以上四種的整合’
- IOC是控制反轉,是將代碼自己的控制權移到外部Spring容器中進行集中管理,也是爲了達到鬆耦合
- Spring Core
- 框架基礎部分,提供了
IOC
容器,對Bean
進行集中管理
- Spring Context
- 基於
Bean
,提供上下文信息
- Spring Dao
- 提供了
JDBC
的抽象層,它可消除冗長的JDBC
編碼,提供了聲明性事務管理方法
- Spring ORM
- 提供了
對象/關係
映射經常使用的API
集成層,如Mybatis
、Hibernate
等
- Spring Aop
- 提供了
AOP
面向切面的編程實現
- Spring Web
- 提供了
Web
開發的信息上下文,可與其餘的Web
集成開發
- Spring Web Mvc
- 提供了
Web
應用的Model - View - Controller
全功能的實現
- 構造方法注入
- Setter方法注入
不過值得一提的是:Setter注入時若是寫了帶參構造方法,那麼無參構造方法必須也要寫上,不然注入失敗
- 基於註解得注入
基本上有五種經常使用註冊
Bean
的註解
@Component
:通用註解@Controller
:註冊控制層Bean@Service
:註冊服務層Bean@Repository
:註冊Dao層Bean@Configuration
:註冊配置類
- 線程不安全
- Spring容器中的Bean是否線程安全,容器自己並無提供Bean的線程安全策略,所以能夠說Spring容器中的Bean自己不具有線程安全的特性
singleton
:單例,默認的做用域prototype
:原型,每次都會建立新對象request
:請求,每次Http請求都會建立一個新對象session
:會話,同一個會話建立一個實例,不一樣會話使用不一樣實例global-session
:全局會話,全部會話共享一個實例
- 後面三種只有在Web應用中使用Spring纔有效
- 編程式事務管理對基於
POJO
的應用來講是惟一選擇,咱們須要在代碼中調用beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理- 基於 TransactionProxyFactoryBean的聲明式事務管理
- 基於 @Transactional 的聲明式事務管理
- 基於Aspectj AOP配置事務
- 用戶發送一個請求至前端控制器
DispatcherServlet
DispatcherServlet
收到請求調用處理器映射器HandlerMapping
- 處理器映射器根據請求
url
找到具體的處理器,生成處理器執行鏈HandlerExecutionChain
(包括處理器對象和處理器攔截器)一併返回給DispatcherServlet
DispatcherServlet
根據處理器Handler獲取處理器適配器HandlerAdapter
執行HandlerAdapter
處理一系列的操做- 執行處理器
Handler
(Controller
,也叫頁面控制器)Handler
執行完成返回ModelAndView
到HandlerAdapter
HandlerAdapter
將Handler
執行結果ModelAndView
返回到DispatcherServlet
DispatcherServlet``將ModelAndView
傳給ViewReslover
視圖解析器ViewReslover
解析後返回具體View
DispatcherServlet
對View
進行渲染視圖(即將模型數據model
填充至視圖中)DispatcherServlet
響應用戶
DispatcherServlet
:前端控制器HandlerMapping
:處理器映射器HandlerAdapter
:處理器適配器HandlerInterceptor
:攔截器ViewResolver
:視圖解析器MultipartResolver
:文件上傳處理器HandlerExceptionResolver
:異常處理器DataBinder
:數據轉換HttpMessageConverter
:消息轉換器FlashMapManager
:頁面跳轉參數管理器HandlerExecutionChain
:處理程序執行鏈RequestToViewNameTranslator
:請求轉視圖翻譯器ThemeResolver
:LocaleResolver
:語言環境處理器
@RequestMapping
是一個註解,用來標識http
請求地址與Controller
類的方法之間的映射- 指定 http 請求的類型使用
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
@Autowired
爲Spring
提供的註解,須要導入包org.springframework.beans.factory.annotation.Autowired
,採起的策略爲按照類型注入@Resource
註解由J2EE提供,須要導入包javax.annotation.Resource
,默認按照ByName
自動注入
- #{} 表示一個佔位符
能夠有效的防止SQL注入
- ${} 表示拼接SQL串
能夠用於動態判斷字段
order by ${field} desc
能夠動態修改fieId來達到動態根據字段降序查詢
- 原始分割
取出數據後,進行手動分割
- LIMIT關鍵字
修改執行SQL語句
- RowBounds實現分頁
將
PageInfo
信息封裝成RowBounds
,調用DAO層方法
- Mybatis的Interceptor實現
原理就是執行SQL語句前,在原SQL語句後加上limit關鍵字,不用本身去手動添加
RowBounds
表面是在「全部」數據中檢索數據,其實並不是是一次性查詢出全部數據,由於 MyBatis 是對 jdbc 的封裝,在 jdbc 驅動中有一個 Fetch Size 的配置,它規定了每次最多從數據庫查詢多少條數據,假如你要查詢更多數據,它會在你執行 next()的時候,去查詢更多的數據。就比如你去自動取款機取 10000 元,但取款機每次最多能取 2500 元,因此你要取 4 次才能把錢取完。只是對於 jdbc 來講,當你調用 next()的時候會自動幫你完成查詢工做。這樣作的好處能夠有效的防止內存溢出。
- 邏輯分頁是一次性查詢不少數據,而後再在結果中檢索分頁的數據。這樣作弊端是須要消耗大量的內存、有內存溢出的風險、對數據庫壓力較大。
- 物理分頁是從數據庫查詢指定條數的數據,彌補了一次性所有查出的全部數據的種種缺點,好比須要大量的內存,對數據庫查詢壓力較大等問題
- MyBatis 支持延遲加載,設置
lazyLoadingEnabled=true
便可- 延遲加載的原理的是調用的時候觸發加載,而不是在初始化的時候就加載信息。好比調用
a.getB().getName()
,這個時候發現a.getB()
的值爲null
,此時會單獨觸發事先保存好的關聯 B 對象的 SQL,先查詢出來 B,而後再調用a.setB(b)
,而這時候再調用a.getB(). getName()
就有值了,這就是延遲加載的基本原理
- 一級緩存
- 基於
PerpetualCache
的HashMap
本地緩存,它的聲明週期是和SQLSession
一致的,有多個SQLSession
或者分佈式的環境中數據庫操做,可能會出現髒數據- 當
Session flush
或close
以後,該Sessio
中的全部Cache
就將清空,默認一級緩存是開啓的
- 二級緩存
- 也是基於
PerpetualCache
的HashMap
本地緩存,不一樣在於其存儲做用域爲Mapper
級別的,若是多個SQLSession
之間須要共享緩存,則須要使用到二級緩存- 二級緩存可自定義存儲源,如 Ehcache。默認不打開二級緩存,要開啓二級緩存,使用二級緩存屬性類須要實現
Serializable
序列化接口(可用來保存對象的狀態)
- 擴展
- 開啓二級緩存後的查詢流程:
二級緩存 -> 一級緩存 -> 數據庫
- 緩存更新機制:當某一個做用域(一級緩存 Session/二級緩存 Mapper)進行了C/U/D 操做後,默認該做用域下全部 select 中的緩存將被 clear
- Mybatis 更加靈活,能夠本身寫SQL語句
- 也正是本身寫了不少SQL語句,因此移植性比較差
- Mybatis 入門比較簡單,使用門檻也低
- hibernate 能夠自行把二級緩存更換爲第三方的
SimpleExecutor
:每執行一次UPDATE\SELECT
就開啓一個Statement
對象,用完後當即關閉ReuseExecutor
:執行 UPDATE\SELECT,以 SQL 做爲 key 查找
Statement對象,存在就使用,不存在就建立,用完後不關閉
Statement對象,而是放置於 Map 內供下一次使用。簡言之,就是重複使用
Statement`對象BatchExecutor
:執行UPDATE
(沒有 select,jdbc 批處理不支持 select),將全部 SQL 都添加到批處理中addBatch()
,等待統一執行executeBatch()
,它緩存了多個Statement
對象,每一個Statement
對象都是addBatch()
完畢後,等待逐一執行executeBatch()
批處理,與 jdbc 批處理相同
- 分頁插件的基本原理是使用 MyBatis 提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的 SQL,而後重寫 SQL,根據 dialect 方言,添加對應的物理分頁語句和物理分頁參數
MyBatis 自定義插件針對 MyBatis 四大對象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)進行攔截
- Executor:攔截內部執行器,它負責調用 StatementHandler 操做數據庫,並把結果集經過 ResultSetHandler 進行自動映射,另外它還處理了二級緩存的操做
. StatementHandler:攔截 SQL 語法構建的處理,它是 MyBatis 直接和數據庫執行 SQL 腳本的對象,另外它也實現了 MyBatis 的一級緩存- ParameterHandler:攔截參數的處理
- ResultSetHandler:攔截結果集的處理
MyBatis 插件要實現 Interceptor 接口
- setProperties 方法是在 MyBatis 進行配置插件的時候能夠配置自定義相關屬性,即:接口實現對象的參數配置
- plugin 方法是插件用於封裝目標對象的,經過該方法咱們能夠返回目標對象自己,也能夠返回一個它的代理,能夠決定是否要進行攔截進而決定要返回一個什麼樣的目標對象,官方提供了示例:return Plugin. wrap(target, this)
- intercept 方法就是要進行攔截的時候要執行的方法
public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties); }
官方插件實現:
@Intercepts({@Signature(type = Executor. class, method = "query", args = {MappedStatement. class, Object. class, RowBounds. class, ResultHandler. class})}) public class TestInterceptor implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { Object target = invocation. getTarget(); //被代理對象 Method method = invocation. getMethod(); //代理方法 Object[] args = invocation. getArgs(); //方法參數 // do something . . . . . . 方法攔截前執行代碼塊 Object result = invocation. proceed(); // do something . . . . . . . 方法攔截後執行代碼塊 return result; } public Object plugin(Object target) { return Plugin. wrap(target, this); } }
具體案例請看 Mybatis 實現自定義插件 通俗易懂
InnoDB 和 Myisam 都是用 B+Tree 來存儲數據的
- InnoDB 支持事務,且支持四種隔離級別(讀未提交、讀已提交、可重複讀、串行化),默認的爲可重複讀.
- Myisam 只支持表鎖,且不支持事務.Myisam 因爲有單獨的索引文件,在讀取數據方面的性能很高.
- 在項目配置文件中生命自定義的
key
,在項目啓動時會判斷redis是否存在key
,若是沒有就會建立一個key
傳入null
值- 數據加熱的含義就是在正式部署以前,我先把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數據就會加載到緩存中
緩存雪崩是指,緩存層出現了錯誤,不能正常工做了.因而全部的請求都會達到存儲層,存儲層的調用量會暴增,形成存儲層也會掛掉的狀況.
解決方案
- redis 高可用 就是搭建 redis 集羣,其中一臺redis掛掉後 可使用其餘的 redis
- 限流降級 就是每個 key 只能一個線程來查詢數據和緩存,其餘線程等待
- 數據預熱 數據加熱的含義就是在正式部署以前,我先把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數據就會加載到緩存中.在即將發生大併發訪問前手動觸發加載緩存不一樣的 key ,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻.*
就是訪問redis數據庫,查不到數據,就是沒有命中,會去持久化數據庫查詢,仍是沒有查到.假如高併發的狀況下,持久化數據庫一下增長了很大壓力,就至關於出現了緩存穿透
解決方案
- 緩存空對象 在存儲層命中失敗後,即便返回空對象也將其緩存,並設置一個過時時間,以後訪問的這個數據將會從緩存中取出,很好的保護了後端數據源,這樣也會有出現問題 例如空值被緩存也就會增長大量的緩存空間,設置了過時時間仍是會存在緩存層和存儲層的數據會有一段時間窗口的不一致,這對於須要保持一致性的業務會有影響
- 布隆過濾器 對全部可能查詢的參數以 hash 形式存儲,查詢時發現值不存在就直接丟棄,不會去持久層查詢
RabbitMQ 對於 queue 中的 message 的保存方式有兩種方式:disc 和 ram.若是採用disc,則須要對 exchange/queue/delivery mode 都要設置成 durable 模式. Disc 方式的好處是當 RabbitMQ 失效了, message 仍然能夠在重啓以後恢復.而使用 ram 方式, RabbitMQ 處理 message 的效率要高不少, ram 和 disc 兩種方式的效率比大概是 3:1.因此若是在有其它 HA 手段保障的狀況下,選用 ram 方式是能夠提升消息隊列的工做效率的.
- 棧內存用來存儲局部變量和方法調用
- 而堆內存用來存儲 Java 中的對象.不管是成員變量,局部變量,仍是類變量.,它們指向的對象都存儲在堆內存中.
- 棧內存歸屬單個線程,一個棧對應一個線程,其中儲存的變量只能在該線程中能夠訪問到,也能夠理解爲私有內存
- 而堆內存中的對象 全部線程都可見,堆內存中對象能夠被全部線程訪問到
- 棧內存要遠小於堆內存
在類裏使用 implements 關鍵字實現 Api 接口
- Mybatis 框架
- Hibernate 框架
- JDBC 技術
- c3p0 鏈接池
- dbcp 鏈接池
在 pom.xml 文件引入 redis 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
在 application 配置文件中 書寫 redis 配置
spring.redis.host=127.0.0.1 #Redis服務器鏈接端口 spring.redis.port=6379 #Redis服務器鏈接密碼(默認爲空) #spring.redis.password=
- 服務之間採用Restful等輕量級通信
- 精準的制定優化服務方案,提升系統的可維護性
- 服務之間拆分細緻,資源可重複利用,提升開發效率
- netflix Eureka 註冊中心
- netflix Ribbon 負載均衡
- netflix Zuul 網關
- netflix Hystrix 熔斷器
- feign 服務調用
- List 容許有多個重複對象,而 Set 不容許有重複對象
- List 容許有多個NULL值,而 Set 只容許有一個NULL值
- List 是一個有序的容器,輸出順序便是輸入順序
- Set 是一個無序的容器沒法保證每一個元素的順序,可是能夠用 TreeSet 經過 Comparator 或者 Comparable 維護排序順序
- List的實現類有 ArrayList、LinkList、Vector 其中 ArrayList 最經常使用於查詢較多,隨意訪問.LinkList 同於新增和刪除較多的狀況,Vector 表示底層數組,線程安全象
- Set的實現類有 HashSet、TreeSet、LinkedHashSet 其中基於 HashMap 實現的 HashSet 最爲流行,TreeSet 是一個有序的Set容器象
擴展
Map的實現類有HashMap、HashTable、TreeMap
- 表示全局或靜態的意思、用來修飾成員變量和成員方法,也能夠造成靜態代碼塊
- 達到了不用實例化就可使用被 public static 修飾的變量或方法
保證整個項目中一個類只有一個對象的實例,實現這種功能就叫作單例模式
- 單例模式的好處:
- 單例模式節省公共資源
- 單例模式方便控制
- 如何保證是單利模式 ?
- 構造私有化
- 以靜態方法返回實例
- 確保對象實例只有一個
- 單例模式有哪幾個 ?
- 餓漢模式
把對象建立好,須要使用的時候直接拿到就行
- 懶漢模式
等你須要的時候在建立對象,後邊就不會再次建立
- @SpringBootApplication SpringBoot的核心註解 啓動類
- @EnableAutoConfiguration 開啓SpringBoot自動配置
- @RestController 在控制層 是@ResponseBody註解與@Controller註解的合集
- @RequestMapper 處理請求地址映射的註解
- @RequestParam 獲取url上傳過來的參數
- @Configuration 聲明配置類
- @Component 通用註解
- @Service 業務邏輯層
char 字符型 byte 字節型 boolean 布爾型
float 單浮點型 double 雙浮點型
int 整數型 short 短整數型 long 長整數型
- 能夠用 limit
select
name
,age
,sex
from t_student limit(0,5);
- 升序 order by xx asc
select
name
,age
,sex
from t_student order byage
asc;
- 降序 order by xx desc
select
name
,age
,sex
from t_student order byage
desc;
- maven 專門構建和管理Java項目的工具
- maven的好處在於能夠將項目過程規範化、自動化、高效化以及強大的可擴展性
- 建立索引 儘可能避免全盤掃描 首先考慮在 where 和 order by 涉及的列上建立索引
- 避免在索引上使用計算 注意就是IN關鍵字不走索引,它是走全盤掃描
- 使用預編譯防止 sql 注入
- 儘可能將多條 SQL語句壓縮到一條 SQL 語句中
- 最最最好的就是少用 * , 應該寫成要查詢的字段名,儘可能避免在 where 條件中判斷 null
- 儘可能不用like 的前置百分比
- 對於連續的數值,能用 between 就不要用 in
- 在新建臨時表時,若是一次性插入數據量較大.能夠用 select into 代替 create table
- PRIMARY KEY (主鍵索引)
- 添加INDEX(普通索引) ALTER TABLE
table_name
ADD INDEX index_name (column
)- 添加FULLTEXT(全文索引) ALTER TABLE
table_name
ADD FULLTEXT (column
)- 添加多列索引 ALTER TABLE
table_name
ADD INDEX index_name (column1
,column2
,column3
)
MySQL 索引底層的實現方式是 B+Tree也就是B+樹 具體查看 B+Tree實現方式
使用v-mode屬性, 它的原理是利用了Object.defineProperty()方法從新定義了對象獲取屬性值(get)和設置屬性值(set)的操做來實現的
- 採起先進先出模式,同一時間,消息只會發送給某一個消費者,只有當該消息被消費並告知已收到時,它才能在代理的存儲中被刪除.
- 對於持久性訂閱來講,每個消費者都會獲取消息的拷貝.爲了節約空間,代理的存儲介質中只存儲了一份消息,存儲介質的持久訂閱對象爲其之後的被存儲的消息維護了一個指針,消費者消費時,從存儲介質中複製一個消息.消息被全部訂閱者獲取後才能刪除.
基於文件的消息存儲機制,爲了提升消息存儲的可靠性和可恢復性,它整合了一個事務日誌.KahaDB擁有高性能和可擴展性等特色.因爲KahaDB使用的是基於文件的存儲,因此不須要使用第三方數據庫