javq學(xué)習(xí)

1、面向?qū)ο螅?/h4>

面向?qū)ο笙鄬?duì)應(yīng)的就是面向過程亥鸠,而面向過程就是注重事情的一個(gè)步驟和順序妆够,而面向?qū)ο笞⒅氐氖菂⑴c者识啦,而參與者里面每個(gè)對(duì)象負(fù)責(zé)干那些事情,面向過程比較直接高效神妹,而面向過程更易于復(fù)用颓哮,擴(kuò)展和維護(hù)
面向?qū)ο蟮奶攸c(diǎn):封裝,繼承鸵荠,多態(tài)
封裝:封裝的意義在于明確標(biāo)識(shí)允許外部使用的所有成員函數(shù)和數(shù)據(jù)項(xiàng)冕茅,內(nèi)部細(xì)節(jié)對(duì)外部隱藏,外部調(diào)用無需修改或者關(guān)心內(nèi)部實(shí)現(xiàn)
繼承:繼承基類的方法腰鬼,并做出自己的改變和擴(kuò)展嵌赠,子類共性的方法或者屬性直接使用父類的,而不需要自己在定義熄赡,只需要擴(kuò)展自己個(gè)性化的
多態(tài):基于對(duì)象所屬類的不同姜挺,外部對(duì)同一個(gè)方法的調(diào)用,實(shí)際執(zhí)行的邏輯不同

2彼硫、==和equals的區(qū)別:

==對(duì)于基本數(shù)據(jù)來說是比較他們的值炊豪,對(duì)于對(duì)象來說就是比較他們?cè)诙阎械牡刂罚簿褪潜容^他們是不是同一個(gè)實(shí)例拧篮,

//這個(gè)是str1的值是在棧里面的
String str1 = "Hello" 
//這是new出來了一個(gè)對(duì)象词渤,數(shù)據(jù)保存在堆里面的
String str2 = new String("Hello") 
//這是通過的引用賦值,也就是str3和str2指向的同一個(gè)地址
String str3 = str2;

3串绩、String,StringBuffer,StringBuilder的區(qū)別和使用場景:

String是使用final修飾的缺虐,每次操作都會(huì)產(chǎn)生新的String對(duì)象
StringBuffer和StringBuilder都是在原對(duì)象上面操作的
StringBuffer是線程安全的,StringBuilder是線程不安全的
StringBuffer方法都是Synchronized修飾的
性能:StringBuilder>StringBuffer>String
優(yōu)先使用使用StringBuilder,多線程使用共享變量時(shí)使用StringBuffer

4礁凡、重載和重寫的區(qū)別:

重載是發(fā)生在同一個(gè)類中高氮,方法名必須相同,參數(shù)類型不同顷牌,個(gè)數(shù)不同剪芍,順序不同,方法返回值和訪問修飾符可以不同窟蓝,發(fā)生在編譯時(shí)
重寫:發(fā)生在父子類中罪裹,方法名,參數(shù)列表必須相同运挫,返回值范圍小于等于父類状共,拋出的異常范圍小于等于父類,訪問修飾符范圍大于等于父類,如果父類的方法訪問修飾符為private則子類就不能重寫該方法

5、接口和抽象類的區(qū)別:

  • 抽象類中可以存在普通成員函數(shù)蠢笋,而接口類中只能存在public abstract方法
  • 抽象類中的成員變量可以實(shí)各種類型的,而接口類中的成員變量只能是public static final類型的
  • 抽象類只能繼承一個(gè)鬓椭,接口可以實(shí)現(xiàn)多個(gè)
    接口設(shè)計(jì)的目的是對(duì)類的行為進(jìn)行約束颠猴,他只約束了行為的有無,彈不對(duì)具體實(shí)現(xiàn)進(jìn)行限制小染,抽象類不允許實(shí)例化
    抽象類的設(shè)計(jì)目的是代碼復(fù)用翘瓮,當(dāng)不同的類具有相同的行為,且其中實(shí)現(xiàn)方式一致時(shí)裤翩,可以讓這些類派生出一個(gè)抽象類
    抽象類是對(duì)類本質(zhì)的抽象资盅,表達(dá)的是is a的關(guān)系,抽象類包含了子類通用特性踊赠,將子類存在差異化的特性進(jìn)行抽象呵扛,交由子類去實(shí)現(xiàn)
    而接口是對(duì)行為的抽象,表達(dá)的是like a的關(guān)系筐带,接口核心是定義行為今穿,即實(shí)現(xiàn)類可以做什么具體怎么做,接口并不關(guān)心
    使用場景:當(dāng)你關(guān)注一個(gè)事物的本質(zhì)的時(shí)候伦籍,用抽象類蓝晒,當(dāng)你關(guān)注一個(gè)操作的時(shí)候,用接口
    抽象類的功能遠(yuǎn)超過于接口帖鸦,但是接口的代價(jià)高芝薇,因?yàn)槊總€(gè)類只能繼承一個(gè)父類,在這個(gè)類中你就需要寫出子類的所有共性作儿,但是卻可以實(shí)現(xiàn)多個(gè)接口洛二,在設(shè)計(jì)階段降低了難度

6、List和Set的區(qū)別:

  • List: 有序攻锰,按對(duì)象進(jìn)入的順序保存對(duì)象灭红,可重復(fù),允許多個(gè)null 元素對(duì)象口注,可以使用Iterator取出所有元素,在逐一遍歷君珠,還可以根據(jù)下標(biāo)索引的方式獲取指定索引的元素
  • Set:無序寝志,不可重復(fù),最多只允許一個(gè)null元素策添,取元素的時(shí)候只能通過Iterator接口取得所有的元素材部,再逐一遍歷各個(gè)元素

7、hashcode與equals

  • 如果兩個(gè)對(duì)象相等唯竹,則hashCode也一定也是相同的
  • 兩個(gè)對(duì)象相等乐导,兩個(gè)對(duì)象分別調(diào)用equals方法都返回true
  • 兩個(gè)對(duì)象有相同的hashcode值,他們也不太一定的相等的
  • equals方法被覆蓋浸颓,則hashcode方法也必須被覆蓋
  • hashcode的默認(rèn)行為是對(duì)堆上的對(duì)象產(chǎn)生的獨(dú)特值物臂,如果沒有重寫hashcode旺拉,則兩個(gè)對(duì)象無論如何都不會(huì)相等(即使這兩個(gè)對(duì)象指向相同的數(shù)據(jù))

8、ArrayList和LinkedList區(qū)別

  • ArrayList: 基于動(dòng)態(tài)數(shù)組棵磷,連續(xù)內(nèi)存存儲(chǔ)蛾狗,適合下標(biāo)訪問,擴(kuò)容機(jī)制仪媒,因?yàn)閿?shù)組長度固定沉桌,超出長度存數(shù)據(jù)需要重新建數(shù)組,然后將老數(shù)組拷貝到新數(shù)組算吩,如果不是尾部插入數(shù)據(jù)還會(huì)涉及到數(shù)據(jù)的移動(dòng)留凭,(往后復(fù)制一份,插入新元素)偎巢,使用尾插法并指定初始容量可以極大的提高性能蔼夜,甚至超過linkedlist(需要大量創(chuàng)建node節(jié)點(diǎn))
  • 基于鏈表,可以存儲(chǔ)在分散的內(nèi)存中艘狭,適合做數(shù)據(jù)插入及刪除操作挎扰,不適合做查詢,需要逐一遍歷linkedlist必須使用iterator不能使用for循環(huán)巢音,因?yàn)槊看蝔or循環(huán)體內(nèi)通過get(i)取得某一元素時(shí)都需要對(duì)list重新進(jìn)行遍歷遵倦,性能消耗極大,另外官撼,不要嘗試用indexof對(duì)其進(jìn)行遍歷梧躺,因?yàn)楫?dāng)沒有這個(gè)數(shù)據(jù)的時(shí)候會(huì)將整個(gè)鏈表進(jìn)行遍歷,這樣極其消耗性能

9傲绣、HashMap和HashTable的區(qū)別

區(qū)別:

  • HashMap方法沒有synchronized修飾掠哥,線程非安全,HashTable線程安全
  • HashMap允許key 和value為null,而HashTable不允許
    底層實(shí)現(xiàn):數(shù)組+鏈表
    jdk8開始鏈表高度到8秃诵,數(shù)組長度達(dá)到64续搀,鏈表轉(zhuǎn)變?yōu)榧t黑樹,元素以內(nèi)部類node節(jié)點(diǎn)存在
  • 計(jì)算key的hash值菠净,二次hash然后對(duì)數(shù)組長度取模禁舷,對(duì)應(yīng)到數(shù)組下標(biāo)
  • 如果沒有產(chǎn)生hash沖突,則直接將創(chuàng)建node存入數(shù)組
  • 如果產(chǎn)生hash沖突毅往,先進(jìn)行equals比較牵咙,相同則取代該元素,不同攀唯,則判斷該鏈表高度插入鏈表洁桌,鏈表高度達(dá)到8,并且數(shù)組長度達(dá)到64則轉(zhuǎn)變?yōu)榧t黑樹侯嘀,長度低于6則將紅黑數(shù)轉(zhuǎn)回鏈表
  • key為null另凌,存儲(chǔ)在下表為0的位置
    數(shù)組擴(kuò)容谱轨,當(dāng)存儲(chǔ)數(shù)據(jù)達(dá)到負(fù)載因子的時(shí)候會(huì)重新創(chuàng)建一個(gè)數(shù)組將其進(jìn)行拷貝過去

10、ConcurrentHashMap原理途茫,jdk7和jdk8的區(qū)別

  • jdk7:
    數(shù)據(jù)結(jié)構(gòu):ReetrantLock + Segment + HashEntry,一個(gè)Segment中包含一個(gè)HashEntry數(shù)組碟嘴,每個(gè)HashEntry又是一個(gè)鏈表結(jié)構(gòu)
    元素查詢:二次hash,第一次Hash定位到Segment,第二次Hash定位到元素所在的鏈表的頭部
    鎖:Segment分段鎖 Segment繼承了ReetrantLock,鎖定操作的Segment,其他的Segment不受影響,并發(fā)度為Segment個(gè)數(shù)囊卜,可以通過構(gòu)造函數(shù)指定娜扇,數(shù)組擴(kuò)容不會(huì)影響其他的Segment
    get方法無需加鎖,volatile保證
  • jdk8:數(shù)據(jù)結(jié)構(gòu)synchronized(擴(kuò)容栅组,hash沖突)+CAS+Node+紅黑樹雀瓢,Node的val和next都用volatile修飾,保證可見性
    查找玉掸,替換刃麸,賦值操作都是用CAS
    鎖:鎖鏈表的head節(jié)點(diǎn),不影響其他元素的讀寫司浪,鎖力度更細(xì)泊业,效率更高,擴(kuò)容時(shí)啊易,阻塞所有的讀寫操作吁伺,并發(fā)擴(kuò)容
    讀操作無鎖:
    Node的val和next使用volatile修飾,讀寫線程對(duì)該變量互相可見
    數(shù)組用volatile修飾租谈,保證擴(kuò)容時(shí)被讀線程感知不去讀臟數(shù)據(jù)

11篮奄、如何實(shí)現(xiàn)一個(gè)IOC容器

1、配置包掃描路徑
2割去、遞歸包掃描獲取.class文件
3窟却、反射,確定需要交給IOC管理的類
4呻逆、對(duì)需要注入的類進(jìn)行依賴注入

  • 配置文件掃描需要的包路徑
  • 定義一些注解夸赫,分別表示訪問控制層,業(yè)務(wù)邏輯層咖城,數(shù)據(jù)持久層憔足,依賴注入注解,獲取配置文件注解
  • 從配置文件中獲取需要掃描的包路徑酒繁,獲取到當(dāng)前路徑下的文件夾信息,我們將當(dāng)前路徑下所有以.class結(jié)尾的文件添加到一個(gè)Set集合中進(jìn)行存儲(chǔ)
  • 遍歷這個(gè)Set集合控妻,獲取在類上有指定注解的類州袒,并將其交給IOC容器,定義一個(gè)安全的Map用來存儲(chǔ)這些對(duì)象
  • 遍歷這個(gè)IOC容器弓候,獲取到每一個(gè)類的實(shí)例郎哭,判斷里面是否有其他依賴他匪,然后進(jìn)行遞歸注入

12、什么是字節(jié)碼夸研,采用字節(jié)碼的好處是什么

java中引入了虛擬機(jī)的概念邦蜜,即在機(jī)器和編譯程序之間加入了一層抽象的虛擬的機(jī)器。這臺(tái)虛擬的機(jī)器在任何平臺(tái)上都提供了一個(gè)共同的接口亥至。
編譯器只需要面向虛擬機(jī)悼沈,生成虛擬機(jī)能夠理解的代碼叫做字節(jié)碼(即擴(kuò)展名為.class的文件),他不面向任何特定的處理器姐扮,只面向虛擬機(jī)
每一種平臺(tái)的解釋器都是不同的絮供,但是實(shí)現(xiàn)的虛擬機(jī)是相同的,java源程序編譯后編程字節(jié)碼茶敏,字節(jié)碼由虛擬機(jī)解釋執(zhí)行壤靶,虛擬機(jī)將每一條需要執(zhí)行的字節(jié)碼送給解釋器,解釋器將其翻譯成特定機(jī)器上的機(jī)器碼惊搏,然后再特定的機(jī)器上運(yùn)行贮乳,這也就是解釋了java的編譯與解釋并存的特點(diǎn)
javay源代碼-->編譯器-->jvm可執(zhí)行的java字節(jié)碼(即虛擬指令)-->jvm-->jvm中解釋器-->機(jī)器可執(zhí)行的二進(jìn)制機(jī)器碼-->程序執(zhí)行
采用字節(jié)碼的好處
java語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言可移植的特點(diǎn)恬惯。所以java程序運(yùn)行時(shí)比較高效向拆,而且,由于字節(jié)碼并不專對(duì)一種特點(diǎn)的機(jī)器宿崭,因此亲铡,java程序無需重新編譯便可在多種不同的機(jī)器上運(yùn)行

13、java類加載器有哪些

jdk自帶有三各類加載器:bootstrapClassloader,ExtClassLoader,AppClassLoader
bootstrapClassloader是ExtClassLoader的父類加載器葡兑,默認(rèn)負(fù)責(zé)加載%JAVA_HOME%/lib下的jar包和class文件
ExtClassLoader是AppClassLoader的父類加載器奖蔓,負(fù)責(zé)加載%JAVA_HOME%/lib/ext文件夾下的jar包和class類
AppClassLoader是自定義類加載器的父類,負(fù)責(zé)加載classpath下的類文件
繼承classloader實(shí)現(xiàn)自定義的類加載器

14讹堤、雙親委派機(jī)制

向上查找緩存吆鹤,直到bootstrapclassloader,這里沒有緩存就會(huì)到相應(yīng)的加載路徑去加載,這里有相應(yīng)的類就會(huì)加載洲守,沒有相應(yīng)的類就會(huì)向下查找(向上查找到頂層疑务,向下查找到自定義類加載器)
雙親委派的好處:

  • 主要是為了其安全性,避免用戶自己編寫的類動(dòng)態(tài)的替換java的一些和心類梗醇,比如String
  • 同時(shí)也避免了類的重復(fù)加載知允,因?yàn)镴VM中區(qū)分不同類,不僅僅是根據(jù)類名叙谨,相同的class文件被不同的ClassLoader加載器加載的就是兩個(gè)類

15温鸽、java中的異常體系

java中的所有的異常都來自頂級(jí)父類Throwable
Throwable下有兩個(gè)子類Exception和Error
Error是程序無法處理的異常,一旦出現(xiàn)這個(gè)錯(cuò)誤,則程序?qū)⒈黄韧V惯\(yùn)行
Exception不會(huì)導(dǎo)致程序停止涤垫,又分為兩部分RunTimeException運(yùn)行時(shí)異常和CheckedException檢查異常
RuntimeException常常發(fā)生在程序運(yùn)行過程中姑尺,會(huì)導(dǎo)致程序當(dāng)前線程執(zhí)行失敗,CheckException常常發(fā)生在程序編譯過程中蝠猬,會(huì)導(dǎo)致程序編譯不通過

16切蟋、GC如何判斷對(duì)象可以被回收

  • 引用計(jì)數(shù)法:每個(gè)對(duì)象有一個(gè)引用技數(shù)屬性,新增一個(gè)引用計(jì)數(shù)加一榆芦,引用釋放時(shí)計(jì)數(shù)減一柄粹,計(jì)數(shù)為0時(shí)可以回收(有一個(gè)缺點(diǎn),兩個(gè)對(duì)象相互引用時(shí)這兩個(gè)對(duì)象就無法回收)
  • 可達(dá)性分析:從GC Roots開始向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連時(shí),則證明此對(duì)象是不可用的活箕,那么虛擬機(jī)就判斷是可回收對(duì)象

GC Roots的對(duì)象有哪些:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象
  • 方法區(qū)中常量引用的對(duì)象
  • 本地方法棧中JNI(即一般說的Native方法)引用的對(duì)象

可達(dá)性分析中的不可達(dá)對(duì)象并不是立即死亡的,對(duì)象擁有一次自我拯救的機(jī)會(huì)欣范,對(duì)象被系統(tǒng)宣告死亡至少經(jīng)歷兩次標(biāo)記過程:第一次是經(jīng)過可達(dá)性分析發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈颤难,第二次是在虛擬機(jī)自動(dòng)建立的Finalize隊(duì)列中判斷是否需要執(zhí)行finalize()方法栈雳。
當(dāng)對(duì)象編程(GC Roots)不可達(dá)時(shí),GC會(huì)判斷該對(duì)象是否覆蓋了finalize方法屠列,若未覆蓋瘦材,則直接將其回收,否則仿畸,若對(duì)象未執(zhí)行finalize方法食棕,將其放入F-Queue隊(duì)列,由一低優(yōu)先級(jí)執(zhí)行該隊(duì)列中對(duì)象的finalize方法颁湖。執(zhí)行finalize方法完畢后宣蠕,GC會(huì)再次判斷該對(duì)象是否可達(dá),若不可達(dá)甥捺,則進(jìn)行回收抢蚀,否則,對(duì)象“復(fù)活”
每個(gè)對(duì)象只能觸發(fā)一次finalize方法
由于finalize方法運(yùn)行代價(jià)高昂镰禾,不確定性大皿曲,無法保證各個(gè)對(duì)象的調(diào)用順序,不推薦大家使用吴侦,減一遺忘他

17屋休、現(xiàn)成的生命周期?線程有幾種狀態(tài)

1.線程通常有5種狀態(tài)备韧,創(chuàng)建劫樟,就緒,運(yùn)行织堂,阻塞和死亡狀態(tài)
2.阻塞狀態(tài)又分為三種:
(1)叠艳、等待阻塞:運(yùn)行的線程執(zhí)行wait方法,該線程會(huì)釋放占用的所有資源易阳,JVM會(huì)把該線程放入“等待池”中附较,進(jìn)入這個(gè)狀態(tài)后,是不能自動(dòng)喚醒的潦俺,必須依賴其他線程調(diào)用notify或notifyAll方法才能被喚醒拒课,wait是object類的方法
(2)徐勃、同步阻塞:運(yùn)行的線程在獲取同步鎖時(shí),若該同步鎖被別的線程占用早像,則jvm會(huì)把該線程放入“鎖池”中
(3)僻肖、其他阻塞:運(yùn)行的線程執(zhí)行sleep或join方法,或則發(fā)出了I/O請(qǐng)求時(shí)卢鹦,JVM會(huì)把該線程設(shè)置為阻塞狀態(tài)檐涝。當(dāng)sleep狀態(tài)超時(shí),join等待線程終止或則超時(shí)法挨,或則I/O處理完畢時(shí),線程重新進(jìn)入就緒狀態(tài)幅聘,sleep是Thread類的方法

  • 新建狀態(tài)(New):新創(chuàng)建了線程對(duì)象
  • 就緒狀態(tài)(Runnable):線程對(duì)象創(chuàng)建后凡纳,其他線程調(diào)用了該對(duì)象的start方法,改狀態(tài)的線程位于可運(yùn)行線程池中帝蒿,變得可運(yùn)行荐糜,等待獲取CPU的使用權(quán)
  • 運(yùn)行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼
  • 阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU的使用權(quán)葛超,暫時(shí)停止運(yùn)行暴氏,線程進(jìn)入就緒狀態(tài),獲取相應(yīng)的資源后轉(zhuǎn)到運(yùn)行狀態(tài)
  • 死亡狀態(tài)(Dead):線程執(zhí)行完了或則因?yàn)楫惓M顺隽藃un方法绣张,該線程結(jié)束生命周期

18答渔、sleep(),wait(),join(),yield()的區(qū)別

1.鎖池:所有線程需要競爭同步鎖的線程都會(huì)放在鎖池中,比如當(dāng)前線程對(duì)象的鎖已經(jīng)被其中一個(gè)線程得到侥涵,則其他線程需要在這個(gè)鎖池進(jìn)行等待沼撕,當(dāng)前面的線程釋放同步鎖后鎖池中的線程去競爭同步鎖,當(dāng)某個(gè)線程得到后就會(huì)進(jìn)入就緒隊(duì)列進(jìn)行等待cpu資源的分配
2.等待池:當(dāng)我們調(diào)用wait方法后芜飘,線程會(huì)釋放到等待池當(dāng)中务豺,等待池的線程是不會(huì)去競爭同步鎖,只有調(diào)用了notify或notifyAll后等待線程才會(huì)開始去競爭鎖嗦明,notify是隨機(jī)從等待池中選出一個(gè)線程放到鎖池笼沥,而notifyAll是將等待池的所有線程放到鎖池當(dāng)中

1.sleep是Thread類的靜態(tài)方法,wait則是Object類的本地方法
2.sleep方法不會(huì)釋放lock娶牌,但是wait會(huì)釋放奔浅,而且會(huì)加入到等待隊(duì)列中

sleep就是把cpu的執(zhí)行資格和執(zhí)行權(quán)釋放出去,不再運(yùn)行此線程裙戏,當(dāng)定時(shí)時(shí)間結(jié)束再取回cpu資源乘凸,參與cpu的調(diào)度,獲取到cpu資源后就可以繼續(xù)運(yùn)行了累榜,而如果sleep時(shí)該線程有鎖营勤,那么sleep不會(huì)釋放這個(gè)鎖灵嫌,而是把鎖帶著進(jìn)入凍結(jié)狀態(tài),也就是說其他需要這個(gè)鎖的線程根本不可能獲取到這個(gè)鎖葛作,寿羞,也就是說無法執(zhí)行程序,如果再睡眠期間其他線程調(diào)用了這個(gè)線程的interrupt方法赂蠢,那么這個(gè)線程也會(huì)拋出interruptexception異常返回绪穆,這點(diǎn)和wait是一樣的

3.sleep方法不依賴于同步器synchronized,但是wait需要依賴synchronized關(guān)鍵字
4.sleep不需要被喚醒,但是wait需要(不指定時(shí)間需要被其他線程喚醒)
5.sleep一般用于當(dāng)前線程休眠虱岂,或則輪詢暫停操作氧骤,wait則多用于多線程之間的通信
6.sleep會(huì)讓出cpu執(zhí)行時(shí)間強(qiáng)制上下文交換,而wait則不一定簸喂,wait后可能還是有機(jī)會(huì)重新競爭到鎖繼續(xù)執(zhí)行的

yield執(zhí)行后線程直接進(jìn)入就緒狀態(tài)竞惋,馬上釋放了cpu的執(zhí)行權(quán),但是依然保留了cpu的執(zhí)行資格蔑滓,所以有可能cpu下次進(jìn)行線程調(diào)度還會(huì)讓這個(gè)線程獲取到執(zhí)行權(quán)繼續(xù)執(zhí)行
join執(zhí)行后線程進(jìn)入阻塞狀態(tài)郊酒,例如在線程B中調(diào)用線程A的join,那么線程B會(huì)進(jìn)入到阻塞隊(duì)列键袱,直到線程A結(jié)束或中斷線程

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println("22222222");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t1.join();
        //這行代碼必須要等t1這個(gè)線程執(zhí)行完畢才會(huì)執(zhí)行
        System.out.println("11111111");
    }

19燎窘、談?wù)勀銓?duì)線程安全的理解

不是線程安全,應(yīng)該是內(nèi)存安全蹄咖,堆是共享內(nèi)存褐健,可以被所有線程訪問

當(dāng)多個(gè)線程訪問一個(gè)對(duì)象時(shí),如果不用進(jìn)行額外的同步控制或其他的協(xié)調(diào)操作比藻,調(diào)用這個(gè)對(duì)象的行為都可以獲得正確的結(jié)果铝量,我們就說這個(gè)對(duì)象是線程安全的

堆是進(jìn)程和線程共有的空間,分全局堆和局部堆银亲。全局堆就是所有沒有分配的空間慢叨,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對(duì)進(jìn)程初始化的時(shí)候分配务蝠,運(yùn)行過程中也可以向系統(tǒng)要額外的堆拍谐,但是用完了要還給操作系統(tǒng),要不就會(huì)造成內(nèi)存泄漏

在Java中馏段,堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊轩拨,是所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建院喜。堆所存在內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例亡蓉,幾乎所有的對(duì)象實(shí)例以及數(shù)組都在這里分配內(nèi)存

棧是每個(gè)線程獨(dú)有的,保存其u運(yùn)行狀態(tài)和局部自動(dòng)變量的喷舀,棧在線程開始的時(shí)候初始化砍濒,每個(gè)線程的棧相互獨(dú)立淋肾,因此,棧是線程安全的爸邢,操作系統(tǒng)在切換線程的時(shí)候會(huì)自動(dòng)切換棧樊卓,棧空間不需要在高級(jí)語言里面顯示的分配和釋放

目前主流操作系統(tǒng)都是多任務(wù)的杠河,即多個(gè)進(jìn)程同時(shí)運(yùn)行碌尔,為了保證安全,每個(gè)進(jìn)程只能訪問分配給自己的內(nèi)存空間券敌,而不能訪問別的進(jìn)程的唾戚,這是由操作系統(tǒng)保障的
在每個(gè)進(jìn)程的空間中都會(huì)有一塊特殊的公共區(qū)域,通常稱為堆(內(nèi)存)待诅。進(jìn)程內(nèi)的所有線程都可以訪問到該區(qū)域颈走,這就是造成問題的潛在原因

20、Thread,Runnable的區(qū)別

Thread和Runnable的實(shí)質(zhì)繼承關(guān)系咱士,沒有可比性,無論使用Runnable還是Thread轧钓,都會(huì)new Thread,然后執(zhí)行run方法序厉,用法上,如果有復(fù)雜的線程操作需求毕箍,那么就選擇繼承Thread弛房,如果只是簡單的執(zhí)行一個(gè)任務(wù),那么就是先runnabe而柑。

21文捶、說說你對(duì)守護(hù)線程的理解

守護(hù)線程:為所有的線程提供服務(wù)的線程,任何一個(gè)線程都是真?zhèn)€jvm中所有非守護(hù)線程的保姆
守護(hù)線程類似于整個(gè)進(jìn)程的一個(gè)默默無聞的小嘍嘍媒咳,他的生死無關(guān)緊要粹排,他卻以來整個(gè)進(jìn)程而運(yùn)行,等待其他進(jìn)程都結(jié)束了涩澡,沒有需要執(zhí)行的了顽耳,程序就結(jié)束了,理都不理守護(hù)線程就把他中斷了
注意:由于守護(hù)線程的終止是自身無法控制的妙同,因此千萬不要把IO射富,F(xiàn)ile等重要的操作邏輯分配給他,因?yàn)樗豢孔V

守護(hù)線程的作用是什么:
舉例粥帚,GC垃圾回收線程:就是一個(gè)經(jīng)典的守護(hù)線程胰耗,當(dāng)我們的程序不再有任何運(yùn)行的Thread,程序就不會(huì)再產(chǎn)生垃圾芒涡,垃圾回收期器也就是無事可做柴灯,所以當(dāng)垃圾回收線程是jvm上僅剩的線程時(shí)卖漫,垃圾回收線程會(huì)自動(dòng)離開,他始終在低級(jí)別的狀態(tài)中運(yùn)行弛槐,用于實(shí)時(shí)監(jiān)控和管理系統(tǒng)中可回收資源
應(yīng)用場景:(1)來為其他線程提供服務(wù)支持的情況懊亡;(2)或則在任何情況下不再有任何運(yùn)行的Thread,程序結(jié)束時(shí)乎串,這個(gè)線程必須正常且立刻關(guān)閉店枣,就可以作為守護(hù)線程來使用,反之叹誉,如果一個(gè)正在執(zhí)行某個(gè)操作的線程必須要正確地關(guān)閉否則就會(huì)出現(xiàn)不好的后果的話鸯两,那么這個(gè)線程就不能設(shè)置未守護(hù)線程,而是用戶線程长豁,通常都是寫關(guān)鍵的事物钧唐,比方說,數(shù)據(jù)庫錄入或則更新匠襟,這些操作都是不能中斷的

thread.setDaemon(true)必須是線程啟動(dòng)之前钝侠,否則會(huì)拋出一個(gè)illegalThreadStateException異常,你不能把正在運(yùn)行的常規(guī)線程設(shè)置為守護(hù)線程

在Daemon線程中產(chǎn)生的新線程也是守護(hù)線程

守護(hù)線程不能用于去訪問固有資源酸舍,比如讀寫操作或則計(jì)算邏輯帅韧,因?yàn)樗麜?huì)在任何時(shí)候甚至在一個(gè)操作的中間發(fā)生中斷

Java自帶的多線程框架,比如ExecutorService啃勉,會(huì)將守護(hù)線程轉(zhuǎn)換為用戶線程忽舟,所以如果使用后臺(tái)線程就不能用java的線程池

22、ThreadLocal的原理和使用場景

每一個(gè)Thread對(duì)象均包含有一個(gè)ThreadLocalMap類型的成員變量threadLocals淮阐,他存儲(chǔ)本線程中所有ThreadLocal對(duì)象及其對(duì)應(yīng)的值

ThreadLocalMap由一個(gè)個(gè)Entry對(duì)象構(gòu)成

Entry繼承自WeakReference<ThreadLocal<T>>,一個(gè)Entry由ThreadLocal對(duì)象和Object對(duì)象構(gòu)成叮阅,由此可見,Entry的key是ThreadLocal對(duì)象泣特,并且是一個(gè)弱引用浩姥,當(dāng)沒指向key的強(qiáng)引用后,該key就會(huì)被垃圾收集器回收
當(dāng)執(zhí)行set方法状您,ThreadLocal首先會(huì)獲取當(dāng)前對(duì)象線程對(duì)象及刻,然后獲取當(dāng)前線程的ThreadLocalMap對(duì)象,再以當(dāng)前ThreadLocal對(duì)象為key竞阐,將值存儲(chǔ)進(jìn)ThreadLocalMap對(duì)象中

get方法執(zhí)行過程類似缴饭,ThreadLocal首先會(huì)獲取當(dāng)前線程的ThreadLocalMap對(duì)象,再以當(dāng)前ThreadLocal對(duì)象為key骆莹,獲取對(duì)應(yīng)的value
由于每一條線程均含有各自私有的ThreadLocalMap容器颗搂,這些容器互不影響,因此不會(huì)存在線程安全性問題幕垦,從而也無需使用同步機(jī)制來保證多條線程訪問容器的互斥性

使用場景:

  • 在進(jìn)行對(duì)象跨層傳遞的時(shí)候丢氢,使用ThreadLocal可以避免多次傳遞傅联,打破層次間的約束
  • 線程間數(shù)據(jù)隔離
  • 進(jìn)行實(shí)物操作,用于存儲(chǔ)線程事務(wù)信息
  • 數(shù)據(jù)庫連接疚察,Session會(huì)話管理

Spring框架在事務(wù)開始時(shí)會(huì)給當(dāng)前線程綁定一個(gè)Jdbc Connection,在整個(gè)事務(wù)過程都是使用線程綁定的connection來執(zhí)行數(shù)據(jù)庫操作蒸走,實(shí)現(xiàn)了事物的隔離性,Spring框架里面就是用的ThreadLocal來實(shí)現(xiàn)這種隔離

23貌嫡、ThreadLocal內(nèi)存泄漏原因比驻,如何避免

內(nèi)存泄漏為程序在申請(qǐng)內(nèi)存后,無法釋放已申請(qǐng)的內(nèi)存空間岛抄,一次內(nèi)存泄漏危害可以忽略别惦,但內(nèi)存泄漏堆積后果很嚴(yán)重,無論多少夫椭,遲早會(huì)被占光
不再會(huì)被使用的或則變量占用的內(nèi)存不能被回收掸掸,就是內(nèi)存泄漏

強(qiáng)引用:使用最普通的引用(new),一個(gè)對(duì)象具有強(qiáng)引用蹭秋,不會(huì)被垃圾回收器回收扰付,當(dāng)內(nèi)存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤仁讨,使程序異常終止悯周,也不會(huì)受這種對(duì)象
如果想取消強(qiáng)引用和某個(gè)對(duì)象之間的關(guān)聯(lián),可以顯示地賦值為null陪竿,這樣可以將jvm在合適的時(shí)間就會(huì)回收該對(duì)象
弱引用:jvm進(jìn)行垃圾回收時(shí),無論內(nèi)存是否充足屠橄,都會(huì)回收被弱引用關(guān)聯(lián)的對(duì)象族跛,在Java中,用java.lang.ref.WeakReference類來表示锐墙,可以在緩存中使用弱引用

ThreadLocal的實(shí)現(xiàn)原理礁哄,每一個(gè)Thread維護(hù)一個(gè)ThreadLocalMap,key為使用弱引用的ThreadLocal實(shí)例溪北,value為線程變量的副本

ThreadLocalMap使用ThreadLocal的弱引用作為key桐绒,如果一個(gè)ThreadLocal不存在外部強(qiáng)引用時(shí),key(ThreadLocal:強(qiáng)引用不存在了之拨,當(dāng)GC進(jìn)行垃圾回收的時(shí)候就會(huì)回收)勢(shì)必會(huì)被GC回收茉继,這樣就會(huì)導(dǎo)致ThreadLocalMap中key為null,而value還存在著強(qiáng)引用蚀乔,只有thread線程推出以后value的強(qiáng)引用鏈條才會(huì)斷掉烁竭,但如果當(dāng)前線程遲遲不結(jié)束的話,這些key為null的Entry的value就會(huì)一致存在一條強(qiáng)引用鏈
key使用強(qiáng)引用:
當(dāng)threadLocalMap的key為強(qiáng)引用回收ThreadLocal時(shí)吉挣,因?yàn)門hreadLocalMap還持有ThreadLocal的強(qiáng)引用派撕,如果沒有手動(dòng)刪除婉弹,ThreadLocal不會(huì)被回收,導(dǎo)致Entry內(nèi)存泄漏终吼。
key使用弱引用:
當(dāng)ThreadLocalMap的key為弱引用回收ThreadLocal時(shí)镀赌,由于ThreadLocalMap持有ThreadLocal的弱引用,即使沒有手動(dòng)刪除际跪,ThreadLocal也會(huì)被回收商佛,當(dāng)key為null,在下一次ThreadLocalMap調(diào)用set,get,remove方法的時(shí)候會(huì)被清除value值

因此垫卤,ThreadLocal內(nèi)存泄漏的根源是:由于ThreadLocalMap的生命周期一樣長威彰,如果沒有手動(dòng)刪除對(duì)應(yīng)key就會(huì)導(dǎo)致內(nèi)存泄漏,而不是因?yàn)槿跻?/p>

ThreadLocal正確的使用方法

  • 每次使用完ThreadLocal都調(diào)用他的remove方法清除數(shù)據(jù)
  • 將ThreadLocal變量定義成private static,這樣就一致存在ThreadLocal的強(qiáng)引用穴肘,也就能保證任何時(shí)候都能通過ThreadLocal的弱引用訪問到Entry的value值歇盼,進(jìn)而清除掉


    image.png

24、兵并發(fā)评抚,并行豹缀,串行的區(qū)別

  • 穿行在時(shí)間上不可能發(fā)生重疊,前一個(gè)任務(wù)沒有高度慨代,下一個(gè)任務(wù)就只能等著
  • 并行在時(shí)間上是重疊的邢笙,兩個(gè)任務(wù)在同一時(shí)刻互不干擾的同時(shí)執(zhí)行
  • 并發(fā)允許兩個(gè)任務(wù)彼此干擾,同一時(shí)間點(diǎn)侍匙,只有一個(gè)任務(wù)運(yùn)行氮惯,交替執(zhí)行

25、并發(fā)的三大特性

  • 原子性
    原子性是指在一個(gè)操作中cpu不可以中途停止然后再調(diào)度想暗,即不被該中斷操作妇汗,要不全部執(zhí)行,要不都不執(zhí)行说莫。就好比轉(zhuǎn)賬杨箭,從賬戶A向賬戶B轉(zhuǎn)1000源,那么必然包括2個(gè)操作储狭,從賬戶A減去1000元互婿,往賬戶B加上1000元,2個(gè)操作必須全部完成
private long count = 0
public void calc(){
  count++;
}
  • 1:將count從貯存讀到工作內(nèi)存中的副本中
  • 2:+1的運(yùn)算
  • 3:將結(jié)果寫入到內(nèi)存
  • 4:將工作內(nèi)存的值刷回主存(什么時(shí)候刷回由操作系統(tǒng)決定辽狈,不確定的)

那程序中原子性指的是最小的操作單元慈参,比如自增操作,它本身其實(shí)并不是原子性操作刮萌,分了3步的懂牧,包括讀取變量的原始值,進(jìn)行加1操作,寫入工作內(nèi)存僧凤,所以在多線程中畜侦,有可能一個(gè)線程還沒自增完,可能才執(zhí)行到第二步躯保,另一個(gè)線程已經(jīng)讀取了值旋膳,導(dǎo)致結(jié)果錯(cuò)誤。那如果我們保證自增操作是一個(gè)原子性的操作途事,那么就能保證其他線程讀取到的一定是自增后的數(shù)據(jù)
關(guān)鍵字:synchronized
當(dāng)多個(gè)線程訪問同一個(gè)變量時(shí)验懊,一個(gè)線程修改了這個(gè)變量的值,其他線程能夠立即查看得到修改的值
若兩個(gè)線程在不同的cpu尸变,那么線程1改變了i的值還沒刷新到主存义图,線程2又使用了i,那么這個(gè)i值肯定還是之前的召烂,線程1對(duì)變量的修改線程2沒看到這就是可見性問題

//線程1
boolean stop = false;
while(stop){
  doSomething();
}
//線程2
stop = true;

如果下次2改變了stop的值碱工,線程1一定會(huì)停止嗎?不一定奏夫,當(dāng)線程2更改了stop變量的值之后怕篷,多少還沒來得及寫入主存當(dāng)中,線程2轉(zhuǎn)去2去做其他事情了酗昼,那么線程1由于不知道下次2對(duì)stop變量的更改廊谓,因此還會(huì)一致循環(huán)下去
關(guān)鍵字:volatile,synchronized,final

  • 有序性
    虛擬機(jī)在進(jìn)行代碼編譯時(shí),對(duì)于那些改變順序之后不會(huì)對(duì)最終結(jié)果造成影響的代碼麻削,虛擬機(jī)不一定會(huì)按照我們寫的代碼的順序執(zhí)行蒸痹,有可能將他們中心排序之后,雖然對(duì)變量的值沒有造成影響呛哟,但有可能會(huì)出現(xiàn)線程安全問題
int a = 0;
boolean flag = false;
public void write(){
  a = 2;             // 1   
  flag = true;       //2
}
public void multiply(){
  if(flag) {         //3
    int ret = a*a;   //4
  }
}

write方法里的1和2做了重排序叠荠,線程1先對(duì)flag賦了值為true,隨后執(zhí)行線程2竖共,ret直接算出結(jié)果,再到線程1俺祠,這時(shí)候a才賦值為2公给,恨明顯遲了一步
關(guān)鍵字:volatile,synchronized
volatile本身包含了禁止指令重拍的語義,而synchronized關(guān)鍵字是由一個(gè)變量在同一時(shí)只允許一條線程對(duì)其進(jìn)行操作

synchronized關(guān)鍵字同時(shí)滿足以上三種特性蜘渣,但是volatile關(guān)鍵字不滿足原子性
在某些情況下淌铐,volatile的同步機(jī)制的性能確實(shí)要優(yōu)于鎖(使用synchronized關(guān)鍵字或java.util.concurrent包里面的鎖),因?yàn)関olatile的總開銷要比鎖低

26蔫缸、為什么使用線程池腿准?解釋下線程池參數(shù)?

1.降低資源消耗,提高線程利用率,降低創(chuàng)建和銷毀線程的消耗
2.提高效應(yīng)速度吐葱,任務(wù)來了街望,直接有線程可用可執(zhí)行,而本身先創(chuàng)建線程弟跑,再執(zhí)行
3.提高線程的可管理性灾前,線程是稀缺資源,使用線程池可以統(tǒng)一分配調(diào)優(yōu)監(jiān)控

  • corePoolSize 代表核心線程數(shù)孟辑,也就是正常情況下創(chuàng)建工作的線程數(shù)哎甲,這些線程創(chuàng)建后并不會(huì)消除,而是一種常駐線程
  • maxinumPoolSize 代表的是最大線程數(shù)量饲嗽,他與核心線程數(shù)相對(duì)應(yīng)炭玫,表示最大允許創(chuàng)建的線程數(shù),比如當(dāng)前線程任務(wù)較多貌虾,隊(duì)列任務(wù)中已滿并且當(dāng)前已經(jīng)創(chuàng)建的線程數(shù)小于maxinumPoolSize吞加,那么此時(shí)將會(huì)創(chuàng)建新的線程,但是線程池內(nèi)線程總數(shù)不會(huì)超過最大線程數(shù)(setMaximumPoolSize可以對(duì)最大線程數(shù)進(jìn)行修改)
  • keepAliveTime, unit 表示超出核心線程數(shù)之外的線程的空閑存活時(shí)間酝惧,也就是核心線程不會(huì)消除榴鼎,但是超出核心線程數(shù)的部分如果空閑時(shí)間超出制定的存活時(shí)間就會(huì)被消除,我們可以通過setKeepAliveTime來設(shè)置空閑時(shí)間
  • workQueue 用來存放待執(zhí)行的任務(wù)晚唇,假設(shè)我們現(xiàn)在核心線程都已經(jīng)被使用巫财,還有任務(wù)進(jìn)來則全部放入對(duì)列,直到整個(gè)隊(duì)列被放滿但任務(wù)還在持續(xù)進(jìn)入則會(huì)開始創(chuàng)建新的線程
  • ThreadFactory 實(shí)際上是一個(gè)線程工程哩陕,用來生產(chǎn)線程執(zhí)行任務(wù)平项,我們可以選擇使用默認(rèn)的創(chuàng)建線程,產(chǎn)生的線程都在同一個(gè)組內(nèi)悍及,擁有相同的優(yōu)先級(jí)闽瓢,且都不是守護(hù)線程,當(dāng)然我們也可以選擇自定義線程工廠心赶,一般我們會(huì)根據(jù)業(yè)務(wù)來制定不同的線程工廠
  • Handler 任務(wù)拒絕策略扣讼,有兩種情況 ,第一種是當(dāng)我們調(diào)用shutdown等方法關(guān)閉線程池后缨叫,這時(shí)候即使線程池內(nèi)部還有沒執(zhí)行完的任務(wù)正在執(zhí)行椭符,但是由于線程池已經(jīng)關(guān)閉,我們?cè)倮^續(xù)想線程池提交任務(wù)就會(huì)遭到拒絕耻姥,另一種情況就是達(dá)到最大線程數(shù)销钝,,隊(duì)列也裝滿了琐簇,這時(shí)候沒有能力處理線程或則排隊(duì)的空間就會(huì)拒絕

27、簡述線程池的處理流程

image.png

28似忧、線程池中阻塞隊(duì)列的作用?為什么是先添加隊(duì)列而不是先創(chuàng)建最大線程

1.一般的隊(duì)列只能保證作為一個(gè)有線長度的緩沖區(qū)严拒,如果超出了緩沖長度藕届,就無法保留當(dāng)前的任務(wù)了庇麦,阻塞隊(duì)列通過阻塞可以保留當(dāng)前想要繼續(xù)入隊(duì)的任務(wù)
阻塞隊(duì)列可以保證任務(wù)隊(duì)列中沒有任務(wù)時(shí),阻塞獲取任務(wù)的線程喜德,使得線程進(jìn)入wait狀態(tài)山橄,釋放cpu資源
阻塞隊(duì)列自帶阻塞和喚醒的功能恨狈,不需要額外處理衩婚,無任務(wù)執(zhí)行時(shí)橱乱,線程池利用阻塞隊(duì)列的take方法掛起胶台,從而維持核心線程的存活污尉,不至于一致占用cpu資源

2.在創(chuàng)建新線程的時(shí)候姜盈,是要獲取全局鎖的硕蛹,這個(gè)時(shí)候其他的就得阻塞浪漠,影響了整體效率

29秕豫、線程池中線程復(fù)用原理

線程池將線程和任務(wù)進(jìn)行解耦朴艰,線程是線程,任務(wù)是任務(wù)混移,拜托了之前通過Thread創(chuàng)建線程時(shí)的一個(gè)線程必須對(duì)應(yīng)一個(gè)任務(wù)的限制
在線程池中祠墅,同一個(gè)任務(wù)可以從阻塞隊(duì)列中不斷獲取新任務(wù)來執(zhí)行,其核心原理在于線程池對(duì)Thread進(jìn)行了封裝歌径,并不是每次執(zhí)行任務(wù)都會(huì)調(diào)用Thread.start來創(chuàng)建新線程毁嗦,而是讓每個(gè)線程去執(zhí)行一個(gè)循環(huán)任務(wù),在這個(gè)循環(huán)任務(wù)中不停檢查是否有任務(wù)需要被執(zhí)行沮脖,如果有直接執(zhí)行金矛,也就是調(diào)用任務(wù)中的run方法,將run方法當(dāng)成一個(gè)普通的方法執(zhí)行勺届,通過這種方式只使用固定的線程就將所有任務(wù)的run方法串聯(lián)起來

30驶俊、spring是什么

輕量級(jí)的開源的J2EE框架,他是一個(gè)容器框架免姿,用來裝javabean(Java對(duì)象)饼酿,中間層框架(萬能加),可以起一個(gè)連接作用胚膊,比如說把Struts和hibernate粘和到一起運(yùn)用故俐,可以讓我們的企業(yè)開發(fā)更快,更簡潔
spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)和面向切面的容器框架

  • 從大小與開銷兩方面而言spring都是輕量級(jí)的
  • 通過控制反轉(zhuǎn)的計(jì)數(shù)達(dá)到松耦合的目的
  • 提供了面向切面編程的豐富支持紊婉,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)進(jìn)行內(nèi)聚性的開發(fā)
  • 包含并管理應(yīng)用對(duì)象的配置和生命周期药版,這個(gè)意義上是一個(gè)容器
  • 將簡單的組件配置,組合成為復(fù)雜的應(yīng)用喻犁,這個(gè)意義上是一個(gè)框架

31槽片、談?wù)勀銓?duì)AOP的理解

系統(tǒng)是由許多不同的組建所組成的何缓,每一個(gè)組件各負(fù)責(zé)一塊特定的功能,除了實(shí)現(xiàn)自身核心功能之外还栓,這些組件還經(jīng)常承擔(dān)著額外的職責(zé)碌廓,例如日志,事務(wù)管理和安全這樣的核心服務(wù)經(jīng)常融入到自身具有核心業(yè)務(wù)邏輯的組件中去剩盒。這些系統(tǒng)服務(wù)經(jīng)常被稱為橫切關(guān)注點(diǎn)谷婆,因?yàn)樗麄儠?huì)跨越系統(tǒng)的多個(gè)組件

當(dāng)我們需要為分散的對(duì)象引入公共行為的時(shí)候,OOP則顯得無能為力辽聊,也就是說纪挎,OOP允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系跟匆,例如日志功能

日志代碼往往水平的散布在所有對(duì)象層次中廷区,而與他所散布到的對(duì)象的核心功能毫無關(guān)系

在OOP設(shè)計(jì)中,他導(dǎo)致了大量代碼的重復(fù)贾铝,而不利于各個(gè)模塊的復(fù)用

AOP:將所有程序中的交叉業(yè)務(wù)邏輯(比如安全隙轻,日志,事務(wù)等)垢揩,封裝成一個(gè)切面玖绿,然后注入到目標(biāo)對(duì)象(具體業(yè)務(wù)邏輯)中去,AOP可以對(duì)某個(gè)對(duì)象或某些對(duì)象的功能進(jìn)行增強(qiáng)叁巨,比如對(duì)象中的方法進(jìn)行增強(qiáng)斑匪,可以在執(zhí)行某個(gè)方法之前額外的做一些事情,在某個(gè)方法之后額外的做一些事情

32锋勺、談?wù)勀銓?duì)IOC的理解

容器概念蚀瘸,控制反轉(zhuǎn),依賴注入
IOC容器:實(shí)際上就是個(gè)map(key,value)庶橱,里面存的是各種對(duì)象(在xml里配置的bean節(jié)點(diǎn)贮勃,@repository,@service,@component,@controller),在項(xiàng)目啟動(dòng)的時(shí)候會(huì)讀取配置文件里的bean節(jié)點(diǎn),根據(jù)全限定類名使用反射創(chuàng)建對(duì)象放到map里苏章,掃描到上述注解的類還是通過反射創(chuàng)建對(duì)象放到map里寂嘉。
這個(gè)時(shí)候map里就有各種對(duì)象了,接下來我們?cè)诖a里需要用到里面的對(duì)象時(shí)枫绅,再通過DI注入(autowired,resource等注解xml里bean節(jié)點(diǎn)內(nèi)的ref屬性泉孩,項(xiàng)目啟動(dòng)的時(shí)候會(huì)讀取xml節(jié)點(diǎn)ref屬性更具id注入,也會(huì)掃描這些注解并淋,根據(jù)類型或id注入寓搬,id就是對(duì)對(duì)象名)

控制反轉(zhuǎn):
沒有引入IOC容器之前,對(duì)象A依賴于對(duì)象B县耽,那么對(duì)象A在初始化或則運(yùn)行到某一點(diǎn)的時(shí)候句喷,自己必須主動(dòng)去創(chuàng)建對(duì)象B或則使用已經(jīng)創(chuàng)建的對(duì)象B曼尊,無論是創(chuàng)建還是使用對(duì)象B,控制權(quán)都在自己手上
引入IOC容器之后脏嚷,對(duì)象A與對(duì)象B之間失去了直接聯(lián)系,當(dāng)對(duì)象A運(yùn)行到需要對(duì)象B的時(shí)候瞒御,IOC容器會(huì)主動(dòng)創(chuàng)建一個(gè)對(duì)象B注入到對(duì)象A需要的地方
通過前后的對(duì)比父叙,不難看出來:對(duì)象A獲得依賴對(duì)象B的過程,由主動(dòng)行為變味了被動(dòng)行為肴裙,控制權(quán)顛倒過來了趾唱,這就是控制反轉(zhuǎn)這個(gè)名稱的由來。
全部兌現(xiàn)的控制權(quán)全部上交給IOC容器蜻懦,所以甜癞,IOC容器成了整個(gè)系統(tǒng)的關(guān)鍵核心,他起到了一種類似粘合劑的作用宛乃,把系統(tǒng)中的所有對(duì)象粘合在一起發(fā)揮作用悠咱,如果沒有這個(gè)粘合劑,對(duì)象與對(duì)象之間會(huì)彼此失去聯(lián)系征炼,這就是悠人把IOC容器比喻成粘合劑的由來

依賴注入:
獲得以來對(duì)象的過程被反轉(zhuǎn)了析既。控制被反轉(zhuǎn)之后谆奥,獲得依賴對(duì)象的過程由自身管理變?yōu)榱擞蒊OC容器自動(dòng)注入眼坏,依賴注入是實(shí)現(xiàn)IOC的方法,就是由IOC容器在運(yùn)行期間酸些,動(dòng)態(tài)的將某種依賴關(guān)系注入到對(duì)象之中

33宰译、BeanFactory和ApplicationContext有什么區(qū)別?

ApplicationContext是BeanFactory的子接口
ApplicationContext提供了更完整的功能:
1.繼承MessageSource魄懂,因此支持國際化
2.統(tǒng)一的文件訪問方式
3.提供在監(jiān)聽器中注冊(cè)BEAN的時(shí)間
4.同事加載多個(gè)配置文件
5.載入多個(gè)(有繼承關(guān)系)上下文沿侈,使得每一個(gè)上下文都專注于一個(gè)特定的層次,比如應(yīng)用的web層

  • BeanFactory采用的是延遲加載形式來注入Bean的市栗,即只有在使用到某個(gè)Bean時(shí)(調(diào)用getBean),c才對(duì)該對(duì)象進(jìn)行加載實(shí)例化肋坚,這樣,我們就不能發(fā)現(xiàn)一些存在的spring的配置問題肃廓,如果bean的某一個(gè)屬性沒有注入智厌,BeanFactory加載后,直至第一次調(diào)用getBean方法才會(huì)拋出異常
  • ApplicationContext他是在容器啟動(dòng)的時(shí)候盲赊,一次性創(chuàng)建了所有的Bean铣鹏,這樣,在容器啟動(dòng)時(shí)哀蘑,我們就可以發(fā)現(xiàn)spring中存在的配置錯(cuò)誤诚卸,這樣有利于檢查所有依賴屬性是否注入葵第,ApplicationContext啟動(dòng)后預(yù)載入所有的單實(shí)例Bean,通過預(yù)載入單實(shí)例bean合溺,確保當(dāng)你需要的時(shí)候卒密,你就不用等待,因?yàn)樗麄円呀?jīng)創(chuàng)建好了
  • 相對(duì)于基本的BeanFactory,ApplicationContext唯一的不足是占用內(nèi)存空間棠赛,當(dāng)應(yīng)用程序配置Bean較多時(shí)哮奇,程序啟動(dòng)較慢
  • BeanFactory通常以編程的方式被創(chuàng)建,ApplicationContext還能以聲明的方式創(chuàng)建如使用

34睛约、描述一下spring bean

1.解析類得到BeanDefinition
2.如果有多個(gè)構(gòu)造方法鼎俘,則要推斷構(gòu)造方法
3.確定好構(gòu)造方法后,進(jìn)行實(shí)例化得到一個(gè)對(duì)象
4.對(duì)對(duì)象中加了@Autoware等注解的屬性鏡像注入
5.回調(diào)Aware方法辩涝,比如BeanNameAware,BeanFactoryAware(bean需要定義自己需要感知spring容器里的一些屬性(需要感知那些就定義那些)贸伐,bean需要實(shí)現(xiàn)上面這些接口并實(shí)現(xiàn)接口方法,然后將傳入的參數(shù)設(shè)置到前面定義的屬性里面怔揩,具體網(wǎng)上查看文章:https://blog.csdn.net/qq_38526573/article/details/88095674)
6.調(diào)用BeanPostProcessor的初始化前的方法(可以修改我們的bean屬性捉邢,需要自定義實(shí)現(xiàn)這個(gè)接口)
7.調(diào)用初始化方法
8.調(diào)用BeanPostProcessor的初始化后的方法,在這里會(huì)進(jìn)行AOP
9.如果當(dāng)前創(chuàng)建的bean是單列的則會(huì)把bean放入單列池
10.使用bean
11.spring容器關(guān)閉調(diào)用DisposableBean中destory方法

35商膊、說一下spring 支持的幾種bean的作用域

  • singleton:默認(rèn)歌逢,每個(gè)容器中只有一個(gè)bean的實(shí)例,單例的模式由BeanFactory自身來維護(hù)翘狱,該對(duì)象的聲明周期與spring ioc容器一致(但在第一次被注入時(shí)才會(huì)被創(chuàng)建)
  • prototype:為每一個(gè)bean請(qǐng)求提供一個(gè)實(shí)例秘案,在每次呼入時(shí)都會(huì)創(chuàng)建一個(gè)新的對(duì)象
  • request:bean被定義為在每個(gè)HTTP請(qǐng)求中創(chuàng)建一個(gè)單例對(duì)象,潦匈,也就是說在單個(gè)請(qǐng)求中都會(huì)復(fù)用這一個(gè)單例對(duì)象
  • session:與request范圍類似阱高,確保每個(gè)session中有一個(gè)bean的實(shí)例,在session過期后茬缩,bean會(huì)隨之銷毀
  • application:bean被定義為在ServletContext的聲明周期中復(fù)用一個(gè)單例對(duì)象
  • websocket:bean被定義為在websocket的聲明周期中復(fù)用一個(gè)單例對(duì)象

global-session:全局作用域赤惊,global-session和portlet應(yīng)用相關(guān),當(dāng)你的應(yīng)用部署在portlet容器中工作時(shí)凰锡,它包含很多portlet未舟,如果你想要聲明讓所有的portlet共用全局的存儲(chǔ)變量的話,那么這全局變量需要存儲(chǔ)在global-session中掂为,全局作用域與Servlet中的session作用域效果相同

36裕膀、spring框架中的單例bean是線程安全的么?

spring中的bean默認(rèn)是單例模式的勇哗,框架并沒有對(duì)bean進(jìn)行多線程的封裝處理
如果bean是有狀態(tài)的昼扛,那么就需要開發(fā)人員自己來進(jìn)行安全的保證,最簡單的辦法就是改變bean的作用域把singleton改為prototype這樣每次請(qǐng)求bean就相當(dāng)于是新創(chuàng)建了一個(gè)bean欲诺,這樣就可以保證線程安全了

  • 有狀態(tài)就是數(shù)據(jù)存儲(chǔ)功能
  • 無狀態(tài)就是不會(huì)存儲(chǔ)數(shù)據(jù)抄谐,controoler,service和dao層本身并不是線程安全的渺鹦,如果只是調(diào)用里面的方法,而且多線程調(diào)用一個(gè)單例的方法蛹含,會(huì)在全局中復(fù)制變量毅厚,這是自己的線程的構(gòu)造內(nèi)存,是安全的
    dao會(huì)操作數(shù)據(jù)庫connection,connection是帶有狀態(tài)的浦箱,比如說數(shù)據(jù)庫事務(wù)吸耿,spring的事務(wù)管理器使用ThreadLocal為不同的線程維護(hù)了一套獨(dú)立的connection副本,保證線程之間不會(huì)互相影響(spring是如何保證事務(wù)獲取同一個(gè)connection的)
    不要在bean中聲明任何有狀態(tài)的實(shí)例變量或類變量憎茂,如果必須如此,那么就使用ThreadLocal把變量變?yōu)榫€程私有的锤岸,如果bean的實(shí)例變量或類變量需要在多個(gè)線程之間共享竖幔,那么就只能使用synchronized,lock,CAS等這些實(shí)現(xiàn)線程同步的功能了

37、spring框架中都用到了那些設(shè)計(jì)模式

簡單工廠:由一個(gè)工廠類根據(jù)傳入的參數(shù)是偷,動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類

spring中的BeanFactory就是簡單工廠模式的體現(xiàn)拳氢,根據(jù)傳入一個(gè)唯一的標(biāo)識(shí)來獲取Bean對(duì)象,但是否是在傳入?yún)?shù)后創(chuàng)建還是傳入?yún)?shù)前創(chuàng)建這個(gè)要根據(jù)具體情況來定

工廠方法:

實(shí)現(xiàn)了FactoryBean接口的bean是一類叫做factory的bean蛋铆,其特點(diǎn)是馋评,spring會(huì)在使用getBean調(diào)用獲得該bean時(shí),會(huì)自動(dòng)調(diào)用該bean的getObject方法,所以返回的不是factory這個(gè)bean刺啦,而是bean.getObject方法的返回值

單例模式:保證一個(gè)類僅有一個(gè)實(shí)例留特,并提供一個(gè)訪問他的全局訪問點(diǎn)

spring對(duì)單例的實(shí)現(xiàn):spring中的單例模式完成了后半句話,即提供了全局訪問點(diǎn)BeanFactory玛瘸,但沒有從構(gòu)造器級(jí)別去控制單例蜕青,這是因?yàn)閟pring管理的是任意的Java對(duì)象

適配器模式:

spring定義了一個(gè)適配接口,使得每一種controller有一種對(duì)應(yīng)的適配器實(shí)現(xiàn)類糊渊,讓適配器代替controller執(zhí)行相應(yīng)的方法右核,這樣就擴(kuò)展controoler時(shí),只需要增加一個(gè)適配器類就完成了SpringMVC的擴(kuò)展了

裝飾器模式:動(dòng)態(tài)的給一個(gè)對(duì)象添加一些額外的職責(zé)渺绒,就增加功能來說贺喝,Decorator模式相比生成子類更為靈活

spring中用到的包裝器模式在雷鳴上有兩種表現(xiàn),一種是類名中含有Wrapper宗兼,另一種是類中含有Decorator

動(dòng)態(tài)代理:

切面在應(yīng)用運(yùn)行時(shí)的時(shí)刻被織入躏鱼,一般情況下,在植入切面時(shí)殷绍,AOP容器會(huì)為繆奧對(duì)象動(dòng)態(tài)創(chuàng)建一個(gè)代理對(duì)象挠他,springaop激素以這樣方式織入切面的
織入:把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過程

觀察者模式:

spring的事件驅(qū)動(dòng)模型使用的是觀察者模式,spring中observer模式常用的地方是listener的實(shí)現(xiàn)

策略模式:

spring框架的資源訪問Resource接口篡帕,該接口提供了更強(qiáng)的資源訪問能力殖侵,spring框架本身大量使用了resource接口來訪問底層實(shí)現(xiàn)

裝飾器模式關(guān)注于在一個(gè)對(duì)象上動(dòng)態(tài)的添加方法贸呢,然而代理模式關(guān)注于控制對(duì)對(duì)象的訪問。換句話 說拢军,用代理模式楞陷,代理類(proxy class)可以對(duì)它的客戶隱藏一個(gè)對(duì)象的具體信息。因此茉唉,當(dāng)使用代理模式的時(shí)候固蛾,我們常常在一個(gè)代理類中創(chuàng)建一個(gè)對(duì)象的實(shí)例。并且度陆,當(dāng)我們使用裝飾器模 式的時(shí)候艾凯,我們通常的做法是將原始對(duì)象作為一個(gè)參數(shù)傳給裝飾者的構(gòu)造器。

38懂傀、spring事務(wù)的實(shí)現(xiàn)方式和原理以及隔離級(jí)別

在使用spring框架時(shí)趾诗,可以有兩種使用事務(wù)的方式,一種是編程式蹬蚁,一種是聲明式的恃泪,@Transcation注解就是聲明式的
首先,事務(wù)這個(gè)概念是數(shù)據(jù)庫層面的犀斋,spring只是基于數(shù)據(jù)庫中的事務(wù)進(jìn)行了擴(kuò)展贝乎,以及提供了一些讓程序員更加方便操作事物的方式
比如我們可以通過在某個(gè)方法上添加@Transcation注解,就可以開啟事務(wù)叽粹,這個(gè)方法中所有的sql都會(huì)在一個(gè)事務(wù)中執(zhí)行览效,統(tǒng)一成功或失敗
在一個(gè)方法上加了@Transcation注解后,Spring會(huì)基于這個(gè)類生成一個(gè)代理對(duì)象虫几,會(huì)將這個(gè)代理對(duì)象作為bean朽肥,當(dāng)使用這個(gè)代理對(duì)象時(shí),如果這個(gè)方法上存在@Transcation注解持钉,那么代理邏輯會(huì)先把事務(wù)的自動(dòng)提交設(shè)置為false衡招,然后再去執(zhí)行原本的業(yè)務(wù)邏輯方法,如果執(zhí)行業(yè)務(wù)邏輯方法沒有出現(xiàn)異常每强,那么就會(huì)將事務(wù)進(jìn)行提交始腾,如果執(zhí)行業(yè)務(wù)邏輯方法出現(xiàn)了異常,那么則會(huì)將事務(wù)進(jìn)行回滾
當(dāng)然空执,針對(duì)那些異忱思回滾事務(wù)是可以配置的,可以利用@Transcation注解中的rollbackFor屬性進(jìn)行配置辨绊,默認(rèn)情況下會(huì)對(duì)RuntimeException和Error進(jìn)行回滾

spring事務(wù)隔離級(jí)別就是數(shù)據(jù)庫的隔離級(jí)別:外加一個(gè)默認(rèn)級(jí)別

  • read uncommitted(未提交讀):讀寫進(jìn)行奶栖,解決了更新丟失,可能會(huì)出現(xiàn)臟讀
  • read committed(提交讀,不可重復(fù)讀):讀寫進(jìn)行宣鄙,寫事務(wù)會(huì)限制其他事務(wù)讀取該行數(shù)據(jù)袍镀,A讀,B寫冻晤,A再讀數(shù)據(jù)已經(jīng)發(fā)送了變化苇羡,解決了更新丟失和臟讀問題
  • repeatable read(可重復(fù)讀):寫會(huì)禁止讀事務(wù),讀會(huì)禁止讀事務(wù)不會(huì)限制讀事務(wù)鼻弧,解決了更新丟失设江、臟讀、不可重復(fù)讀攘轩、但是還會(huì)出現(xiàn)幻讀
  • serializable(可串行化):事務(wù)隊(duì)列化

數(shù)據(jù)庫的配置隔離級(jí)別是read commited,而spring配置的隔離級(jí)別是repeatable read,請(qǐng)問這時(shí)隔離級(jí)別是以那一個(gè)為準(zhǔn)叉存?以spring為準(zhǔn),如果spring配置的隔離級(jí)別數(shù)據(jù)庫不支持度帮,效果取決于數(shù)據(jù)庫

39歼捏、事務(wù)的傳播機(jī)制

spring事務(wù)傳播機(jī)制
多個(gè)事務(wù)方法相互調(diào)用時(shí),事務(wù)如何在這些方法間傳播

方法A是一個(gè)事務(wù)的方法够傍,方法A執(zhí)行過程中調(diào)用了方法B甫菠,那么方法B有無事務(wù)以及方法B對(duì)事務(wù)的要求不同隊(duì)徽對(duì)方法A的事務(wù)具體執(zhí)行造成影響挠铲,同時(shí)方法A的事務(wù)對(duì)方法B的事務(wù)執(zhí)行也有影響冕屯,這種影響具體是什么就由兩個(gè)方法所定義的類型所決定的

REQUIRED(spring默認(rèn)的事務(wù)傳播類型):如果當(dāng)前沒有事務(wù),則自己新建一個(gè)事務(wù)拂苹,如果當(dāng)前存在事務(wù)安聘,則加入這個(gè)事務(wù)
SUPPORTS:當(dāng)前存在事務(wù),則加入當(dāng)前十五瓢棒,如果當(dāng)前沒有事務(wù)浴韭,就以非事務(wù)方法進(jìn)行
MANDATORY:當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù)脯宿,如果當(dāng)前事務(wù)不存在念颈,則拋出異常
REQUIRES_NEW:創(chuàng)建一個(gè)新事物,如果存在當(dāng)前事務(wù)连霉,則掛起該事務(wù)
NOT_SUPPORTED:以非事務(wù)方式執(zhí)行榴芳,如果當(dāng)前存在事務(wù),則掛起當(dāng)前事務(wù)
NEVER:不使用事務(wù)跺撼,如果當(dāng)前事務(wù)存在窟感,則拋出異常
NESTED:如果當(dāng)前事務(wù)存在,則在潛逃事務(wù)中執(zhí)行歉井,否則REQUIRED的操作一樣(開啟一個(gè)事物)

和REQUIRES_NEW的區(qū)別
REQUIRES_NEW是新創(chuàng)建一個(gè)事務(wù)并且新開啟的這個(gè)事務(wù)與原事務(wù)無關(guān)柿祈,而NESTED則是當(dāng)前存在事務(wù)時(shí)(我們把當(dāng)前事務(wù)稱之為父事務(wù))會(huì)開啟一個(gè)嵌套事務(wù)(稱之為一個(gè)子事務(wù)),在NETSTED情況下父事務(wù)回滾時(shí),子事務(wù)也會(huì)回滾躏嚎,而在REQUIRES_NEW情況下蜜自,原有事務(wù)回滾,不會(huì)影響新開啟的事務(wù)
和REQUIRED的區(qū)別
REQUIRED情況下紧索,調(diào)用方存在事務(wù)時(shí)袁辈,則被調(diào)用方和調(diào)用使用同一事務(wù),那么被調(diào)用放出現(xiàn)異常時(shí)珠漂,由于供用一個(gè)事務(wù)晚缩,所以無論調(diào)用方是否catch其異常,事務(wù)都會(huì)回滾媳危,而在NESTED情況下荞彼,被調(diào)用方發(fā)生異常時(shí),調(diào)用方可以catch其異常待笑,這樣只有子事務(wù)回滾鸣皂,父事務(wù)不受影響

40、spring事務(wù)什么時(shí)候會(huì)失效

spring事務(wù)的原理是AOP暮蹂,進(jìn)行了切面增強(qiáng)寞缝,那么失效的根本原因是這個(gè)AOP不起作用了!常見情況有如下幾種

  • 1.發(fā)生自調(diào)用仰泻,類里面使用this調(diào)用本類的方法(this通常省略)荆陆,此時(shí)這個(gè)this對(duì)象不是代理類,而是UserService對(duì)象本身
    解決方法很簡單集侯,讓那個(gè)this變成UserService的代理類即可
  • 2.方法不是public的

@Transcational只能用于public的方法上被啼,否則事務(wù)會(huì)失效凯沪,如果要用在非public方發(fā)上产禾,可以開啟Aspect代理模式

  • 3.數(shù)據(jù)庫不支持事務(wù)
  • 4.沒有被spring管理
  • 5.異常被吃掉,事務(wù)不會(huì)回滾(或則拋出異常沒有被定義泣刹,默認(rèn)為RuntimeException)

41辈讶、什么是bean的自動(dòng)裝配命浴,有哪些方式

開啟自動(dòng)裝配,只需要在xml配置文件<bean>中定義autowire屬性

<bean id="customer" class="com.xxx.xxx.Customer" autowire="" />

autowire屬性有五種裝配的方式:

  • no -缺省情況下贱除,自動(dòng)裝配是通過ref屬性手動(dòng)設(shè)定

手動(dòng)裝配:以value或ref的方式明確指定屬性值都是手動(dòng)裝配

  • byName - 根據(jù)bean的屬性名稱進(jìn)行自動(dòng)裝配

Customer的屬性名稱person生闲,Spring會(huì)將bean id為person的bean通過setter方法進(jìn)行自動(dòng)裝配
<bean id="customer" class="com.xxx.xxx.Customer" autowire="buName"/>
<bean id="person" class="com.xxx.xxx.Person" />

  • byType - 根據(jù)bean的類型進(jìn)行自動(dòng)裝配

Customer的屬性person的類型為Person,Spring會(huì)將Person 類型的bean通過setter方法進(jìn)行自動(dòng)裝配
<bean id="customer" class="com.xxx.xxx.Customer" autowire="byType "/>
<bean id="person" class="com.xxx.xxx.Person" />

  • constructor - 類似byType勘伺,不過是應(yīng)用于構(gòu)造器的參數(shù)跪腹,如果一個(gè)bean與構(gòu)造器參數(shù)的類型形同,則進(jìn)行自動(dòng)裝配飞醉,否則導(dǎo)致異常

Customer構(gòu)造函數(shù)的參數(shù)person的類型為Person冲茸,spring會(huì)將Person類型通過構(gòu)造方法進(jìn)行自動(dòng)裝配
<bean id="customer" class="com.xxx.xxx.Customer" autowire="constructor"/>
<bean id="person" class="com.xxx.xxx.Person" />

  • autodetect - 如果有默認(rèn)的構(gòu)造器屯阀,則通過contructor方式進(jìn)行自動(dòng)裝配,否則使用byType方式進(jìn)行自動(dòng)裝配

如果有默認(rèn)的構(gòu)造器轴术,則通過constructor方式進(jìn)行自動(dòng)裝配难衰,否則使用byType方式進(jìn)行自動(dòng)裝配

42、spring boot逗栽,spring mvc和spring

spring是一個(gè)IOC容器盖袭,用來管理bean,使用依賴注入實(shí)現(xiàn)控制反轉(zhuǎn)彼宠,可以很方便的整合各種框架鳄虱,提供AOP機(jī)制彌補(bǔ)OOP的代碼重復(fù)問題,更方便將不同方法中的共同處理抽取成切面凭峡,自動(dòng)注入給方法執(zhí)行拙已,比如日志,異常等

springmvc是spring提供的一個(gè)快速開發(fā)web框架的一個(gè)解決方案摧冀,提供了一個(gè)總的前端控制器Servlet倍踪,用來接受請(qǐng)求,然后定義了一套路由策略(url到handle的銀蛇)即適配執(zhí)行handle索昂,將handle結(jié)果使用試圖解析計(jì)數(shù)生成視圖展現(xiàn)給前端

springboot是spring提供的一個(gè)快速開發(fā)工具包建车,讓程序員能更方便,更快速的開發(fā)spring+springmvc應(yīng)用椒惨,簡化了配置(約定了默認(rèn)配置)缤至,整合了一系列的解決方案(starter機(jī)制),redis,mongodb,es,可以開箱即用

43框产、SpringMVC工作流程

1.用戶發(fā)送請(qǐng)求到前端控制器DispatcherServlet
2.DispatcherServlet收到請(qǐng)求調(diào)用HandlerMapping處理映射器
3.處理器映射器找到具體的處理器(可以根據(jù)xml配置凄杯,注解進(jìn)行查找)错洁,生成處理器及攔截器(如果有則生成)一并返回給DispatcherServlet
4.DispatcherServlet調(diào)用HandlerAdapter處理器適配器
5.HandlerAdapter經(jīng)過適配器調(diào)用具體的處理器(Controller秉宿,也叫后端控制器)
6.Controller執(zhí)行完成返回ModelAndView
7.HandlerAdapter將controller執(zhí)行結(jié)果ModelAndView返回給DispatcherServlet
8.DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
9.ViewResolver解析后返回具體View
10.DispatcherServlet根據(jù)View進(jìn)行渲染視圖(將模型數(shù)據(jù)填充到視圖中)
11.DispatcherServlet響應(yīng)用戶

44、SpringMVC的主要組件

Handler:也就是處理器屯碴,他直接對(duì)應(yīng)著MVC的c也就是Controller層描睦,他的具體表現(xiàn)形式有很多,可以實(shí)類导而,也可以是方法忱叭,在Controller層中@RequestMapping標(biāo)注的所有方法都可以看成是一個(gè)Handler,只要可以實(shí)際處理請(qǐng)求就可以是Handler
1.HandlerMapping
iniHandlerMapping(context),處理器映射器今艺,根據(jù)用戶請(qǐng)求資源的url來查找Handler的韵丑,在SpringMVC中會(huì)有很多請(qǐng)求,每個(gè)請(qǐng)求都需要一個(gè)Handler處理虚缎,具體接收到一個(gè)請(qǐng)求之后使用那個(gè)Handler進(jìn)行撵彻,這就是HandlerMapping需要做的事

2.HandlerAdapter
initHandlerAdapter(context),適配器,因?yàn)镾pringMVC中的Handler可以是任意的形式,只要能處理請(qǐng)求就OK陌僵,但是Servlet需要的處理方法的結(jié)構(gòu)確實(shí)固定的轴合,都是以request和response為參數(shù)的方法,如何讓固定的Servlet處理方法調(diào)用靈活的Handler來進(jìn)行處理呢碗短?這就是Handler要做的事情
Handler是哦那個(gè)來干活的工具受葛,HandlerMapping用來根據(jù)需要干的活找到相應(yīng)的工具,HandlerAdapter是使用工具干活的人

3.HandlerExceptionResolver
initHandlerExceptionResolvers(context),其他組件都是用來干活的偎谁,在干活的過程中難免會(huì)出問題总滩,出問題后怎么辦呢?這就需要有一個(gè)轉(zhuǎn)門的角色對(duì)異常情況進(jìn)行處理巡雨,在SpringMVC中就是HandlerExceptionResolver咳秉,具體來說,此組建的作用是根據(jù)異常設(shè)置ModelAndView鸯隅,之后再交給render方法進(jìn)行渲染

4.ViewResolver
initViewResolvers(context),ViewResolver用來將String類型的視圖和Local解析為View類型的視圖澜建,View是用來渲染頁面的,也就是將程序返回的參數(shù)植入模板里蝌以,生成html(也可能是其他類型)文件炕舵。這里就有兩個(gè)關(guān)鍵問題,使用那個(gè)模板跟畅?用什么計(jì)數(shù)(規(guī)則)之惡u參數(shù)咽筋?這其實(shí)是ViewResolver主要做的工作,ViewResolver需要找到渲染所用的模板和所用的計(jì)數(shù)(也就是使徒的類型)進(jìn)行渲染徊件,具體的渲染過程則交由不同的視圖自己完成

5.RequestToViewTranslator
initRequestToViewNameTranslator(context),ViewReslver是根據(jù)ViewName查找View,但有的Handler處理完后并沒有設(shè)置View也沒有設(shè)置ViewName奸攻,這時(shí)就需要從request獲取ViewName了,如何從request中獲取ViewName就是RequestToViewNameTranslator要做的事情了虱痕,RequestToViewNameTranslator在SpringMVC容器里只可以配置一個(gè)睹耐,所以所有request到ViewName的轉(zhuǎn)換規(guī)則都要在一個(gè)Translator里面全部實(shí)現(xiàn)

6.LocalResolver
initLocalResolver(context),解析視圖需要兩個(gè)參數(shù),一是視圖名部翘,另一個(gè)是Local硝训,視圖名是處理器返回的Local是從哪里來的?這就是LocalResolver要做的事情新思,LocalResolver用于從request解析出Local窖梁,Local就是zh-cn之類,標(biāo)識(shí)一個(gè)區(qū)域夹囚,有了這個(gè)就可以對(duì)不同區(qū)域的用戶顯示不同的結(jié)果纵刘,SpringMVC主要有兩個(gè)地方用到了Local:一是ViewResolver視圖解析的時(shí)候;二是用到國際化資源或則主題的時(shí)候

7.ThemeResolver
initThemeResolver(context),用來解析主題荸哟,SpringMVC中一個(gè)主題對(duì)應(yīng)一個(gè)properties文件假哎,里面存放著跟當(dāng)前主題相關(guān)的所有資源蛔翅,如圖片,css樣式等位谋,SpringMVC的主題也支持國際化山析,同一個(gè)主題不同區(qū)域也可以顯示不同的風(fēng)格,SpringMVC中跟主題相關(guān)的類有ThemeResolver掏父,ThemeResource和Theme笋轨,主題是通過一系列資源來具體實(shí)現(xiàn)的,要得到一個(gè)主題的資源赊淑,首先要得到資源的名稱爵政,這是ThemeResolver的工作,然后通過主題名稱找到對(duì)應(yīng)的主題(可以理解為一個(gè)配置)文件陶缺,這是ThemeSource的工作钾挟,最后主題中獲取資源就可以了

8.MultipartResolver
initMultipartResolver(context),用來處理上傳請(qǐng)求,處理方法是將普通的request包裝成MultipartHttpServletRequest饱岸,后者可以直接調(diào)用getFile方法獲取File掺出,如果上傳多個(gè)文件,還可以調(diào)用getFileMap得到FileName -> File結(jié)構(gòu)的Map苫费,此組件中一共有三個(gè)方法汤锨,作用分別是判單是不是上傳請(qǐng)求,將request包裝成MultipartHttpServletRequest,處理完后清理上傳過程中產(chǎn)生的臨時(shí)資源

9.FlashMapManager
initFlashMapManager(context),用來管理FlashMap的百框,F(xiàn)lashMap主要用在redirect中傳遞參數(shù)

45闲礼、SpringBoot自動(dòng)配置原理

@Import + @Configuration + Spring spi
自動(dòng)配置類由各個(gè)starter提供,使用@Configuration + @Bean定義配置類铐维,放到META-INF/spring.factories下使用Spring spi掃描META-INF/spring.factories下的配置類
使用@Import導(dǎo)入自動(dòng)配置類
https://blog.csdn.net/u014745069/article/details/83820511

46柬泽、如何理解Spring Boot中的Starter

使用spring + springmvc使用,如果需要引入mybatis等框架嫁蛇,需要到xml中定義mybatis需要的bean starter就是定義一個(gè)starter的jar包锨并,寫一個(gè)@Configuration配置類,將這些bean定義在里面棠众,然后在starter包的META-INF/spring.factories中寫入改配置類
開發(fā)人員只需要將相應(yīng)的starter包依賴引入琳疏,進(jìn)行相應(yīng)的屬性配置(使用默認(rèn)配置時(shí)有决,不需要配置)闸拿,就可以直接進(jìn)行代碼開發(fā),使用對(duì)應(yīng)的功能了书幕,比如mybatis-spring-boot-starter,spring-boot-starter-redis

47新荤、什么是嵌入式服務(wù)器,為什么要使用嵌入式服務(wù)器

節(jié)省了下載安裝tomcat台汇,應(yīng)用也不需要再打war包苛骨,然后放到webapp目錄下再運(yùn)行
只需要一個(gè)安裝了java的虛擬機(jī)篱瞎,就可以直接在上面部署應(yīng)用程序了
springboot已經(jīng)內(nèi)置了tomcat.jar,運(yùn)行main方法時(shí)會(huì)去啟動(dòng)tomcat痒芝,并利用tomcat的spi機(jī)制加載springmvc

48俐筋、mybatis的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):
1.基于SQL語句編程,相當(dāng)靈活严衬,不會(huì)對(duì)應(yīng)用程序或則數(shù)據(jù)庫的現(xiàn)有設(shè)計(jì)造成任何影響澄者,SQL寫在XML里,接觸sql與程序代碼的耦合请琳,便于統(tǒng)一管理粱挡,提供XML標(biāo)簽,支持編寫動(dòng)態(tài)SQL語句俄精,并可重用
2.與JDBC相比询筏,減少了50%以上的代碼量,消除了JDBC大量冗余的代碼竖慧,不需要手動(dòng)開關(guān)連接
3.很好的與各種數(shù)據(jù)庫兼容(因?yàn)镸yBatis使用JDBC來連接數(shù)據(jù)庫嫌套,所以只要JDBC支持的數(shù)據(jù)庫MyBatis都支持)
4.能夠與Spring很好的集成
5.提供映射標(biāo)簽,支持對(duì)象與數(shù)據(jù)庫的ORM字段的關(guān)系映射圾旨,提供對(duì)象關(guān)系映射標(biāo)簽灌危,支持對(duì)象關(guān)系組件維護(hù)

缺點(diǎn):
1.SQL語句的編寫工作量較大,尤其當(dāng)字段多碳胳,關(guān)聯(lián)表多時(shí)勇蝙,對(duì)開發(fā)人員編寫SQL語句的工地有一定要求
2.SQL語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫移植性較差

49挨约、MyBatis與Hibernate對(duì)比

SQL和ORM的爭論味混,永遠(yuǎn)都不會(huì)停止
開發(fā)速度的對(duì)比:
Hibernate的真正掌握要比mybatis難,mybatis框架相對(duì)簡單容易上手诫惭,但也相對(duì)簡陋些
比起兩者的開發(fā)速度翁锡,不僅僅要考慮到兩者的特性及性能,更要根據(jù)項(xiàng)目需求去考慮究竟哪一個(gè)更合適項(xiàng)目開發(fā)夕土,比如:一個(gè)項(xiàng)目中用到的復(fù)雜查詢基本沒有馆衔,就是簡單的增刪改查,這樣選擇hibernate效率就快很多了怨绣,因?yàn)榛镜膕ql語句都已經(jīng)封裝好了角溃,根本需要你去寫sql語句,這就節(jié)省了大量的時(shí)間篮撑,但是對(duì)于一個(gè)大型項(xiàng)目减细,復(fù)雜語句較多,這樣再去選擇hibernate就不是一個(gè)很好的選擇赢笨,選擇mybatis就會(huì)加快很多未蝌,而且語句的管理也比較方便
開發(fā)工作量的對(duì)比
Hibernate與Mybatis都有相應(yīng)的代碼生成工具驮吱,可以生成簡單基本的DAO層方法,針對(duì)高級(jí)查詢萧吠,mybatis需要手動(dòng)編寫SQL語句左冬,以及ResultMap,而Hibernate有良好的映射機(jī)制,開發(fā)者無需關(guān)心SQL的生成與結(jié)果映射纸型,可以更專心專注于業(yè)務(wù)流程

sql優(yōu)化方面:
Hibernate的查詢會(huì)將表總的所有字段查詢出來又碌,這一點(diǎn)會(huì)有性能消耗。Hibernate也可以自己寫SQL來制定需要查詢的字段绊袋,但這樣就破壞了Hibernate開發(fā)的簡潔性毕匀,而Mybatis的SQL是手動(dòng)編寫的,所以可以按需求指定查詢字段
Hibernate HQL語句的調(diào)優(yōu)需要將sql打印出來癌别,而Hibernate的SQL被很多人嫌棄因?yàn)樘罅嗽聿恚琺ybatis的SQL是自己手動(dòng)編寫的所以調(diào)整方便,但Hibernate具有自己的日志統(tǒng)計(jì)展姐,mybatis本身不帶日志統(tǒng)計(jì)躁垛,使用log4j進(jìn)行日志記錄

對(duì)象管理的對(duì)比:
Hibernate是完整的對(duì)象/關(guān)系映射機(jī)制的解決方案,他提供了對(duì)象狀態(tài)管理(state management)的功能圾笨,使開發(fā)者不再需要理會(huì)底層數(shù)據(jù)庫系統(tǒng)的細(xì)節(jié)教馆,u也就是說,相對(duì)于常見的JDBC/SQL持久層方案中需要管理SQL語句
Hibernate采用了更自然的面向?qū)ο蟮囊暯莵沓志没痡ava應(yīng)用中的數(shù)據(jù)
換句話說擂达,使用Hibernate的開發(fā)者應(yīng)該總數(shù)關(guān)注對(duì)象的狀態(tài)土铺,不必考慮SQL語句的執(zhí)行,這部分細(xì)節(jié)已經(jīng)由Hibernate掌管妥當(dāng)板鬓,只有開發(fā)者再進(jìn)行系統(tǒng)性能條有的時(shí)候才需要進(jìn)行了解悲敷,而mybatis在這一塊沒有文檔說明,用戶需要對(duì)對(duì)象自己進(jìn)行詳細(xì)的管理

緩存機(jī)制對(duì)比
相同點(diǎn):都可以實(shí)現(xiàn)自己的緩存或使用其他第三方緩存方案俭令,創(chuàng)建適配器來完全覆蓋緩存行為
不同點(diǎn):Hibernate的二級(jí)緩存配置在SessionFactory生成的配置文件中進(jìn)行詳細(xì)配置后德,然后再在具體的表-對(duì)象映射中配置是那種緩存
mybatis的耳機(jī)緩存配置都是在每個(gè)具體的表-對(duì)象映射中進(jìn)行詳細(xì)配置,這樣針對(duì)不同的表可以自定義不同的緩存機(jī)制抄腔,并且mybatis可以在命名空間中共享相同的緩存配置和實(shí)例瓢湃,通過cache-ref來實(shí)現(xiàn)
兩者比較:因?yàn)镠ibernate對(duì)查詢對(duì)象有著良好的管理機(jī)制,用戶無需關(guān)心SQL赫蛇,所以在使用二級(jí)緩存時(shí)如果出現(xiàn)臟數(shù)據(jù)绵患,系統(tǒng)會(huì)爆出錯(cuò)誤提示
而mybatis在這一方面,使用二級(jí)緩存需要特別小心棍掐,如果不能完全確定數(shù)據(jù)更行操作的波及范圍藏雏,避免cache的盲目使用,否則作煌,臟數(shù)據(jù)的出現(xiàn)會(huì)給系統(tǒng)的正常運(yùn)行帶來很大的隱患

Hibernate功能強(qiáng)大掘殴,數(shù)據(jù)庫無關(guān)性好,O/R映射能力強(qiáng)粟誓,如果你對(duì)Hibernate相當(dāng)精通奏寨,而且對(duì)Hibernate進(jìn)行了適當(dāng)?shù)姆庋b,那么你的項(xiàng)目整個(gè)持久層代碼會(huì)相當(dāng)簡單鹰服,需要寫的代碼很少病瞳,開發(fā)速度很快,非常爽悲酷。

Hibernate的缺點(diǎn)就是學(xué)習(xí)門檻不低套菜,要精通門檻更高,而且怎么設(shè)計(jì)O/R映射设易,在性能和對(duì)象模型之間如何權(quán)衡取得平衡逗柴,以及怎樣用好Hibernate方面需要你的經(jīng)驗(yàn)和能力都很強(qiáng)才行。

iBATIS入門簡單顿肺,即學(xué)即用戏溺,提供了數(shù)據(jù)庫查詢的自動(dòng)對(duì)象綁定功能,而且延續(xù)了很好的SQL使用經(jīng)驗(yàn)屠尊,對(duì)于沒有那么高的對(duì)象橫型要求的項(xiàng)目來說旷祸,相當(dāng)完美。

iBATIS的缺點(diǎn)就是框架還是比較簡陋讼昆,功能尚有缺失托享,雖然簡化了數(shù)據(jù)綁定代碼,但是整個(gè)底層數(shù)據(jù)庫查詢實(shí)際還是要自己寫的浸赫,工作量也比較大嫌吠,而且不太容易適應(yīng)快速數(shù)據(jù)庫修改,

50、#{}和${}的區(qū)別是什么

1.#{}是預(yù)編譯處理掺炭、是占位符辫诅。S{}是字符串替換、是拼接符

2.Mybatis 在處理#{}時(shí)涧狮,會(huì)將sql 中的#{}替換為?號(hào)炕矮,調(diào)用PreparedStatement來賦值

3.Mybatis在處理${}時(shí),就是把s{}替換成變量的值者冤,調(diào)用Statement來賦道

4.#{}的變量替換是在DBMS中肤视、變量替換后,1督對(duì)應(yīng)的變量白動(dòng)加上單引號(hào)

5.${}的變量替換是在DBMS外涉枫、變量替換后邢滑,S{}對(duì)應(yīng)的變量不會(huì)加上單引號(hào)

6.使用#{}可以有效的方止 SQL注入,提亮系統(tǒng)安全性。

51愿汰、簡述mybatis的插件運(yùn)行原理困后,如何編寫一個(gè)插件

答: Mybatis.只支持針對(duì) ParameterHandler乐纸、ResultSetHandler、StatementHandler摇予、Executor這4種接口的插件汽绢,Mybatis 使用JDK的動(dòng)態(tài)代理,為需要攔截的接口生成代理對(duì)象以實(shí)現(xiàn)接口方法攔截功能侧戴,每當(dāng)執(zhí)行這4種接口對(duì)象的方法時(shí)宁昭,就會(huì)進(jìn)入攔截方法,具體就是InvocationHandler的 invoke()方法酗宋,攔截那些你指定需要攔截的方法积仗。
(插件編寫實(shí)例:https://blog.csdn.net/weixin_44046437/article/details/100526643

52、索引的基本原理

索引用來快速的尋找那些具有特定值的記錄蜕猫,如果沒有索引寂曹,一般來說執(zhí)行查詢時(shí)遍歷整張表
索引的原理:就是把無序數(shù)據(jù)變成有序的查詢
1.把創(chuàng)建了索引的列的內(nèi)容進(jìn)行排列
2.堆排序結(jié)果生成倒排表
3.在倒排表內(nèi)容上拼上數(shù)據(jù)地址鏈
4.在查詢的時(shí)候,先拿到倒排表內(nèi)容丹锹,再取出數(shù)據(jù)地址鏈稀颁,從而拿到具體數(shù)據(jù)

53、mysql聚簇和非聚簇索引的區(qū)別

·聚簇索引:將數(shù)據(jù)存儲(chǔ)與索引放到了一塊楣黍、并且是按照一定的順序組織的匾灶,找到索引也就找到了數(shù)據(jù),數(shù)據(jù)的物理存放順序與索引順序是一致的租漂,即:只要索引是相鄰的阶女,那么對(duì)應(yīng)的數(shù)據(jù)一定也是相鄰地存放在磁盤上的
非聚簇索引:葉子節(jié)點(diǎn)不存儲(chǔ)數(shù)據(jù)、存儲(chǔ)的是數(shù)據(jù)行地址哩治,也就是說根據(jù)索引查找到數(shù)據(jù)行的位置再取磁盤查找數(shù)據(jù)秃踩,這個(gè)就有點(diǎn)類似一本樹的目錄,比如我們要找第三章第一節(jié)业筏,那我們先在這個(gè)目錄里面找憔杨,找到對(duì)應(yīng)的頁碼后再去對(duì)應(yīng)的頁碼看文章

優(yōu)勢(shì):
1、查詢通過聚皎索引可以直接獲收數(shù)據(jù)蒜胖,相比非聚簇索引需要第二次查詢〈非覆蓋索引的情況下)效率要高
2消别、聚族索引對(duì)于范查詢的效率很高,因?yàn)槠鋽?shù)據(jù)是按照大小排列的
3、聚族索引適合用在排序的場合台谢,非聚族索引不適合
劣勢(shì):
1寻狂、維護(hù)索引很昂貴,特別是插入新行或者主鍵被更新導(dǎo)至要分員(page sp1it)的時(shí)候朋沮。建議在大量插入新行后蛇券,選在負(fù)獲較低的時(shí)間段,通過OPTIMIZE TABLE優(yōu)化表,因?yàn)楸仨毐灰苿?dòng)的行數(shù)據(jù)可能造成碎片纠亚。使用獨(dú)亭表空間可以弱化碎片
2塘慕、表因?yàn)槭褂肬UId(例機(jī)ID)作為主鍵,使數(shù)據(jù)存儲(chǔ)稀疏菜枷,這就會(huì)出現(xiàn)聚簇索引有可能有比全表掃面更慢苍糠,所以建議使用int的auto_increment作為主鍵
3叁丧、如果主鍵比較大的話啤誊,那輔助索引將會(huì)變的更大,因?yàn)槲镏饕娜~子存儲(chǔ)的是主鍵值;過長的主鍵值拥娄,公導(dǎo)致非葉子節(jié)點(diǎn)占用占用更多的物理空間

InnoDB中一定有主鍵蚊锹,主鍵一定是聚簇索引,不手動(dòng)設(shè)置稚瘾、則會(huì)使用unique索引牡昆,沒有unique索引,則會(huì)使用數(shù)據(jù)庫內(nèi)部的一個(gè)行的隱藏id來當(dāng)作主鍵索引摊欠。在聚簇索引之上創(chuàng)建的索引稱之為輔助索引丢烘,輔助索引訪問數(shù)據(jù)總是需要二次查找,非聚簇索引都是輔助索引些椒,像復(fù)合索引播瞳、前綴索引、唯一索引免糕,輔助索引葉子節(jié)點(diǎn)存儲(chǔ)的不再是行的物理位置赢乓,而是主鍵值

InnoDB中一定有主鍵,主鍵一定是聚簇索引石窑,不手動(dòng)設(shè)置牌芋、則會(huì)使用unique索引,沒有unique索引松逊,則會(huì)使用數(shù)據(jù)庫內(nèi)部的一個(gè)行的隱藏id來當(dāng)作主鍵索引抛蚁。在聚簇索引之上創(chuàng)建的索引稱之為輔助索引,輔助索引訪問數(shù)據(jù)總是需要二次查找闺兢,非聚簇索引都是輔助索引食寡,像復(fù)合索引、前綴索引烛恤、唯一索引母怜,輔助索引葉子節(jié)點(diǎn)存儲(chǔ)的不再是行的物理位置,而是主鍵值

MyISAM使用的是非聚簇索引缚柏,沒有聚簇索引苹熏,非聚簇索引的兩模B+樹看上去沒什么不同,節(jié)點(diǎn)的結(jié)構(gòu)完全一致只是存儲(chǔ)的內(nèi)容不同而已,主鍵索引B+樹的節(jié)點(diǎn)存儲(chǔ)了主鍵轨域,輔助鍵索引B+樹存儲(chǔ)了輔助鍵袱耽。表數(shù)據(jù)存儲(chǔ)在獨(dú)立的地方,這兩顆B+樹的葉子節(jié)點(diǎn)都使用一個(gè)地址指向真正的表數(shù)據(jù)干发,對(duì)于表數(shù)據(jù)來說朱巨,這兩個(gè)鍵沒有任何差別。由于索引樹是獨(dú)立的枉长,通過輔助鍵檢系無需訪問主鍵的索引樹冀续。
如果涉及到大數(shù)據(jù)量的排序、全表掃描必峰、count之類的操作的話洪唐,還是MyISAM占優(yōu)勢(shì)些,因?yàn)樗饕伎臻g小,這些操作是需要在內(nèi)存中完成的吼蚁。

如果涉及到大數(shù)據(jù)量的排序凭需、全表掃描、count之類的操作的話肝匆,還是MyISAM占優(yōu)勢(shì)些粒蜈,因?yàn)樗饕伎臻g小,這些操作是需要在內(nèi)存中完成的。

54旗国、mysql索引的數(shù)據(jù)結(jié)構(gòu)枯怖,各自優(yōu)劣

索引的數(shù)據(jù)結(jié)構(gòu)和具體存儲(chǔ)引擎的實(shí)現(xiàn)有關(guān),在MySQL中使用較多的索引有Hash索引粗仓,B+樹索引等嫁怀,InnoDB存儲(chǔ)引擎的默認(rèn)索引實(shí)現(xiàn)為:B+樹索引。對(duì)于哈希索引來說借浊,底層的數(shù)據(jù)結(jié)構(gòu)就是哈希表塘淑,因此在絕大多數(shù)需求為單條記錄查詢的時(shí)候,可以選擇哈希索引蚂斤,查詢性能最快;其余大部分場景存捺,建議選擇BTree索引。
B+樹:
B+樹是一個(gè)平衡的多叉樹曙蒸,從根節(jié)點(diǎn)到每個(gè)葉子節(jié)點(diǎn)的高度差值不超過1捌治,而且同層級(jí)的節(jié)點(diǎn)間有指針相互鏈接。在B+樹上的常規(guī)檢索纽窟,從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的搜索效率基本相當(dāng)肖油,不會(huì)出現(xiàn)大幅波動(dòng),而且基于索引的順序掃描時(shí)臂港,也可以利用雙向指針快速左右移動(dòng)森枪,效率非常高视搏。因此,B+樹索引被廣泛應(yīng)用于數(shù)據(jù)庫县袱、文件系統(tǒng)等場景浑娜。
哈希索引:
哈希索引就是采用一定的哈希算法,把鍵值換算成新的哈希值式散,檢索時(shí)不需要類似B+樹那樣從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)逐級(jí)查找筋遭,只需一次哈希算法即可立刻定位到相應(yīng)的位置,速度非潮┲簦快
如果是等值查詢漓滔,那么哈希索引明顯有絕對(duì)優(yōu)勢(shì),因?yàn)橹恍枰?jīng)過一次算法即可找到相應(yīng)的鍵值;前提是鍵值都是唯一的揍移。如果鍵值不是唯一的次和,就需要先找到該鍵所在位置反肋,然后再根據(jù)鏈表往后掃描那伐,直到找到相應(yīng)的數(shù)據(jù);如果是范圍查詢檢索,這時(shí)候哈希索引就毫無用武之地了石蔗,因?yàn)樵仁怯行虻逆I值罕邀,經(jīng)過哈希算法后,有可能變成不連續(xù)的了养距,就沒辦法再利用索引完成范圍查詢檢系;
哈希索引也沒辦法利用索引完成排序诉探,以及l(fā)ike 'xx%′這樣的部分模糊查詢(這種部分模糊查詢,其實(shí)本質(zhì)上也是范圍查詢)
哈希索引也不支持多列聯(lián)合索引的最左匹配規(guī)則;
B+樹索引的關(guān)鍵字檢索效率比較平均棍厌,不像B樹那樣波動(dòng)幅度大肾胯,在有大量重復(fù)犍值情況下,哈希索引的效率也是極低的耘纱,因?yàn)榇嬖诠E鲎矄栴}敬肚。

55、索引的設(shè)計(jì)原則

查詢更快束析、占用空間更小
1.適合索引的列是出現(xiàn)在where子句中的列艳馒,或者連接子句中指定的列
2基數(shù)較小的類,索引效果較差员寇,沒有必要在此列建立索引
3.使用短索引弄慰,如果對(duì)長字符串列進(jìn)行索引,應(yīng)該指定一個(gè)前綴長度蝶锋,這樣能夠節(jié)省大量索引空間陆爽,如果搜索詞超過索引前綴長度,則使用索引排除不匹配的行扳缕,然后檢查其余行是否可能匹配慌闭。
4.不要過度索引恶守。索引需要額外的磁盤空間,并降低寫操作的性能贡必。在修改表內(nèi)容的時(shí)候兔港,索引會(huì)進(jìn)行更新甚至重構(gòu),索引列越多仔拟,這個(gè)時(shí)間就會(huì)越長衫樊。所以只保持需要的索引有利于查詢即可。
5.定義有外鍵的數(shù)據(jù)列一定要建立索引利花。
6.更新頻繁字段不適合創(chuàng)建索引
7.若是不能有效區(qū)分?jǐn)?shù)據(jù)的列不適合做索引列(如性別科侈,男女未知,最多也就三種炒事,區(qū)分度實(shí)在太低)
8.盡量的擴(kuò)展索引臀栈,不要新建索引。比如表中已經(jīng)有a的索引挠乳,現(xiàn)在要加(a,b)的索引权薯,那么只需要修改原來的索引即可。
9.對(duì)于那些查詢中很少涉及的列睡扬,重復(fù)值比較多的列不要建立索引盟蚣。
10.對(duì)于定義為text、image和bit的數(shù)據(jù)類型的列不要建立索引.

56卖怜、mysql鎖的類型有那些

基于鎖的屬性分類:共享鎖屎开、排他鎖
基于鎖的粒度分類:行級(jí)鎖(INNODB)、表級(jí)鎖(INNODB马靠、MYISAM)奄抽、頁級(jí)鎖(BDB引擎)、記錄鎖甩鳄、間隙鎖逞度、臨鍵鎖。
基于鎖的狀態(tài)分類:意向共享鎖娩贷、意向排它鎖第晰。

  • 共享鎖(Share Lock)

共享談?dòng)址Q讀鎖,簡稱S談:當(dāng)一個(gè)事務(wù)為數(shù)據(jù)加上讀領(lǐng)之后彬祖,其他事務(wù)只能對(duì)該數(shù)據(jù)加i讀鎖茁瘦,而不能對(duì)數(shù)據(jù)加寫鎮(zhèn),直到所有的讀鎖釋放之后其他事務(wù)才能對(duì)其進(jìn)行加持寫談。共享鎖的特性主要是為了支持并發(fā)的讀取數(shù)據(jù)储笑,讀取數(shù)據(jù)的時(shí)候不支持修改,避免出現(xiàn)重復(fù)讀的問題甜熔。

  • 排他鎖(exclusive Lock)

排他談?dòng)址Q寫鎖,簡稱X談;當(dāng)一個(gè)事務(wù)為數(shù)據(jù)加上寫鎖時(shí)突倍,其他請(qǐng)求將不能再為數(shù)據(jù)加任何鏡腔稀,直到該頓釋放之后,其他事務(wù)才能對(duì)數(shù)據(jù)進(jìn)行加談盆昙。排他鎖的目的是在數(shù)據(jù)修改時(shí)候,不允許其他人同時(shí)修改焊虏,也不允許其他人讀收淡喜。避免了出現(xiàn)臟數(shù)器和臟讀的問題。

  • 表鎖

表鎖是指上鎖的時(shí)候鎖住的是整個(gè)表诵闭,當(dāng)下一個(gè)事務(wù)訪問該表的時(shí)候炼团,必須等前一個(gè)事務(wù)釋放了鎖才能進(jìn)行對(duì)表進(jìn)行訪問:

  • 行鎖

行鎖是指上鎖的時(shí)候鎖住的是表的某一行或多行記錄,其他事務(wù)訪問同一張表時(shí)疏尿,只有被鏡住的記錄不能訪問瘟芝,其他的記錄可正常訪向
特點(diǎn):粒度小,加談比表談麻煩,不容易沖突褥琐,相比表談支持的并發(fā)要高:

  • 記錄鎖(Record Lock)

記承談也屬于行談中的一種锌俱,只不過記錄鎖的范圍只是表中的某一條記錄,記錄談是說事務(wù)在加鎖后談住的只是表的某一條記錄敌呈。
精準(zhǔn)條件命中,并且命中的條件字段是唯一索引
加了記錄鏡之后數(shù)據(jù)可以避免數(shù)據(jù)在查詢的時(shí)候被修改的重復(fù)讀問題贸宏,也避免了在修改的事務(wù)未提交前被其他事務(wù)讀取的臟讀問題。

  • 頁鎖

頁級(jí)談是MySQL中鎖定粒度介于任級(jí)鏡和表級(jí)鏡中間的一種談驱富。表級(jí)鏡速度快锚赤,但沖突多,行級(jí)沖突少褐鸥,但速度慢。所以取了折裘的頁級(jí)赐稽,一次饃定相鄰的一組記錄叫榕。
特點(diǎn):開銷和加鎖時(shí)間界于表鏡和行鎖之問:會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之問,并發(fā)度一般

  • 間隙鎖(Gap Lock)

屬于行鎖中的一種姊舵,向陬談是在事務(wù)加鎖后其鎮(zhèn)住的是表記錄的某一個(gè)區(qū)間晰绎,當(dāng)表的相鄰ID之間出現(xiàn)空隙則會(huì)形成一個(gè)區(qū)間,遵循左開右閉原則。
范圍查詢并且查詢未命中記錄括丁,查詢條件必須命中索引荞下、問隙談只會(huì)出現(xiàn)在REPEATABLE_READ(重復(fù)讀)的事務(wù)級(jí)別中。
觸發(fā)條件:防止:幻]讀問題史飞,事務(wù)并發(fā)的時(shí)候尖昏,如果沒有問隱鎖,就會(huì)發(fā)生如下圖的問題构资,在同一個(gè)事務(wù)里抽诉,A事務(wù)的兩次查詢出的結(jié)果會(huì)不一樣。
比如表里面的數(shù)據(jù)TD為1,4,5,7,10 ,那么會(huì)形成以下幾個(gè)間隙區(qū)間吐绵,-n-1區(qū)間迹淌,1-4區(qū)間河绽,7-10區(qū)間,10-n區(qū)問(-n代表負(fù)無窮大,n代表正無窮大》

  • 臨建鎖(Next-Key Lock)

也屬于行鎖的一種唉窃,并且它是INNODB的行鎖默認(rèn)算法耙饰,總結(jié)來說它就是記錄鏡和問隙鎖的組合,臨鍵鎖會(huì)把查詢出來的記錄鎖住纹份,同時(shí)也會(huì)把該范圍查詢內(nèi)的所有問隱空間也會(huì)談住榔幸,再之它會(huì)把相鄰的下一個(gè)區(qū)間也會(huì)鎖住
觸發(fā)條件:范圍查詢并命中,查詢命中了索引矮嫉。
結(jié)合記錄談和向陳鎖的特性削咆,臨鍵鎖避免了在范圍查詢時(shí)出現(xiàn)臟讀、重復(fù)讀蠢笋、幻讀問題拨齐。加了臨鍵鎖之后,在范圍區(qū)向內(nèi)數(shù)據(jù)不允許被修改和插入

如果當(dāng)事務(wù)A加鎖成功之后就沒置一個(gè)狀態(tài)告訴后面的人昨寞,已經(jīng)有人對(duì)表里的行加了一個(gè)排他鎖了瞻惋,你們不能對(duì)整個(gè)表加共享鎖或排它鎖了,那么后面需要對(duì)整個(gè)表加鎖的人只需要獲取這個(gè)狀態(tài)就知道自己是不是可以對(duì)表加鎖援岩,避免了對(duì)整個(gè)索引樹的每個(gè)節(jié)點(diǎn)掃描是否加鎖歼狼,而這個(gè)狀態(tài)就是意向鎖。

  • 意向共享鎖

當(dāng)一個(gè)事務(wù)試圖對(duì)整個(gè)表進(jìn)行加共亭談之前享怀,首先需要獲得這個(gè)表的意向共亭談羽峰。

  • 意向排他鎖

當(dāng)一個(gè)事務(wù)試圖對(duì)整個(gè)表進(jìn)行加排它鏡之前,首先需要獲得這個(gè)表的意向排它談添瓷。

57梅屉、mysql執(zhí)行計(jì)劃怎么看

執(zhí)行計(jì)劃就是sql的執(zhí)行查詢的順序,以及如何使用索引查詢鳞贷,返回的結(jié)果集的行數(shù)EXPLAIN SELECT * from A where x=? and Y=?


image.png

1.id :是一個(gè)有順序的編號(hào)坯汤,是查詢的順序號(hào),有幾個(gè)select就顯示幾行搀愧。id的順序是按select 出現(xiàn)的順序增長的惰聂。id列的值越大執(zhí)行優(yōu)先級(jí)越高越先執(zhí)行,id列的值相同則從上往下執(zhí)行咱筛,id列的值為NULL最后執(zhí)行搓幌。
2.selectType表示查詢中每個(gè)select子句的類型

  • SIMPLE:表示此查詢不包含UNION查詢或子查詢.PRIMARY:表示此查詢是最外層的查詢(包含子查詢)- SuBQUERY:子查詢中的第一個(gè)SELECT
  • UNION:表示此查詢是 UNION的第二或隨后的查詢
  • DEPENDENT UNION: UNION 中的第二個(gè)或后面的查詢語句,取決于外面的查詢 uNION RESULT,UNION的結(jié)果
  • DEPENDENT SUBQUERY:子查詢中的第一個(gè)SELECT,取決于外面的查詢.即子查詢依賴于外層查詢的結(jié)果. DERIVED:衍生,表示導(dǎo)出表的SELECT (FROM子句的子查詢)

3.table:表示該語句查詢的表
4.type:優(yōu)化sql的重要字段眷蚓,也是我們判斷sal性能和優(yōu)化程度重要指標(biāo)鼻种。他的取值類型范圍:

  • const:通過索引一次命中,匹配一行數(shù)據(jù)
  • system:表中只有一行記錄沙热,相當(dāng)于系統(tǒng)表;
  • eq_ref:唯一性索引掃描叉钥,對(duì)于每個(gè)索引鍵罢缸,表中只有一條記錄與之匹配ref:非唯一性索引掃描,返回匹配某個(gè)值的所有
  • range:只檢索給定范圍的行,使用一個(gè)索引來選擇行投队,一般用于between枫疆、<、>; index:只遍歷索引樹;
  • ALL:表示全表掃描敷鸦,這個(gè)類型的查詢是性能最差的查詢之一息楔。那么基本就是隨著表的數(shù)量增多,執(zhí)行效率越慢扒披。

執(zhí)行效率:
ALL < index <range< ref <eq_ref < const < system值依。最好是避免ALL和index

5.possible_keys:它表示Mysql在執(zhí)行該sqli語句的時(shí)候,可能用到的索引信息碟案,僅僅是可能愿险,實(shí)際不一定會(huì)用到。
6.key:此字段是 mysql在當(dāng)前查詢時(shí)所真正使用到的索引价说。他是possible_keys的子集

58辆亏、事務(wù)的基本特性和隔離級(jí)別

事務(wù)基本特性ACID分別是:
原子性指的是一個(gè)事務(wù)中的操作要么全部成功,要么全部失敗鳖目。
一致性指的是數(shù)據(jù)庫總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)換到另外一個(gè)一致性的狀態(tài)扮叨。比如A轉(zhuǎn)賬給B100塊錢,假設(shè)A只有90塊领迈,支付之前我們數(shù)據(jù)庫里的數(shù)據(jù)都是符合約束的,但是如果事務(wù)執(zhí)行成功了,我們的數(shù)據(jù)庫數(shù)據(jù)就破壞約束了,因此事務(wù)不能成功,這里我們說事務(wù)提供了一致性的保證
隔離性指的是一個(gè)事務(wù)的修改在最終提交前彻磁,對(duì)其他事務(wù)是不可見的。持久性指的是一旦事務(wù)提交惦费,所做的修改就會(huì)永久保存到數(shù)據(jù)庫中兵迅。
隔離性有4個(gè)隔離級(jí)別,分別是:

  • read uncommit讀未提交薪贫,可能會(huì)讀到其他事務(wù)未提交的數(shù)據(jù),t也叫做臟讀
    用戶本來應(yīng)該讀取到id=1的用戶age應(yīng)該是10刻恭,結(jié)果讀取到了其他事務(wù)還沒有提交的事務(wù)瞧省,結(jié)果讀取結(jié)果age=20,這就是臟讀鳍贾。
  • read commit讀已提交鞍匾,兩次讀取結(jié)果不一致,叫做不可重復(fù)讀骑科。不可重復(fù)讀解決了臟讀的問題橡淑,他只會(huì)讀取已經(jīng)提交的事務(wù)
    用戶開啟事務(wù)讀取id=1用戶,查詢到age=10咆爽,再次讀取發(fā)現(xiàn)結(jié)果=20梁棠,在同一個(gè)事務(wù)里同一個(gè)查詢讀取到不同
  • repeatable read 可重復(fù)復(fù)讀置森,這是mysql的默認(rèn)級(jí)別,就是每次讀取結(jié)果都一樣符糊,但是有可能產(chǎn)生幻讀凫海。
  • serializable 串行,一般是不會(huì)使用的男娄,他會(huì)給每一行讀取的數(shù)據(jù)加鎖行贪,會(huì)導(dǎo)致大量超時(shí)和鎖競爭的問題

59、關(guān)心過業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎?統(tǒng)計(jì)過慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過?

在業(yè)務(wù)系統(tǒng)中模闲,除了使用主鍵進(jìn)行的查詢建瘫,其他的都會(huì)在測(cè)試庫上測(cè)試其耗時(shí),慢查詢的統(tǒng)計(jì)主要由運(yùn)維在做尸折,會(huì)定期將業(yè)務(wù)中的慢查詢反饋給我們啰脚。
慢查詢的優(yōu)化首先要搞明白慢的原因是什么?是查詢條件沒有命中索引?是load了不需要的數(shù)據(jù)列?還是數(shù)據(jù)量太大?

所以優(yōu)化也是針對(duì)這三個(gè)方向來的

  • 首先分析語句,看看是否load了額外的數(shù)據(jù)翁授,可能是查詢了多余的行并且拋棄掉了拣播,可能是加載了許多結(jié)果中并不需要的列,對(duì)語句進(jìn)行分析以及重寫收擦。
  • 分析語句的執(zhí)行計(jì)劃贮配,然后獲得其使用索引的情況,之后修改語句或者修改索引塞赂,使得語句可以盡可能的命中索引泪勒。
  • 如果對(duì)語句的優(yōu)化已經(jīng)無法進(jìn)行,可以考慮表中的數(shù)據(jù)量是否太大宴猾,如果是的話可以進(jìn)行橫向或者縱向的分表圆存。

60、ACID靠什么保證的?

A原子性由undo log日志保證仇哆,它記錄了需要回滾的日志信息沦辙,事務(wù)回滾時(shí)撤銷已經(jīng)執(zhí)行成功的sql

C一致性由其他三大特性保證、程序代碼要保證業(yè)務(wù)上的一致性

l隔離性由MVCC來保證

D持久性由內(nèi)存+redo log來保證讹剔,mysq|修改數(shù)據(jù)同時(shí)在內(nèi)存和redo log記錄這次操作油讯,宕機(jī)的時(shí)候可以從redolog恢復(fù)

InnoD8 redo log寫盤,InnoDB事務(wù)進(jìn)入prepare狀態(tài)。
如果前面 prepare 成功延欠,binlog 寫盤陌兑,再繼續(xù)將事務(wù)日志持久化到 bin1og,如果持久化成功由捎,那么兔综、InnoDB事務(wù)則進(jìn)入commit狀態(tài)(在 redo log里面寫一個(gè)commit記錄)

redolog的刷盤會(huì)在系統(tǒng)空閑時(shí)進(jìn)行

61、什么是MVCC

多版本并發(fā)控制:讀取數(shù)據(jù)時(shí)通過一種類似快照的方式將數(shù)據(jù)保存下來,這樣讀鎖就和寫鎖不沖突了软驰,不同的事務(wù)session會(huì)看到自己特定版本的數(shù)據(jù)涧窒,版本鏈

MVCC只在 READCOMMITED和REPEATABLE READ兩個(gè)隔離級(jí)別下工作。其他兩個(gè)隔離級(jí)別夠和MVCC不兼容,因?yàn)镽EAD UNCOMMITTED總是讀取最新的數(shù)據(jù)行,而不是符合當(dāng)前事務(wù)版本的數(shù)據(jù)行碌宴。而SERIALIZABLE則會(huì)對(duì)所有讀取的行都加鎖,

聚簇索引記錄中有兩個(gè)必要的隱藏列:

trx_id:用來存儲(chǔ)每次對(duì)某條聚簇索引記錄進(jìn)行修改的時(shí)候的事務(wù)id.

roll_pointer:每次對(duì)哪條聚簇索引記錄有修改的時(shí)候杀狡,都會(huì)把老版本寫入undo日志中。這個(gè)roll_pointer就是存了一個(gè)指針贰镣,它指向這條聚簇索引記錄的上一個(gè)版本的位置呜象,通過它來獲得上一個(gè)版本的記錄信息。(注意插入操作的undo日志沒有這個(gè)屬性碑隆,因?yàn)樗鼪]有老版本)

已提交讀和可重復(fù)讀的區(qū)別就在于它們生成Readview的策略不同恭陡。


image.png

開始事務(wù)時(shí)創(chuàng)建readview,readView維護(hù)當(dāng)前活動(dòng)的事務(wù)id上煤,即未提交的事務(wù)id休玩,排序生成一個(gè)數(shù)組訪問數(shù)據(jù),獲取數(shù)據(jù)中的事務(wù)id(獲取的是事務(wù)id最大的記錄)劫狠,對(duì)比readview:

如果在readview的左邊(比readview都小)拴疤,可以訪問(在左邊意味著該事務(wù)已經(jīng)提交)

如果在readview的右邊(比readview都大)或者就在readview中,不可以訪問独泞,獲取roll_pointer呐矾,取上一版本重新對(duì)比(在右邊意味著,該事務(wù)在readview生成之后出現(xiàn)懦砂,在readview中意味著該事務(wù)還未提交)

已提交讀隔離級(jí)別下的事務(wù)在每次查詢的開始都會(huì)生成一個(gè)獨(dú)立的ReadView,而可重復(fù)讀隔離級(jí)別則在第一次讀的時(shí)候生成一個(gè)Readview蜒犯,之后的讀都復(fù)用之前的Readview。

這就是Mysql的MVCC,通過版本鏈荞膘,實(shí)現(xiàn)多版本罚随,可并發(fā)讀·寫,寫·讀羽资。通過ReadView生成策略的不同實(shí)現(xiàn)不同的隔離級(jí)別淘菩。

62、mysql主從同步原理

mysql主從同步的過程:
Mysql的主從復(fù)制中主要有三個(gè)線程:master(binlog duno thread) . slave(I/o thread . sQLthread, Master—條線程和Slave中的兩條線程屠升。

  • 主節(jié)點(diǎn)binlog瞄勾,主從復(fù)制的基礎(chǔ)是主庫記錄數(shù)據(jù)庫的所有變更記錄到 binlog。binlog是數(shù)據(jù)庫服務(wù)器啟動(dòng)的那一刻起弥激,保存所有修改數(shù)據(jù)庫結(jié)構(gòu)或內(nèi)容的一個(gè)文件。
  • 主節(jié)點(diǎn) log dump線程愿阐,當(dāng)binlog有變動(dòng)時(shí)微服,log dump線程讀取其內(nèi)容并發(fā)送給從節(jié)點(diǎn)。
  • 從節(jié)點(diǎn)VO線程接收binlog內(nèi)容缨历,并將其寫入到relay log文件中以蕴。
  • ·從節(jié)點(diǎn)的SQL線程讀取relay log文件內(nèi)容對(duì)數(shù)據(jù)更新進(jìn)行重放糙麦,最終保證主從數(shù)據(jù)庫的一致性。

注:主從節(jié)點(diǎn)使用 binglog文件+ position偏移量來定位主從同步的位置丛肮,從節(jié)點(diǎn)會(huì)保存其已接收到的偏移量赡磅,如果從節(jié)點(diǎn)發(fā)生宕機(jī)重啟,則會(huì)自動(dòng)從position 的位置發(fā)起同步宝与。

由于mysql默認(rèn)的復(fù)制方式是異步的焚廊,主庫把日志發(fā)送給從庫后不關(guān)心從庫是否已經(jīng)處理,這樣會(huì)產(chǎn)生一個(gè)問題就是假設(shè)主庫掛了习劫,從庫處理失敗了咆瘟,這時(shí)候從庫升為主庫后,日志就丟失了诽里。由此產(chǎn)生兩個(gè)概念袒餐。

全同步復(fù)制
主庫寫入binlog后強(qiáng)制同步日志到從庫,所有的從庫都執(zhí)行完成后才返回給客戶端谤狡,但是很顯然這個(gè)方式的話性能會(huì)受到嚴(yán)重影響灸眼。

半同步復(fù)制
和全同步不同的是,半同步復(fù)制的邏輯是這樣墓懂,從庫寫入日志成功后返回ACK確認(rèn)給主庫焰宣,主庫收到至少一個(gè)從庫的確認(rèn)就認(rèn)為寫操作完成,

63、簡述MyISAM和InnoDB的區(qū)別

MyISAM:

  • 不支持事務(wù)拒贱,但是每次查詢都是原子的
  • 支持表級(jí)鎖宛徊,即每次操作是對(duì)整個(gè)表加鎖;
  • 存儲(chǔ)表的總行數(shù);
  • 一個(gè)MYISAM表有三個(gè)文件:索引文件、表結(jié)構(gòu)文件逻澳、數(shù)據(jù)文件;
  • 采用非聚集索引闸天,索引文件的數(shù)據(jù)域存儲(chǔ)指向數(shù)據(jù)文件的指針。輔索引與主索引基本一致斜做,但是輔索引不用保證唯一性箭启。

lnnoDb:

  • 支持ACID的事務(wù)鹿寨,支持事務(wù)的四種隔離級(jí)別;
  • 支持行級(jí)鎖及外鍵約束:因此可以支持寫并發(fā);
  • 不存儲(chǔ)總行數(shù);
  • 一個(gè)InnoDb引擎存儲(chǔ)在一個(gè)文件空間(共享表空間,表大小不受操作系統(tǒng)控制,一個(gè)表可能分布在多個(gè)文件里)春畔,也有可能為多個(gè)(設(shè)置為獨(dú)立表空,表大小受操作系統(tǒng)文件大小限制圣絮,一般為2G)秕脓,受操作系統(tǒng)文件大小的限制;
  • 主鍵索引采用聚集索引(索引的數(shù)據(jù)域存儲(chǔ)數(shù)據(jù)文件本身),輔索引的數(shù)據(jù)域存儲(chǔ)主鍵的值;因此從輔索引查找數(shù)據(jù)诱告,需要先通過輔索引找到主鍵值撵枢,再訪問輔索引;最好使用自增主鍵,防止插入數(shù)據(jù)時(shí),為維持B+樹結(jié)構(gòu)锄禽,文件的大調(diào)整潜必。

64、簡述mysql中索引類型及對(duì)數(shù)據(jù)庫的性能的影響

  • 普通索引:允許被索引的數(shù)據(jù)列包含重復(fù)的值沃但。

  • 唯一索引:可以保證數(shù)據(jù)記錄的唯一性磁滚。

  • 主鍵:是一種特殊的唯一索引,在一張表中只能定義一個(gè)主鍵索引宵晚,主鍵用于唯一標(biāo)識(shí)一條記錄垂攘,使用關(guān)鍵字PRIMARY KEY 來創(chuàng)建。

  • 聯(lián)合索引:索引可以覆蓋多個(gè)數(shù)據(jù)列坝疼,如像INDEX(columnA, columnB)索引搜贤。

  • 全文索引:通過建立倒排索引,可以極大的提升檢索效率,解決判斷字段是否包含的問題,是目前搜索引擎使用的一種關(guān)鍵技術(shù)钝凶∫敲ⅲ可以通過ALTER TABLE table_name ADD FULLTEXT (column);創(chuàng)建全文索引

  • 索引可以極大的提高數(shù)據(jù)的查詢速度。

  • 通過使用索引耕陷,可以在查詢的過程中掂名,使用優(yōu)化隱藏器,提高系統(tǒng)的性能哟沫。

  • 但是會(huì)降低插入饺蔑、刪除、更新表的速度嗜诀,因?yàn)樵趫?zhí)行這些寫操作時(shí)猾警,還要操作索引文件

  • 索引需要占物理空間,除了數(shù)據(jù)表占數(shù)據(jù)空間之外隆敢,每一個(gè)索引還要占一定的物理空間发皿,如果要建立聚簇索引,那么需要的空間就會(huì)更大拂蝎,如果非聚集索引很多穴墅,一旦聚集索引改變,那么所有非聚集索引都會(huì)跟著變温自。

65玄货、RDB和AOF機(jī)制

RDB: Redis DataBase
在指定的時(shí)間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤,實(shí)際操作過程是fork一個(gè)子進(jìn)程悼泌,先將數(shù)據(jù)集寫入臨時(shí)文件松捉,寫入成功后,再替換之前的文件馆里,用二進(jìn)制壓縮存儲(chǔ)惩坑。

優(yōu)點(diǎn):
1掉盅、整個(gè)Redis數(shù)據(jù)庫將只包含—個(gè)文件dump.rdb,方便持久化以舒。
2、容災(zāi)性好慢哈,方便備份蔓钟。
3、性能最大化卵贱,fork子進(jìn)程來完成寫操作滥沫,讓主進(jìn)程繼續(xù)處理命令,所以是IO最大化键俱。使用單獨(dú)子進(jìn)程來進(jìn)行持久化兰绣,主進(jìn)程不會(huì)進(jìn)行任何IO操作,保證了redis 的高性能
4.相對(duì)于數(shù)據(jù)集大時(shí)编振,比AOF的啟動(dòng)效率更高缀辩。

缺點(diǎn):
1、數(shù)據(jù)安全性低踪央。RDB是間隔一段時(shí)間進(jìn)行持久化臀玄,如果持久化之間redis 發(fā)生故障,會(huì)發(fā)生數(shù)據(jù)丟失畅蹂。所以這種方式更適合數(shù)據(jù)要求不嚴(yán)謹(jǐn)?shù)臅r(shí)候)
2健无、由于RDB是通過fork子進(jìn)程來協(xié)助完成數(shù)據(jù)持久化工作的,因此液斜,如果當(dāng)數(shù)據(jù)集較大時(shí)累贤,可能會(huì)導(dǎo)致整個(gè)服務(wù)器停止服務(wù)幾百亳秒,甚至是1秒鐘少漆。

AOF:Append Only File
以日志的形式記錄服務(wù)器所處理的每一個(gè)寫臼膏、刪除操作,查詢操作不會(huì)記錄检疫,以文本的方式記錄讶请,可以打開文件看到詳細(xì)的操作記錄

優(yōu)點(diǎn):
1、數(shù)據(jù)安全屎媳,Redis中提供了3中同步策略夺溢,即每秒同步、每修改同步和不同步烛谊。事實(shí)上风响,每秒同步也是異步完成的,真效率也是非常高的丹禀,所差的是一旦系統(tǒng)出現(xiàn)宕機(jī)現(xiàn)象状勤,那么這一秒鐘之內(nèi)修改的數(shù)據(jù)將會(huì)丟失鞋怀。而每修改同步,我們可以將其視為同步持久化持搜,即每次發(fā)生的數(shù)據(jù)變化都會(huì)被立即記錄到磁盤中密似。
2、通過append模式寫文件葫盼,即使中途服務(wù)器宕機(jī)也不會(huì)破壞已經(jīng)存在的內(nèi)容残腌,可以通過redis-check-aof 工具解決數(shù)據(jù)一致性問題。
3贫导、AOF機(jī)制的rewrite模式抛猫。定期對(duì)AOF文件進(jìn)行重寫,以達(dá)到壓縮的目的

缺點(diǎn):
1孩灯、AOF文件比 RDB文件大闺金,且恢復(fù)速度慢.
2、數(shù)據(jù)集大的時(shí)候峰档,比rdb啟動(dòng)效率低败匹。
3、運(yùn)行效率沒有RDB高

AOF文件比RDB更新顏率高,優(yōu)先使用AOF還原數(shù)據(jù)面哥。
AOF比RDB更安全也更大
RDB性能比AOF好
如果兩個(gè)都配了優(yōu)先加載AOF

66哎壳、Redis的過期鍵的刪除策略

Redis是key-value數(shù)據(jù)庫,我們可以設(shè)置Redis中緩存的key的過期時(shí)間尚卫。Redis的過期策略就是指當(dāng)Redis中緩存的key過期了归榕,Redis如何處理。

  • 惰性過期:只有當(dāng)訪問一個(gè)key時(shí)吱涉,才會(huì)判斷該key是否已過期刹泄,過期則清除。該策略可以最大化地節(jié)省CPU資源怎爵,卻對(duì)內(nèi)存非常不友好特石。極端情況可能出現(xiàn)大量的過期key沒有再次被訪問,從而不會(huì)被清除鳖链,占用大量內(nèi)存姆蘸。
  • 定期過期:每隔一定的時(shí)間,會(huì)掃描一定數(shù)量的數(shù)據(jù)庫的expires字典中一定數(shù)量的key芙委,并清除其中已過期的key逞敷。該策略是前兩者的一個(gè)折中方案。通過調(diào)整定時(shí)掃描的時(shí)間間隔和每次掃描的限定耗時(shí)灌侣,可以在不同情況下使得CPU和內(nèi)存資源達(dá)到最優(yōu)的平衡效果推捐。

(expires字典會(huì)保存所有設(shè)置了過期時(shí)間的key的過期時(shí)間數(shù)據(jù),其中侧啼,key是指向鍵空間中的某個(gè)鍵的指針牛柒,value是該鍵的亳秒精度的UNIX時(shí)間戳表示的過期時(shí)間堪簿。鍵空間是指該Redis集群中保存的所有鍵。)

Redis中同時(shí)使用了惰性過期和定期過期兩種過期策略皮壁。

67椭更、Redis線程模型、單線程快的原因

Redis基于Reactor模式開發(fā)了網(wǎng)絡(luò)事件處理器闪彼,這個(gè)處理器叫做文件事件處理器file event handler甜孤。這個(gè)文件事件處理器,它是單線程的畏腕,所以Redis 才叫做單線程的模型,它采用IO多路復(fù)用機(jī)制來同時(shí)監(jiān)聽多個(gè)Socket茉稠,根據(jù)Socket上的事件類型來選擇對(duì)應(yīng)的事件處理器來處理這個(gè)事件描馅。可以實(shí)現(xiàn)高性能的網(wǎng)絡(luò)通信模型而线,又可以跟內(nèi)部其他單線程的模塊進(jìn)行對(duì)接铭污,保證了 Redis 內(nèi)部的線程模型的簡單性。

文件事件處理器的經(jīng)鉤包含4個(gè)部分:多個(gè)Socket膀篮、IO多路復(fù)用程序嘹狞、文件事件分派器以及事件處理器(命令請(qǐng)求處理器、命令回復(fù)處理器誓竿、連接應(yīng)答處理器等)磅网。

多個(gè)Socket可能并發(fā)的產(chǎn)生不同的操作,每個(gè)操作對(duì)應(yīng)不同的文件事件筷屡,但是IO多路復(fù)用程序會(huì)監(jiān)聽多個(gè)Socket涧偷,會(huì)將Socket放入一個(gè)隊(duì)列中排隊(duì),每次從隊(duì)列中取出一個(gè)Socket給事件分派器毙死,事件分派器把Socket給對(duì)應(yīng)的事件處理器燎潮。

然后一個(gè)Socket的事件處理完之后,IO多路復(fù)用程序才會(huì)將隊(duì)列中的下一個(gè)Socket給事件分派器扼倘。文件事件分派器會(huì)根據(jù)每個(gè)Socket當(dāng)前產(chǎn)生的事件确封,來選擇對(duì)應(yīng)的事件處理器來處理。

單線程快的原因:
1)純內(nèi)存操作
2)核心是基于非阻塞的IO多路復(fù)用機(jī)制
3)單線程反而避免了多線程的頻繁上下文切換帶來的性能問題

68再菊、緩存雪崩爪喘、緩存穿透、緩存擊穿

緩存雪崩是指緩存同一時(shí)間大面積的失效袄简,所以腥放,后面的請(qǐng)求都會(huì)落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉绿语。
解決方案:

  • 緩存數(shù)據(jù)的過期時(shí)間設(shè)置隨機(jī)秃症,防止同一時(shí)間大量數(shù)據(jù)過期現(xiàn)象發(fā)生候址。
  • 給每一個(gè)緩存數(shù)據(jù)增加相應(yīng)的緩存標(biāo)記,記錄緩存是否失效种柑,如果緩存標(biāo)記失效岗仑,則更新數(shù)據(jù)緩存。
  • 緩存預(yù)熱
  • 互斥鎖

緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù)聚请,導(dǎo)致所有的請(qǐng)求都落到數(shù)據(jù)庫上荠雕,造成數(shù)據(jù)庫短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉。
解決方案:

  • 接口層增加校驗(yàn)驶赏,如用戶鑒權(quán)校驗(yàn)炸卑,id做基礎(chǔ)校驗(yàn),id<=O的直接攔截;
  • 從緩存取不到的數(shù)據(jù),在數(shù)據(jù)庫中也沒有取到煤傍,這時(shí)也可以將key-value對(duì)寫為key-null盖文,緩存有效時(shí)間可以設(shè)置短點(diǎn),如30秒(設(shè)置太長會(huì)導(dǎo)致正常情況也沒法使用)蚯姆。這樣可以防止攻擊用戶反復(fù)用同一個(gè)id暴力攻擊
  • 采用布降過濾器五续,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的 bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmap欄戰(zhàn)掉.從而游免了對(duì)底食存儲(chǔ)系結(jié)的查詢壓力

d

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末龄恋,一起剝皮案震驚了整個(gè)濱河市疙驾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郭毕,老刑警劉巖它碎,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铣卡,居然都是意外死亡链韭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門煮落,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敞峭,“玉大人,你說我怎么就攤上這事蝉仇⌒铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵轿衔,是天一觀的道長沉迹。 經(jīng)常有香客問我,道長害驹,這世上最難降的妖魔是什么鞭呕? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮宛官,結(jié)果婚禮上葫松,老公的妹妹穿的比我還像新娘瓦糕。我一直安慰自己,他們只是感情好腋么,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布咕娄。 她就那樣靜靜地躺著,像睡著了一般珊擂。 火紅的嫁衣襯著肌膚如雪圣勒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天摧扇,我揣著相機(jī)與錄音圣贸,去河邊找鬼。 笑死扛稽,一個(gè)胖子當(dāng)著我的面吹牛旁趟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庇绽,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼橙困!你這毒婦竟也來了瞧掺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤凡傅,失蹤者是張志新(化名)和其女友劉穎辟狈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夏跷,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哼转,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了槽华。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壹蔓。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖猫态,靈堂內(nèi)的尸體忽然破棺而出佣蓉,到底是詐尸還是另有隱情,我是刑警寧澤亲雪,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布勇凭,位于F島的核電站,受9級(jí)特大地震影響义辕,放射性物質(zhì)發(fā)生泄漏虾标。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一灌砖、第九天 我趴在偏房一處隱蔽的房頂上張望璧函。 院中可真熱鬧傀蚌,春花似錦、人聲如沸柳譬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽美澳。三九已至销部,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間制跟,已是汗流浹背舅桩。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雨膨,地道東北人擂涛。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像聊记,于是被迫代替她去往敵國和親撒妈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容