1.JVM 堆內(nèi)存和非堆內(nèi)存
堆和非堆內(nèi)存
按照官方的說法:“Java 虛擬機具有一個堆(Heap),堆是運行時數(shù)據(jù)區(qū)域,所有類實例和數(shù)組的內(nèi)存均從此處分配。堆是在 Java 虛擬機啟動時創(chuàng)建的?!薄霸贘VM中堆之外的內(nèi)存稱為非堆內(nèi)存(Non-heap memory)”。
JVM主要管理兩種類型的內(nèi)存:堆和非堆。
Heap memory Code Cache
Eden Space
Survivor Space
Tenured Gen
non-heap memory Perm Gen
native heap?(I guess)堆內(nèi)存
Java 虛擬機具有一個堆,堆是運行時數(shù)據(jù)區(qū)域,所有類實例和數(shù)組的內(nèi)存均從此處分配。堆是在 Java 虛擬機啟動時創(chuàng)建的。對象的堆內(nèi)存由稱為垃圾回收器的自動內(nèi)存管理系統(tǒng)回收。
堆的大小可以固定,也可以擴大和縮小。堆的內(nèi)存不需要是連續(xù)空間。非堆內(nèi)存
Java 虛擬機管理堆之外的內(nèi)存(稱為非堆內(nèi)存)。
Java 虛擬機具有一個由所有線程共享的方法區(qū)。方法區(qū)屬于非堆內(nèi)存。它存儲每個類結(jié)構(gòu),如運行時常數(shù)池、字段和方法數(shù)據(jù),以及方法和構(gòu)造方法的代碼。它是在 Java 虛擬機啟動時創(chuàng)建的。
方法區(qū)在邏輯上屬于堆,但 Java 虛擬機實現(xiàn)可以選擇不對其進(jìn)行回收或壓縮。與堆類似,方法區(qū)的大小可以固定,也可以擴大和縮小。方法區(qū)的內(nèi)存不需要是連續(xù)空間。
除了方法區(qū)外,Java 虛擬機實現(xiàn)可能需要用于內(nèi)部處理或優(yōu)化的內(nèi)存,這種內(nèi)存也是非堆內(nèi)存。例如,JIT 編譯器需要內(nèi)存來存儲從 Java 虛擬機代碼轉(zhuǎn)換而來的本機代碼,從而獲得高性能。幾個基本概念
PermGen space:全稱是Permanent Generation space,即永久代。就是說是永久保存的區(qū)域,用于存放Class和Meta信息,Class在被Load的時候被放入該區(qū)域,GC(Garbage Collection)應(yīng)該不會對PermGen space進(jìn)行清理,所以如果你的APP會LOAD很多CLASS的話,就很可能出現(xiàn)PermGen space錯誤。
Heap space:存放Instance。
Java Heap分為3個區(qū),Young即新生代,Old即老生代和Permanent。
Young保存剛實例化的對象。當(dāng)該區(qū)被填滿時,GC會將對象移到Old區(qū)。Permanent區(qū)則負(fù)責(zé)保存反射對象。堆內(nèi)存分配
JVM初始分配的堆內(nèi)存由-Xms指定,默認(rèn)是物理內(nèi)存的1/64;
JVM最大分配的堆內(nèi)存由-Xmx指定,默認(rèn)是物理內(nèi)存的1/4。
默認(rèn)空余堆內(nèi)存小于40%時,JVM就會增大堆直到-Xmx的最大限制;
空余堆內(nèi)存大于70%時,JVM會減少堆直到-Xms的最小限制。
因此服務(wù)器一般設(shè)置-Xms、-Xmx 相等以避免在每次GC 后調(diào)整堆的大小。
說明:如果-Xmx 不指定或者指定偏小,應(yīng)用可能會導(dǎo)致java.lang.OutOfMemory錯誤,此錯誤來自JVM,不是Throwable的,無法用try…catch捕捉。非堆內(nèi)存分配
- JVM使用-XX:PermSize設(shè)置非堆內(nèi)存初始值,默認(rèn)是物理內(nèi)存的1/64;
- 由XX:MaxPermSize設(shè)置最大非堆內(nèi)存的大小,默認(rèn)是物理內(nèi)存的1/4。
還有一說:MaxPermSize缺省值和-server -client選項相關(guān),-server選項下默認(rèn)MaxPermSize為64m,-client選項下默認(rèn)MaxPermSize為32m。這個我沒有實驗。 - XX:MaxPermSize設(shè)置過小會導(dǎo)致java.lang.OutOfMemoryError: PermGen space 就是內(nèi)存益出。
- 為什么會內(nèi)存益出:
這一部分內(nèi)存用于存放Class和Meta的信息,Class在被 Load的時候被放入PermGen space區(qū)域,它和存放Instance的Heap區(qū)域不同。
GC(Garbage Collection)不會在主程序運行期對PermGen space進(jìn)行清理,所以如果你的APP會LOAD很多CLASS 的話,就很可能出現(xiàn)PermGen space錯誤。 - 這種錯誤常見在web服務(wù)器對JSP進(jìn)行pre compile的時候。
2.MySQL大數(shù)據(jù)量分頁查詢方法及其優(yōu)化
---方法1: 直接使用數(shù)據(jù)庫提供的SQL語句
---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N
---適應(yīng)場景: 適用于數(shù)據(jù)量較少的情況(元組百/千級)
---原因/缺點: 全表掃描,速度會很慢 且 有的數(shù)據(jù)庫結(jié)果集返回不穩(wěn)定(如某次返回1,2,3,另外的一次返回2,1,3). Limit限制的是從結(jié)果集的M位置處取出N條輸出,其余拋棄.
---方法2: 建立主鍵或唯一索引, 利用索引(假設(shè)每頁10條)**
---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 WHERE id_pk > (pageNum10) LIMIT M
---適應(yīng)場景: 適用于數(shù)據(jù)量多的情況(元組數(shù)上萬)
---原因: 索引掃描,速度會很快. 有朋友提出: 因為數(shù)據(jù)查詢出來并不是按照pk_id排序的,所以會有漏掉數(shù)據(jù)的情況,只能方法3
---方法3: 基于索引再排序
---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 WHERE id_pk > (pageNum10) ORDER BY id_pk ASC LIMIT M
---適應(yīng)場景: 適用于數(shù)據(jù)量多的情況(元組數(shù)上萬). 最好ORDER BY后的列對象是主鍵或唯一所以,使得ORDERBY操作能利用索引被消除但結(jié)果集是穩(wěn)定的(穩(wěn)定的含義,參見方法1)
---原因: 索引掃描,速度會很快. 但MySQL的排序操作,只有ASC沒有DESC(DESC是假的,未來會做真正的DESC,期待...).
---方法4: 基于索引使用prepare(第一個問號表示pageNum,第二個?表示每頁元組數(shù))**
---語句樣式: MySQL中,可用如下方法: PREPARE stmt_name FROM SELECT * FROM 表名稱 WHERE id_pk > (?* ?) ORDER BY id_pk ASC LIMIT M
---適應(yīng)場景: 大數(shù)據(jù)量
---原因: 索引掃描,速度會很快. prepare語句又比一般的查詢語句快一點。
3.ThreadGroup
當(dāng)創(chuàng)建了好幾個線程的時候,很多線程的工作任務(wù)是類似或者一致的,這樣我們就可以使用ThreadGroup來管理他們,ThreadGroup可以隨時的獲取在他里面的線程的運行狀態(tài),信息,或者一條命令關(guān)閉掉這個group里面的所有線程。
4.SpringMVC與Struts2的區(qū)別及執(zhí)行流程
Struts2是一個基于MVC設(shè)計模式的Web應(yīng)用框架,它本質(zhì)上相當(dāng)于一個servlet,在MVC設(shè)計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數(shù)據(jù)交互 Struts2=struts1+webwork。
struts2的執(zhí)行流程:
1、客戶端瀏覽器發(fā)出HTTP請求。
2、根據(jù)web.xml配置,該請求被FilterDispatcher接收。
3、根據(jù)struts.xml配置,找到需要調(diào)用的Action類和方法, 并通過IoC方式,將值注入給Aciton。
4、Action調(diào)用業(yè)務(wù)邏輯組件處理業(yè)務(wù)邏輯,這一步包含表單驗證。
5、Action執(zhí)行完畢,根據(jù)struts.xml中的配置找到對應(yīng)的返回結(jié)果result,并跳轉(zhuǎn)到相應(yīng)頁面。
6、返回HTTP響應(yīng)到客戶端瀏覽器。
springmvc全稱是spring web mvc,是spring框架一部分,是一個mvc的框架,和struts2一樣是一個表現(xiàn)層框架。
springMVC的執(zhí)行流程:
1、 用戶發(fā)送請求至前端控制器DispatcherServlet
2、 DispatcherServlet收到請求調(diào)用HandlerMapping處理器映射器查找Handler。
3、 處理器映射器根據(jù)請求url找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一并返回給DispatcherServlet。
4、 DispatcherServlet通過HandlerAdapter處理器適配器調(diào)用處理器
5、 HandlerAdapter調(diào)用處理器Handler
6、 Handler執(zhí)行完成返回ModelAndView
7、 HandlerAdapter將Handler執(zhí)行結(jié)果ModelAndView返回給DispatcherServlet
8、 DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器,ViewReslover根據(jù)邏輯視圖名解析View
9、 ViewReslover返回View
10、 DispatcherServlet對View進(jìn)行渲染視圖(即將模型數(shù)據(jù)填充至request域)。
11、 DispatcherServlet響應(yīng)用戶
Springmvc與struts2的本質(zhì)區(qū)別
1、springmvc入口是一個servlet前端控制器,struts2入口是一個filter過濾器。
2、struts2通過在action類中定義成員變量接收請求參數(shù),struts2只能使用多例模式管理action。
springmvc通過在controller方法中定義形參接收請求參數(shù),springmvc可以使用單例模式管理controller。
3、springmvc是基于方法開發(fā)的,注解開發(fā)中使用requestMapping將url和方法進(jìn)行映射,如果根據(jù)url找到controller類的方法生成一個Handler處理器對象(只包括一個method)。
struts2是基于類開發(fā),每個請求過來創(chuàng)建一個action實例,實例對象中有若干的方法。
開發(fā)中建議使用springmvc,springmvc方法更類似service業(yè)務(wù)方法。
4、Struts采用值棧存儲請求和響應(yīng)的數(shù)據(jù),通過OGNL存取數(shù)據(jù), springmvc通過參數(shù)綁定器是將request請求內(nèi)容解析,并給方法形參賦值。
5、struts2和springmvc的速度是相當(dāng)?shù)?,由于struts2的漏洞較多,很多企業(yè)轉(zhuǎn)向使用springmvc了。
5.談?wù)勀銓truts的理解。
- struts是一個按MVC模式設(shè)計的Web層框架,其實它就是一個大大的servlet,這個Servlet名為ActionServlet,或是ActionServlet的子類。我們可以在web.xml文件中將符合某種特征的所有請求交給這個Servlet處理,這個Servlet再參照一個配置文件(通常為/WEB-INF/struts-config.xml)將各個請求分別分配給不同的action去處理。
一個擴展知識點:struts的配置文件可以有多個,可以按模塊配置各自的配置文件,這樣可以防止配置文件的過度膨脹;
2.ActionServlet把請求交給action去處理之前,會將請求參數(shù)封裝成一個formbean對象(就是一個java類,這個類中的每個屬性對應(yīng)一個請求參數(shù)),封裝成一個什么樣的formbean對象呢?看配置文件。
3.要說明的是, ActionServlet把formbean對象傳遞給action的execute方法之前,可能會調(diào)用formbean的validate方法進(jìn)行校驗,只有校驗通過后才將這個formbean對象傳遞給action的execute方法,否則,它將返回一個錯誤頁面,這個錯誤頁面由input屬性指定,(看配置文件)作者為什么將這里命名為input屬性,而不是error屬性,我們后面結(jié)合實際的運行效果進(jìn)行分析。
4.action執(zhí)行完后要返回顯示的結(jié)果視圖,這個結(jié)果視圖是用一個ActionForward對象來表示的,actionforward對象通過struts-config.xml配置文件中的配置關(guān)聯(lián)到某個jsp頁面,因為程序中使用的是在struts-config.xml配置文件為jsp頁面設(shè)置的邏輯名,這樣可以實現(xiàn)action程序代碼與返回的jsp頁面名稱的解耦。
6.談?wù)勀銓ibernate的理解。
1.面向?qū)ο笤O(shè)計的軟件內(nèi)部運行過程可以理解成就是在不斷創(chuàng)建各種新對象、建立對象之間的關(guān)系,調(diào)用對象的方法來改變各個對象的狀態(tài)和對象消亡的過程,不管程序運行的過程和操作怎么樣,本質(zhì)上都是要得到一個結(jié)果,程序上一個時刻和下一個時刻的運行結(jié)果的差異就表現(xiàn)在內(nèi)存中的對象狀態(tài)發(fā)生了變化。
2.為了在關(guān)機和內(nèi)存空間不夠的狀況下,保持程序的運行狀態(tài),需要將內(nèi)存中的對象狀態(tài)保存到持久化設(shè)備和從持久化設(shè)備中恢復(fù)出對象的狀態(tài),通常都是保存到關(guān)系數(shù)據(jù)庫來保存大量對象信息。從Java程序的運行功能上來講,保存對象狀態(tài)的功能相比系統(tǒng)運行的其他功能來說,應(yīng)該是一個很不起眼的附屬功能,java采用jdbc來實現(xiàn)這個功能,這個不起眼的功能卻要編寫大量的代碼,而做的事情僅僅是保存對象和恢復(fù)對象,并且那些大量的jdbc代碼并沒有什么技術(shù)含量,基本上是采用一套例行公事的標(biāo)準(zhǔn)代碼模板來編寫,是一種苦活和重復(fù)性的工作。
3.通過數(shù)據(jù)庫保存java程序運行時產(chǎn)生的對象和恢復(fù)對象,其實就是實現(xiàn)了java對象與關(guān)系數(shù)據(jù)庫記錄的映射關(guān)系,稱為ORM(即Object Relation Mapping),人們可以通過封裝JDBC代碼來實現(xiàn)了這種功能,封裝出來的產(chǎn)品稱之為ORM框架,Hibernate就是其中的一種流行ORM框架。使用Hibernate框架,不用寫JDBC代碼,僅僅是調(diào)用一個save方法,就可以將對象保存到關(guān)系數(shù)據(jù)庫中,僅僅是調(diào)用一個get方法,就可以從數(shù)據(jù)庫中加載出一個對象。
4.使用Hibernate的基本流程是:配置Configuration對象、產(chǎn)生SessionFactory、創(chuàng)建session對象,啟動事務(wù),完成CRUD操作,提交事務(wù),關(guān)閉session。
5.使用Hibernate時,先要配置hibernate.cfg.xml文件,其中配置數(shù)據(jù)庫連接信息和方言等,還要為每個實體配置相應(yīng)的hbm.xml文件,hibernate.cfg.xml文件中需要登記每個hbm.xml文件。
6.在應(yīng)用Hibernate時,重點要了解Session的緩存原理,級聯(lián),延遲加載和hql查詢。
7.Sprig AOP
前段時間寫的java設(shè)計模式--代理模式,最近在看Spring Aop的時候,覺得于代理模式應(yīng)該有密切的聯(lián)系,于是決定了解下Spring Aop的實現(xiàn)原理。
說起AOP就不得不說下OOP了,OOP中引入封裝、繼承和多態(tài)性等概念來建立一種對象層次結(jié)構(gòu),用以模擬公共行為的一個集合。但是,如果我們需要為部分對象引入公共部分的時候,OOP就會引入大量重復(fù)的代碼。例如:日志功能。
AOP技術(shù)利用一種稱為“橫切”的技術(shù),解剖封裝的對象內(nèi)部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,這樣就能減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性。AOP把軟件系統(tǒng)分為兩個部分:核心關(guān)注點和橫切關(guān)注點。業(yè)務(wù)處理的主要流程是核心關(guān)注點,與之關(guān)系不大的部分是橫切關(guān)注點。橫切關(guān)注點的一個特點是,他們經(jīng)常發(fā)生在核心關(guān)注點的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。
實現(xiàn)AOP的技術(shù),主要分為兩大類:
一是采用動態(tài)代理技術(shù),利用截取消息的方式,對該消息進(jìn)行裝飾,以取代原有對象行為的執(zhí)行;
二是采用靜態(tài)織入的方式,引入特定的語法創(chuàng)建“方面”,從而使得編譯器可以在編譯期間織入有關(guān)“方面”的代碼。
Spring AOP 的實現(xiàn)原理其實很簡單:AOP 框架負(fù)責(zé)動態(tài)地生成 AOP 代理類,這個代理類的方法則由 Advice 和回調(diào)目標(biāo)對象的方法所組成,并將該對象可作為目標(biāo)對象使用。AOP 代理包含了目標(biāo)對象的全部方法,但 AOP 代理中的方法與目標(biāo)對象的方法存在差異,AOP 方法在特定切入點添加了增強處理,并回調(diào)了目標(biāo)對象的方法。
Spring AOP使用動態(tài)代理技術(shù)在運行期織入增強代碼。使用兩種代理機制:
基于JDK的動態(tài)代理(JDK本身只提供接口的代理);
基于CGlib的動態(tài)代理。
1)JDK的動態(tài)代理主要涉及java.lang.reflect包中的兩個類:Proxy和InvocationHandler。其中InvocationHandler只是一個接口,可以通過實現(xiàn)該接口定義橫切邏輯,并通過反射機制調(diào)用目標(biāo)類的代碼,動態(tài)的將橫切邏輯與業(yè)務(wù)邏輯織在一起。而Proxy利用InvocationHandler動態(tài)創(chuàng)建一個符合某一接口的實例,生成目標(biāo)類的代理對象。 其代理對象必須是某個接口的實現(xiàn),它是通過在運行期間創(chuàng)建一個接口的實現(xiàn)類來完成對目標(biāo)對象的代理.只能實現(xiàn)接口的類生成代理,而不能針對類
2)CGLib采用底層的字節(jié)碼技術(shù),為一個類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類的調(diào)用方法,并順勢織入橫切邏輯.它運行期間生成的代理對象是目標(biāo)類的擴展子類.所以無法通知final的方法,因為它們不能被覆寫.是針對類實現(xiàn)代理,主要是為指定的類生成一個子類,覆蓋其中方法.
在spring中默認(rèn)情況下使用JDK動態(tài)代理實現(xiàn)AOP,如果proxy-target-class設(shè)置為true或者使用了優(yōu)化策略那么會使用CGLIB來創(chuàng)建動態(tài)代理.Spring AOP在這兩種方式的實現(xiàn)上基本一樣.以JDK代理為例,會使用JdkDynamicAopProxy來創(chuàng)建代理,在invoke()方法首先需要織入到當(dāng)前類的增強器封裝到攔截器鏈中,然后遞歸的調(diào)用這些攔截器完成功能的織入.最終返回代理對象.
8.介紹一下Hibernate的二級緩存
(1)緩存就是把以前從數(shù)據(jù)庫中查詢出來和使用過的對象保存在內(nèi)存中(一個數(shù)據(jù)結(jié)構(gòu)中),這個數(shù)據(jù)結(jié)構(gòu)通常是或類似Hashmap,當(dāng)以后要使用某個對象時,先查詢緩存中是否有這個對象,如果有則使用緩存中的對象,如果沒有則去查詢數(shù)據(jù)庫,并將查詢出來的對象保存在緩存中,以便下次使用。
(2)Hibernate的Session就是一種緩存,我們通常將之稱為Hibernate的一級緩存,當(dāng)想使用session從數(shù)據(jù)庫中查詢出一個對象時,Session也是先從自己內(nèi)部查看是否存在這個對象,存在則直接返回,不存在才去訪問數(shù)據(jù)庫,并將查詢的結(jié)果保存在自己內(nèi)部。由于Session代表一次會話過程,一個Session與一個數(shù)據(jù)庫連接相關(guān)連,所以Session最好不要長時間保持打開,通常僅用于一個事務(wù)當(dāng)中,在事務(wù)結(jié)束時就應(yīng)關(guān)閉。并且Session是線程不安全的,被多個線程共享時容易出現(xiàn)問題。通常只有那種全局意義上的緩存才是真正的緩存應(yīng)用,才有較大的緩存價值,因此,Hibernate的Session這一級緩存的緩存作用并不明顯,應(yīng)用價值不大。Hibernate的二級緩存就是要為Hibernate配置一種全局緩存,讓多個線程和多個事務(wù)都可以共享這個緩存。我們希望的是一個人使用過,其他人也可以使用,session沒有這種效果。
(3)二級緩存是獨立于Hibernate的軟件部件,屬于第三方的產(chǎn)品,多個廠商和組織都提供有緩存產(chǎn)品,例如,EHCache和OSCache等等。在Hibernate中使用二級緩存,首先就要在hibernate.cfg.xml配置文件中配置使用哪個廠家的緩存產(chǎn)品,接著需要配置該緩存產(chǎn)品自己的配置文件,最后要配置Hibernate中的哪些實體對象要納入到二級緩存的管理中。明白了二級緩存原理和有了這個思路后,很容易配置起Hibernate的二級緩存。擴展知識:一個SessionFactory可以關(guān)聯(lián)一個二級緩存,也即一個二級緩存只能負(fù)責(zé)緩存一個數(shù)據(jù)庫中的數(shù)據(jù),當(dāng)使用Hibernate 的二級緩存后,注意不要有其他的應(yīng)用或SessionFactory來更改當(dāng)前數(shù)據(jù)庫中的數(shù)據(jù),這樣緩存的數(shù)據(jù)就會與數(shù)據(jù)庫中的實際數(shù)據(jù)不一致。
9.三大框架各起的作用
struts 在SSH 框架中起控制的作用 , 其核心是(控制器)Controller, 即ActionServlet,而 ActionServlet 的核心就是Struts-config.xml. 主要控制邏輯關(guān)系的處理 . hibernate 是數(shù)據(jù)持久化層 , 是一種新的對象、關(guān)系的映射工具 , 提供了從 Java 類到數(shù)據(jù)表的映射,也提供了數(shù)據(jù)查詢和恢復(fù)等機制 , 大大減少數(shù)據(jù)訪問的復(fù)雜度。把對數(shù)據(jù)庫的直接操作 , 轉(zhuǎn)換為對持久對象的操作。
spring 是一個輕量級的控制反轉(zhuǎn) (IoC) 和面向切面 (AOP) 的容器框架, 面向接口的編程 , 由容器控制程序之間的(依賴)關(guān)系,而非傳統(tǒng)實現(xiàn)中,由程序代碼直接操控。這也就是所謂“ 控制反轉(zhuǎn)” 的概念所在:(依賴)控制權(quán)由應(yīng)用代碼中轉(zhuǎn)到了外部容器,控制權(quán)的轉(zhuǎn)移,是所謂反轉(zhuǎn)。依賴注入,即組件之間的依賴關(guān)系由容器在運行期決定,形象的來說,即由容器動態(tài)的將某種依賴關(guān)系注入到組件之中 起到的主要作用是解耦。
10.spring核心:aop和ioc的解釋?隔離范圍? 3種注入方法?
(1)aop:Spring提供了對AOP技術(shù)的良好封裝, AOP稱為面向切面編程,就是系統(tǒng)中有很多各不相干的類的方法,在這些眾多方法中要加入某種系統(tǒng)功能的代碼;例如,加入日志,加入權(quán)限判斷,加入異常處理,這種應(yīng)用稱為AOP。實現(xiàn)AOP功能采用的是代理技術(shù),客戶端程序不再調(diào)用目標(biāo),而調(diào)用代理類,代理類與目標(biāo)類對外具有相同的方法聲明,有兩種方式可以實現(xiàn)相同的方法聲明,一是實現(xiàn)相同的接口,二是作為目標(biāo)的子類在,JDK中采用Proxy類產(chǎn)生動態(tài)代理的方式為某個接口生成實現(xiàn)類,spring提供了這種支持,只需要在spring配置文件中配置這兩個元素即可實現(xiàn)代理和aop功能;
(2)Ioc:Spring提供了對IOC良好支持,IOC是一種編程思想,是一種架構(gòu)藝術(shù),利用這種思想可以很好地實現(xiàn)模塊之間的解耦。IOC也稱為DI(Depency Injection);IOC可以理解為‘面向接口編程思想’的一種實現(xiàn)方法,通過IOC實現(xiàn)了強制的‘面向接口編程’。
(3)隔離范圍:Spring支持JDBC規(guī)范定義的四種隔離級別
Default默認(rèn)的事務(wù)隔離級別
READ_UNCOMMITTED讀未提交,一個事務(wù)可以操作另外一個未提交的事務(wù),不能避免臟讀,不可重復(fù)讀,幻讀,隔離級別最低,并發(fā)性 能最高
READ_COMMITTED讀已提交,一個事務(wù)不可以操作另外一個未提交的事務(wù), 能防止臟讀,不能避免不可重復(fù)讀,幻讀。
repeatable_read能夠避免臟讀,不可重復(fù)讀,不能避免幻讀
SERIALIZABLE隔離級別最高,消耗資源最低,代價最高,能夠防止臟讀, 不可重復(fù)讀,幻讀。
(4)Spring的注入和IoC反轉(zhuǎn)控制是一回事;關(guān)于getter和setter方式的注入;
Autowire=”defualt”;autowire=”byName”;autowire=”byType”;
11.Spring Bean的作用域之間有什么區(qū)別?
Spring容器中的bean可以分為5個范圍。所有范圍的名稱都是自說明的,但是為了避免混淆,還是讓我們來解釋一下:
singleton:這種bean范圍是默認(rèn)的,這種范圍確保不管接受到多少個請求,每個容器中只有一個bean的實例,單例的模式由bean factory自身來維護(hù)。
prototype:原形范圍與單例范圍相反,為每一個bean請求提供一個實例。
request:在請求bean范圍內(nèi)會每一個來自客戶端的網(wǎng)絡(luò)請求創(chuàng)建一個實例,在請求完成以后,bean會失效并被垃圾回收器回收。
Session:與請求范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效。
global-session:global-session和Portlet應(yīng)用相關(guān)。當(dāng)你的應(yīng)用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那么這全局變量需要存儲在global-session中。
12.大型網(wǎng)站在架構(gòu)上應(yīng)當(dāng)考慮哪些問題?
1.分層:分層是處理任何復(fù)雜系統(tǒng)最常見的手段之一,將系統(tǒng)橫向切分成若干個層面,每個層面只承擔(dān)單一的職責(zé),然后通過下層為上層提供的基礎(chǔ)設(shè)施和服務(wù)以及上層對下層的調(diào)用來形成一個完整的復(fù)雜的系統(tǒng)。計算機網(wǎng)絡(luò)的開放系統(tǒng)互聯(lián)參考模型(OSI/RM)和Internet的TCP/IP模型都是分層結(jié)構(gòu),大型網(wǎng)站的軟件系統(tǒng)也可以使用分層的理念將其分為持久層(提供數(shù)據(jù)存儲和訪問服務(wù))、業(yè)務(wù)層(處理業(yè)務(wù)邏輯,系統(tǒng)中最核心的部分)和表示層(系統(tǒng)交互、視圖展示)。需要指出的是:(1)分層是邏輯上的劃分,在物理上可以位于同一設(shè)備上也可以在不同的設(shè)備上部署不同的功能模塊,這樣可以使用更多的計算資源來應(yīng)對用戶的并發(fā)訪問;(2)層與層之間應(yīng)當(dāng)有清晰的邊界,這樣分層才有意義,才更利于軟件的開發(fā)和維護(hù)。
2.分割:分割是對軟件的縱向切分。我們可以將大型網(wǎng)站的不同功能和服務(wù)分割開,形成高內(nèi)聚低耦合的功能模塊(單元)。在設(shè)計初期可以做一個粗粒度的分割,將網(wǎng)站分割為若干個功能模塊,后期還可以進(jìn)一步對每個模塊進(jìn)行細(xì)粒度的分割,這樣一方面有助于軟件的開發(fā)和維護(hù),另一方面有助于分布式的部署,提供網(wǎng)站的并發(fā)處理能力和功能的擴展。
3.分布式:除了上面提到的內(nèi)容,網(wǎng)站的靜態(tài)資源(JavaScript、CSS、圖片等)也可以采用獨立分布式部署并采用獨立的域名,這樣可以減輕應(yīng)用服務(wù)器的負(fù)載壓力,也使得瀏覽器對資源的加載更快。數(shù)據(jù)的存取也應(yīng)該是分布式的,傳統(tǒng)的商業(yè)級關(guān)系型數(shù)據(jù)庫產(chǎn)品基本上都支持分布式部署,而新生的NoSQL產(chǎn)品幾乎都是分布式的。當(dāng)然,網(wǎng)站后臺的業(yè)務(wù)處理也要使用分布式技術(shù),例如查詢索引的構(gòu)建、數(shù)據(jù)分析等,這些業(yè)務(wù)計算規(guī)模龐大,可以使用Hadoop以及MapReduce分布式計算框架來處理。
4.集群:集群使得有更多的服務(wù)器提供相同的服務(wù),可以更好的提供對并發(fā)的支持。
5.緩存:所謂緩存就是用空間換取時間的技術(shù),將數(shù)據(jù)盡可能放在距離計算最近的位置。使用緩存是網(wǎng)站優(yōu)化的第一定律。我們通常說的CDN、反向代理、熱點數(shù)據(jù)都是對緩存技術(shù)的使用。
6.異步:異步是實現(xiàn)軟件實體之間解耦合的又一重要手段。異步架構(gòu)是典型的生產(chǎn)者消費者模式,二者之間沒有直接的調(diào)用關(guān)系,只要保持?jǐn)?shù)據(jù)結(jié)構(gòu)不變,彼此功能實現(xiàn)可以隨意變化而不互相影響,這對網(wǎng)站的擴展非常有利。使用異步處理還可以提高系統(tǒng)可用性,加快網(wǎng)站的響應(yīng)速度(用Ajax加載數(shù)據(jù)就是一種異步技術(shù)),同時還可以起到削峰作用(應(yīng)對瞬時高并發(fā))。";能推遲處理的都要推遲處理"是網(wǎng)站優(yōu)化的第二定律,而異步是踐行網(wǎng)站優(yōu)化第二定律的重要手段。
7.冗余:各種服務(wù)器都要提供相應(yīng)的冗余服務(wù)器以便在某臺或某些服務(wù)器宕機時還能保證網(wǎng)站可以正常工作,同時也提供了災(zāi)難恢復(fù)的可能性。冗余是網(wǎng)站高可用性的重要保證。
13.你用過的網(wǎng)站前端優(yōu)化的技術(shù)有哪些?
①瀏覽器訪問優(yōu)化:
- 減少HTTP請求數(shù)量:合并CSS、合并javascript、合并圖片(CSS Sprite)
- 使用瀏覽器緩存:通過設(shè)置HTTP響應(yīng)頭中的Cache-Control和Expires屬性,將CSS、JavaScript、圖片等在瀏覽器中緩存,當(dāng)這些靜態(tài)資源需要更新時,可以更新HTML文件中的引用來讓瀏覽器重新請求新的資源
- 啟用壓縮
- CSS前置,JavaScript后置 -減少Cookie傳輸
② CDN加速:CDN(ContentDistribute Network)的本質(zhì)仍然是緩存,將數(shù)據(jù)緩存在離用戶最近的地方,CDN通常部署在網(wǎng)絡(luò)運營商的機房,不僅可以提升響應(yīng)速度,還可以減少應(yīng)用服務(wù)器的壓力。當(dāng)然,CDN緩存的通常都是靜態(tài)資源。
③反向代理:反向代理相當(dāng)于應(yīng)用服務(wù)器的一個門面,可以保護(hù)網(wǎng)站的安全性,也可以實現(xiàn)負(fù)載均衡的功能,當(dāng)然最重要的是它緩存了用戶訪問的熱點資源,可以直接從反向代理將某些內(nèi)容返回給用戶瀏覽器。
14.你使用過的應(yīng)用服務(wù)器優(yōu)化技術(shù)有哪些?
①分布式緩存:緩存的本質(zhì)就是內(nèi)存中的哈希表,如果設(shè)計一個優(yōu)質(zhì)的哈希函數(shù),那么理論上哈希表讀寫的漸近時間復(fù)雜度為O(1)。緩存主要用來存放那些讀寫比很高、變化很少的數(shù)據(jù),這樣應(yīng)用程序讀取數(shù)據(jù)時先到緩存中讀取,如果沒有或者數(shù)據(jù)已經(jīng)失效再去訪問數(shù)據(jù)庫或文件系統(tǒng),并根據(jù)擬定的規(guī)則將數(shù)據(jù)寫入緩存。對網(wǎng)站數(shù)據(jù)的訪問也符合二八定律(Pareto分布,冪律分布),即80%的訪問都集中在20%的數(shù)據(jù)上,如果能夠?qū)⑦@20%的數(shù)據(jù)緩存起來,那么系統(tǒng)的性能將得到顯著的改善。當(dāng)然,使用緩存需要解決以下幾個問題:
- 頻繁修改的數(shù)據(jù);
- 數(shù)據(jù)不一致與臟讀;
- 緩存雪崩(可以采用分布式緩存服務(wù)器集群加以解決,memcached是廣泛采用的解決方案);
- 緩存預(yù)熱;
- 緩存穿透(惡意持續(xù)請求不存在的數(shù)據(jù))。
②異步操作:可以使用消息隊列將調(diào)用異步化,通過異步處理將短時間高并發(fā)產(chǎn)生的事件消息存儲在消息隊列中,從而起到削峰作用。電商網(wǎng)站在進(jìn)行促銷活動時,可以將用戶的訂單請求存入消息隊列,這樣可以抵御大量的并發(fā)訂單請求對系統(tǒng)和數(shù)據(jù)庫的沖擊。目前,絕大多數(shù)的電商網(wǎng)站即便不進(jìn)行促銷活動,訂單系統(tǒng)都采用了消息隊列來處理。
③使用集群。
④代碼優(yōu)化:
-多線程:基于Java的Web開發(fā)基本上都通過多線程的方式響應(yīng)用戶的并發(fā)請求,使用多線程技術(shù)在編程上要解決線程安全問題,主要可以考慮以下幾個方面:A. 將對象設(shè)計為無狀態(tài)對象(這和面向?qū)ο蟮木幊逃^點是矛盾的,在面向?qū)ο蟮氖澜缰斜灰暈椴涣荚O(shè)計),這樣就不會存在并發(fā)訪問時對象狀態(tài)不一致的問題。B. 在方法內(nèi)部創(chuàng)建對象,這樣對象由進(jìn)入方法的線程創(chuàng)建,不會出現(xiàn)多個線程訪問同一對象的問題。使用ThreadLocal將對象與線程綁定也是很好的做法,這一點在前面已經(jīng)探討過了。C. 對資源進(jìn)行并發(fā)訪問時應(yīng)當(dāng)使用合理的鎖機制。 - 非阻塞I/O:使用單線程和非阻塞I/O是目前公認(rèn)的比多線程的方式更能充分發(fā)揮服務(wù)器性能的應(yīng)用模式,基于Node.js構(gòu)建的服務(wù)器就采用了這樣的方式。Java在JDK 1.4中就引入了NIO(Non-blockingI/O),在Servlet3規(guī)范中又引入了異步Servlet的概念,這些都為在服務(wù)器端采用非阻塞I/O提供了必要的基礎(chǔ)。
- 資源復(fù)用:資源復(fù)用主要有兩種方式,一是單例,二是對象池,我們使用的數(shù)據(jù)庫連接池、線程池都是對象池化技術(shù),這是典型的用空間換取時間的策略,另一方面也實現(xiàn)對資源的復(fù)用,從而避免了不必要的創(chuàng)建和釋放資源所帶來的開銷。
15.Hibernate與Mybatis比較
第一方面:開發(fā)速度的對比
就開發(fā)速度而言,Hibernate的真正掌握要比Mybatis來得難些。Mybatis框架相對簡單很容易上手,但也相對簡陋些。個人覺得要用好Mybatis還是首先要先理解好Hibernate。
比起兩者的開發(fā)速度,不僅僅要考慮到兩者的特性及性能,更要根據(jù)項目需求去考慮究竟哪一個更適合項目開發(fā),比如:一個項目中用到的復(fù)雜查詢基本沒有,就是簡單的增刪改查,這樣選擇hibernate效率就很快了,因為基本的sql語句已經(jīng)被封裝好了,根本不需要你去寫sql語句,這就節(jié)省了大量的時間,但是對于一個大型項目,復(fù)雜語句較多,這樣再去選擇hibernate就不是一個太好的選擇,選擇mybatis就會加快許多,而且語句的管理也比較方便。
第二方面:開發(fā)工作量的對比
Hibernate和MyBatis都有相應(yīng)的代碼生成工具??梢陨珊唵位镜腄AO層方法。針對高級查詢,Mybatis需要手動編寫SQL語句,以及ResultMap。而Hibernate有良好的映射機制,開發(fā)者無需關(guān)心SQL的生成與結(jié)果映射,可以更專注于業(yè)務(wù)流程。
第三方面:sql優(yōu)化方面
Hibernate的查詢會將表中的所有字段查詢出來,這一點會有性能消耗。Hibernate也可以自己寫SQL來指定需要查詢的字段,但這樣就破壞了Hibernate開發(fā)的簡潔性。而Mybatis的SQL是手動編寫的,所以可以按需求指定查詢的字段。
Hibernate HQL語句的調(diào)優(yōu)需要將SQL打印出來,而Hibernate的SQL被很多人嫌棄因為太丑了。MyBatis的SQL是自己手動寫的所以調(diào)整方便。但Hibernate具有自己的日志統(tǒng)計。Mybatis本身不帶日志統(tǒng)計,使用Log4j進(jìn)行日志記錄。
第四方面:對象管理的對比
Hibernate 是完整的對象/關(guān)系映射解決方案,它提供了對象狀態(tài)管理(state management)的功能,使開發(fā)者不再需要理會底層數(shù)據(jù)庫系統(tǒng)的細(xì)節(jié)。也就是說,相對于常見的 JDBC/SQL 持久層方案中需要管理 SQL 語句,Hibernate采用了更自然的面向?qū)ο蟮囊暯莵沓志没?Java 應(yīng)用中的數(shù)據(jù)。
換句話說,使用 Hibernate 的開發(fā)者應(yīng)該總是關(guān)注對象的狀態(tài)(state),不必考慮 SQL 語句的執(zhí)行。這部分細(xì)節(jié)已經(jīng)由 Hibernate 掌管妥當(dāng),只有開發(fā)者在進(jìn)行系統(tǒng)性能調(diào)優(yōu)的時候才需要進(jìn)行了解。而MyBatis在這一塊沒有文檔說明,用戶需要對對象自己進(jìn)行詳細(xì)的管理。
第五方面:緩存機制
Hibernate緩存
Hibernate一級緩存是Session緩存,利用好一級緩存就需要對Session的生命周期進(jìn)行管理好。建議在一個Action操作中使用一個Session。一級緩存需要對Session進(jìn)行嚴(yán)格管理。
Hibernate二級緩存是SessionFactory級的緩存。 SessionFactory的緩存分為內(nèi)置緩存和外置緩存。內(nèi)置緩存中存放的是SessionFactory對象的一些集合屬性包含的數(shù)據(jù)(映射元素?fù)?jù)及預(yù)定SQL語句等),對于應(yīng)用程序來說,它是只讀的。外置緩存中存放的是數(shù)據(jù)庫數(shù)據(jù)的副本,其作用和一級緩存類似.二級緩存除了以內(nèi)存作為存儲介質(zhì)外,還可以選用硬盤等外部存儲設(shè)備。二級緩存稱為進(jìn)程級緩存或SessionFactory級緩存,它可以被所有session共享,它的生命周期伴隨著SessionFactory的生命周期存在和消亡。
MyBatis緩存
MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3 中的緩存實現(xiàn)的很多改進(jìn)都已經(jīng)實現(xiàn)了,使得它更加強大而且易于配置。
默認(rèn)情況下是沒有開啟緩存的,除了局部的 session 緩存,可以增強變現(xiàn)而且處理循環(huán) 依賴也是必須的。要開啟二級緩存,你需要在你的 SQL 映射文件中添加一行: <cache/>
字面上看就是這樣。這個簡單語句的效果如下:
- 映射語句文件中的所有 select 語句將會被緩存。
- 映射語句文件中的所有 insert,update 和 delete 語句會刷新緩存。
- 緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
- 根據(jù)時間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會以任何時間順序 來刷新。
- 緩存會存儲列表集合或?qū)ο?無論查詢方法返回什么)的 1024 個引用。
- 緩存會被視為是 read/write(可讀/可寫)的緩存,意味著對象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。
所有的這些屬性都可以通過緩存元素的屬性來修改。
比如: <cache eviction=”FIFO” flushInterval=”60000″ size=”512″ readOnly=”true”/>
這個更高級的配置創(chuàng)建了一個 FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對象或列表的 512 個引用,而且返回的對象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會 導(dǎo)致沖突??捎玫氖栈夭呗杂? 默認(rèn)的是 LRU:
- LRU – 最近最少使用的:移除最長時間不被使用的對象。
- FIFO – 先進(jìn)先出:按對象進(jìn)入緩存的順序來移除它們。
- SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象。
- WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象。
flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個合理的毫秒 形式的時間段。默認(rèn)情況是不設(shè)置,也就是沒有刷新間隔,緩存僅僅調(diào)用語句時刷新。
size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對象數(shù)目和你運行環(huán)境的 可用內(nèi)存資源數(shù)目。默認(rèn)值是1024。
readOnly(只讀)屬性可以被設(shè)置為 true 或 false。只讀的緩存會給所有調(diào)用者返回緩 存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優(yōu)勢。可讀寫的緩存 會返回緩存對象的拷貝(通過序列化) 。這會慢一些,但是安全,因此默認(rèn)是 false。
相同點:Hibernate和Mybatis的二級緩存除了采用系統(tǒng)默認(rèn)的緩存機制外,都可以通過實現(xiàn)你自己的緩存或為其他第三方緩存方案,創(chuàng)建適配器來完全覆蓋緩存行為。
不同點:Hibernate的二級緩存配置在SessionFactory生成的配置文件中進(jìn)行詳細(xì)配置,然后再在具體的表-對象映射中配置是那種緩存。
MyBatis的二級緩存配置都是在每個具體的表-對象映射中進(jìn)行詳細(xì)配置,這樣針對不同的表可以自定義不同的緩存機制。并且Mybatis可以在命名空間中共享相同的緩存配置和實例,通過Cache-ref來實現(xiàn)。
兩者比較:因為Hibernate對查詢對象有著良好的管理機制,用戶無需關(guān)心SQL。所以在使用二級緩存時如果出現(xiàn)臟數(shù)據(jù),系統(tǒng)會報出錯誤并提示。
而MyBatis在這一方面,使用二級緩存時需要特別小心。如果不能完全確定數(shù)據(jù)更新操作的波及范圍,避免Cache的盲目使用。否則,臟數(shù)據(jù)的出現(xiàn)會給系統(tǒng)的正常運行帶來很大的隱患。
第六方面:總結(jié)
對于總結(jié),大家可以到各大java論壇去看一看
相同點:Hibernate與MyBatis都可以是通過SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session來開啟執(zhí)行事務(wù)和SQL語句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
- Hibernate和MyBatis都支持JDBC和JTA事務(wù)處理。
Mybatis優(yōu)勢
- MyBatis可以進(jìn)行更為細(xì)致的SQL優(yōu)化,可以減少查詢字段。
- MyBatis容易掌握,而Hibernate門檻較高。
Hibernate優(yōu)勢
- Hibernate的DAO層開發(fā)比MyBatis簡單,Mybatis需要維護(hù)SQL和結(jié)果映射。
- Hibernate對對象的維護(hù)和緩存要比MyBatis好,對增刪改查的對象的維護(hù)要方便。
- Hibernate數(shù)據(jù)庫移植性很好,MyBatis的數(shù)據(jù)庫移植性不好,不同的數(shù)據(jù)庫需要寫不同SQL。
- Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。
他人總結(jié)
- Hibernate功能強大,數(shù)據(jù)庫無關(guān)性好,O/R映射能力強,如果你對Hibernate相當(dāng)精通,而且對Hibernate進(jìn)行了適當(dāng)?shù)姆庋b,那么你的項目整個持久層代碼會相當(dāng)簡單,需要寫的代碼很少,開發(fā)速度很快,非常爽。
- Hibernate的缺點就是學(xué)習(xí)門檻不低,要精通門檻更高,而且怎么設(shè)計O/R映射,在性能和對象模型之間如何權(quán)衡取得平衡,以及怎樣用好Hibernate方面需要你的經(jīng)驗和能力都很強才行。
- iBATIS入門簡單,即學(xué)即用,提供了數(shù)據(jù)庫查詢的自動對象綁定功能,而且延續(xù)了很好的SQL使用經(jīng)驗,對于沒有那么高的對象模型要求的項目來說,相當(dāng)完美。
- iBATIS的缺點就是框架還是比較簡陋,功能尚有缺失,雖然簡化了數(shù)據(jù)綁定代碼,但是整個底層數(shù)據(jù)庫查詢實際還是要自己寫的,工作量也比較大,而且不太容易適應(yīng)快速數(shù)據(jù)庫修改。
16.filter與servlet的比較
一、概念:
1、servlet:servlet是一種運行服務(wù)器端的java應(yīng)用程序,具有獨立于平臺和協(xié)議的特性,并且可以動態(tài)的生成web頁面,它工作在客戶端請求與服務(wù)器響應(yīng)的中間層。
2、filter:filter是一個可以復(fù)用的代碼片段,可以用來轉(zhuǎn)換HTTP請求、響應(yīng)和頭信息。Filter不像Servlet,它不能產(chǎn)生一個請求或者響應(yīng),它只是修改對某一資源的請求,或者修改從某一的響應(yīng)。
二、生命周期:
1、servlet:servlet的生命周期始于它被裝入web服務(wù)器的內(nèi)存時,并在web服務(wù)器終止或重新裝入servlet時結(jié)束。servlet一旦被裝入web服務(wù)器,一般不會從web服務(wù)器內(nèi)存中刪除,直至web服務(wù)器關(guān)閉或重新結(jié)束。
(1)、裝入:啟動服務(wù)器時加載Servlet的實例;
(2)、初始化:web服務(wù)器啟動時或web服務(wù)器接收到請求時,或者兩者之間的某個時刻啟動。初始化工作有init()方法負(fù)責(zé)執(zhí)行完成;
(3)、調(diào)用:從第一次到以后的多次訪問,都是只調(diào)用doGet()或doPost()方法;
(4)、銷毀:停止服務(wù)器時調(diào)用destroy()方法,銷毀實例。
2、filter:(一定要實現(xiàn)javax.servlet包的Filter接口的三個方法init()、doFilter()、destroy(),空實現(xiàn)也行)
(1)、啟動服務(wù)器時加載過濾器的實例,并調(diào)用init()方法來初始化實例;
(2)、每一次請求時都只調(diào)用方法doFilter()進(jìn)行處理;
(3)、停止服務(wù)器時調(diào)用destroy()方法,銷毀實例。
三、職責(zé)
1、servlet
創(chuàng)建并返回一個包含基于客戶請求性質(zhì)的動態(tài)內(nèi)容的完整的html頁面;
創(chuàng)建可嵌入到現(xiàn)有的html頁面中的一部分html頁面(html片段);
讀取客戶端發(fā)來的隱藏數(shù)據(jù);
讀取客戶端發(fā)來的顯示數(shù)據(jù);
與其他服務(wù)器資源(包括數(shù)據(jù)庫和java的應(yīng)用程序)進(jìn)行通信;
通過狀態(tài)代碼和響應(yīng)頭向客戶端發(fā)送隱藏數(shù)據(jù)。
2、filter:
filter能夠在一個請求到達(dá)servlet之前預(yù)處理用戶請求,也可以在離開servlet時處理http響應(yīng):
在執(zhí)行servlet之前,首先執(zhí)行filter程序,并為之做一些預(yù)處理工作;
根據(jù)程序需要修改請求和響應(yīng);
在servlet被調(diào)用之后截獲servlet的執(zhí)行
四、區(qū)別:
1、servlet 流程是短的,url傳來之后,就對其進(jìn)行處理,之后返回或轉(zhuǎn)向到某一自己指定的頁面。它主要用來在 業(yè)務(wù)處理之前進(jìn)行控制.
2、filter 流程是線性的, url傳來之后,檢查之后,可保持原來的流程繼續(xù)向下執(zhí)行,被下一個filter, servlet接收等,而servlet 處理之后,不會繼續(xù)向下傳遞。filter功能可用來保持流程繼續(xù)按照原來的方式進(jìn)行下去,或者主導(dǎo)流程,而servlet的功能主要用來主導(dǎo)流程。
filter可用來進(jìn)行字符編碼的過濾,檢測用戶是否登陸的過濾,禁止頁面緩存等
17.攔截器和過濾器的區(qū)別
①攔截器是基于java的反射機制的,而過濾器是基于函數(shù)回調(diào)。
②攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
③攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
④攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。
⑤在action的生命周期中,攔截器可以多次被調(diào)用,而過濾器只能在容器初始化時被調(diào)用一次。
⑥攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器里注入一個service,可以調(diào)用業(yè)務(wù)邏輯。
Spring的攔截器與Servlet的Filter有相似之處,比如二者都是AOP編程思想的體現(xiàn),都能實現(xiàn)權(quán)限檢查、日志記錄等。
不同的是:
使用范圍不同:Filter是Servlet規(guī)范規(guī)定的,只能用于Web程序中。而攔截器既可以用于Web程序,也可以用于Application、Swing程序中。
規(guī)范不同:Filter是在Servlet規(guī)范中定義的,是Servlet容器支持的。而攔截器是在Spring容器內(nèi)的,是Spring框架支持的。
使用的資源不同:同其他的代碼塊一樣,攔截器也是一個Spring的組件,歸Spring管理,配置在Spring文件中,因此能使用Spring里的任何資源、對象,例如Service對象、數(shù)據(jù)源、事務(wù)管理等,通過IoC注入到攔截器即可;而Filter則不能。
深度不同:Filter在只在Servlet前后起作用。而攔截器能夠深入到方法前后、異常拋出前后等,因此攔截器的使用具有更大的彈性。所以在Spring構(gòu)架的程序中,要優(yōu)先使用攔截器。
實際上Filter和Servlet極其相似,區(qū)別只是Filter不能直接對用戶生成響應(yīng)。實際上Filter里doFilter()方法里的代碼就是從多個Servlet的service()方法里抽取的通用代碼,通過使用Filter可以實現(xiàn)更好的復(fù)用。
filter是一個可以復(fù)用的代碼片段,可以用來轉(zhuǎn)換HTTP請求、響應(yīng)和頭信息。Filter不像Servlet,它不能產(chǎn)生一個請求或者響 應(yīng),它只是修改對某一資源的請求,或者修改從某一的響應(yīng)。
18.數(shù)據(jù)庫設(shè)計6個注意點+2點總結(jié)
1、主鍵與外鍵
一般而言,一個實體不能既無主鍵又無外鍵。沒有主鍵就沒有實體。
2、區(qū)別對待不同的表
基本表與統(tǒng)計表、中間表、臨時表等不同,有以下特性
a、原始性?;颈碇械挠涗浭窃紨?shù)據(jù)(基礎(chǔ)數(shù)據(jù))的記錄。
b、演繹性。由基本按照一定的業(yè)務(wù)原則可以生成統(tǒng)計表和臨時表的數(shù)據(jù)。
c、穩(wěn)定性?;颈淼慕Y(jié)構(gòu)是相對穩(wěn)定的,表中的記錄是要長期保存的。
所以在設(shè)計數(shù)據(jù)庫的時候,要盡量將基本表和其它中間表、統(tǒng)計表區(qū)別開來。應(yīng)盡量滿足第三范式。其它表可以適當(dāng)?shù)慕档头妒?。但是不管怎樣,滿足第三范式的數(shù)據(jù)庫設(shè)計,往往不是最好的設(shè)計。為了提高數(shù)據(jù)庫的運行效率,常常需要降低范式標(biāo)準(zhǔn):適當(dāng)增加冗余,達(dá)到以空間換時間的目的。
3、范式理解和冗余的分類
第一范式:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解;
第二范式:2NF是對記錄的惟一性約束,要求記錄有惟一標(biāo)識,即實體的惟一性;
第三范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余。
有時為了提高運行效率,就必須降低范式標(biāo)準(zhǔn),適當(dāng)保留冗余數(shù)據(jù)。具體做法是:在概念數(shù)據(jù)模型設(shè)計時遵守第三范式,降低范式標(biāo)準(zhǔn)的工作放到物理數(shù)據(jù)模型設(shè)計時考慮。降低范式就是增加字段,允許冗余。
但是冗余是有區(qū)別的,主鍵與外鍵在多表中的重復(fù)出現(xiàn), 不屬于數(shù)據(jù)冗余,這個概念必須清楚,事實上有許多人還不清楚。
a、非鍵字段的重復(fù)出現(xiàn), 才是數(shù)據(jù)冗余!而且是一種低級冗余,即重復(fù)性的冗余。
b、高級冗余不是字段的重復(fù)出現(xiàn),而是字段的派生出現(xiàn)。
〖例4〗:商品中的“單價、數(shù)量、金額”三個字段,“金額”就是由“單價”乘以“數(shù)量”派生出來的,它就是冗余,而且是一種高級冗余。冗余的目的是為了提高處理速度。只有低級冗余才會增加數(shù)據(jù)的不一致性,因為同一數(shù)據(jù),可能從不同時間、地點、角色上多次錄入。因此,我們提倡高級冗余(派生性冗余),反對低級冗余(重復(fù)性冗余)。
反規(guī)范設(shè)計的數(shù)據(jù)需要額外的工作來維護(hù)數(shù)據(jù)的完整性,一般可以通過以下幾種方式進(jìn)行
a、應(yīng)用邏輯
在應(yīng)用程序的事務(wù)中對同一數(shù)據(jù)的多處存儲進(jìn)行維護(hù)。這種方式比較難于管理,一個維護(hù)邏輯很容易出現(xiàn)在多個應(yīng)用程序當(dāng)中,容易遺漏。
b、批處理維護(hù)
由批處理程序批量的處理所有的非規(guī)范化關(guān)系涉及的數(shù)據(jù)。一般定期運行,運行間隔根據(jù)業(yè)務(wù)來決定,并且可以利用Job來自動運行批處理程序??捎糜趯θ哂鄶?shù)據(jù)的實時性要求不高或者有一定規(guī)則的環(huán)境。
c、觸發(fā)器
在數(shù)據(jù)庫端建立觸發(fā)器,對原數(shù)據(jù)的修改會立即觸發(fā)對冗余列的修改??捎糜趯?shù)據(jù)實時性要求較高的環(huán)境,但同時會降低數(shù)據(jù)的插入和更新速度。
4、重視視圖、物化視圖技術(shù)在數(shù)據(jù)庫的使用
a、簡化查詢
b、隱藏數(shù)據(jù)庫結(jié)構(gòu),權(quán)限管理,安全
c、物化視圖進(jìn)行數(shù)據(jù)預(yù)準(zhǔn)備,性能
5、數(shù)據(jù)完整性
盡量在表級約束條件(5個=2列級+2表級+1表間)實現(xiàn),實現(xiàn)不了的復(fù)雜業(yè)務(wù)約束再進(jìn)行觸發(fā)器和存儲過程實現(xiàn)。
6、要善于識別與正確處理多對多的關(guān)系
若兩個實體之間存在多對多的關(guān)系,則應(yīng)消除這種關(guān)系。消除的辦法是,在兩者之間增加第三個實體。這樣,原來一個多對多的關(guān)系,現(xiàn)在變?yōu)閮蓚€一對多的關(guān)系。要將原來兩個實體的屬性合理地分配到三個實體中去。這里的第三個實體,實質(zhì)上是一個較復(fù)雜的關(guān)系,它對應(yīng)一張基本表。一般來講,數(shù)據(jù)庫設(shè)計工具不能識別多對多的關(guān)系,但能處理多對多的關(guān)系。
〖例3〗:在“圖書館信息系統(tǒng)”中,“圖書”是一個實體,“讀者”也是一個實體。這兩個實體之間的關(guān)系,是一個典型的多對多關(guān)系:一本圖書在不同時間可以被多個讀者借閱,一個讀者又可以借多本圖書。為此,要在二者之間增加第三個實體,該實體取名為“借還書”,它的屬性為:借還時間、借還標(biāo)志(0表示借書,1表示還書),另外,它還應(yīng)該有兩個外鍵(“圖書”的主鍵,“讀者”的主鍵),使它能與“圖書”和“讀者”連接。
===================================================================================
1、 防止數(shù)據(jù)庫設(shè)計打補丁的方法是“三少原則”
(1) 一個數(shù)據(jù)庫中表的個數(shù)越少越好。只有表的個數(shù)少了,才能說明系統(tǒng)的E--R圖少而精,去掉了重復(fù)的多余的實體,形成了對客觀世界的高度抽象,進(jìn)行了系統(tǒng)的數(shù)據(jù)集成,防止了打補丁式的設(shè)計;
(2) 一個表中組合主鍵的字段個數(shù)越少越好。因為主鍵的作用,一是建主鍵索引,二是做為子表的外鍵,所以組合主鍵的字段個數(shù)少了,不僅節(jié)省了運行時間,而且節(jié)省了索引存儲空間;
(3) 一個表中的字段個數(shù)越少越好。只有字段的個數(shù)少了,才能說明在系統(tǒng)中不存在數(shù)據(jù)重復(fù),且很少有數(shù)據(jù)冗余,更重要的是督促讀者學(xué)會“列變行”,這樣就防止了將子表中的字段拉入到主表中去,在主表中留下許多空余的字段。所謂“列變行”,就是將主表中的一部分內(nèi)容拉出去,另外單獨建一個子表。這個方法很簡單,有的人就是不習(xí)慣、不采納、不執(zhí)行。
數(shù)據(jù)庫設(shè)計的實用原則是:在數(shù)據(jù)冗余和處理速度之間找到合適的平衡點。“三少”是一個整體概念,綜合觀點,不能孤立某一個原則。該原則是相對的,不是絕對的?!叭唷痹瓌t肯定是錯誤的。試想:若覆蓋系統(tǒng)同樣的功能,一百個實體(共一千個屬性) 的E--R圖,肯定比二百個實體(共二千個屬性) 的E--R圖,要好得多。
提倡“三少”原則,是叫讀者學(xué)會利用數(shù)據(jù)庫設(shè)計技術(shù)進(jìn)行系統(tǒng)的數(shù)據(jù)集成。數(shù)據(jù)集成的步驟是將文件系統(tǒng)集成為應(yīng)用數(shù)據(jù)庫,將應(yīng)用數(shù)據(jù)庫集成為主題數(shù)據(jù)庫,將主題數(shù)據(jù)庫集成為全局綜合數(shù)據(jù)庫。集成的程度越高,數(shù)據(jù)共享性就越強,信息孤島現(xiàn)象就越少,整個企業(yè)信息系統(tǒng)的全局E—R圖中實體的個數(shù)、主鍵的個數(shù)、屬性的個數(shù)就會越少。
提倡“三少”原則的目的,是防止讀者利用打補丁技術(shù),不斷地對數(shù)據(jù)庫進(jìn)行增刪改,使企業(yè)數(shù)據(jù)庫變成了隨意設(shè)計數(shù)據(jù)庫表的“垃圾堆”,或數(shù)據(jù)庫表的“大雜院”,最后造成數(shù)據(jù)庫中的基本表、代碼表、中間表、臨時表雜亂無章,不計其數(shù),導(dǎo)致企事業(yè)單位的信息系統(tǒng)無法維護(hù)而癱瘓。
2、提高數(shù)據(jù)庫運行效率的辦法
在給定的系統(tǒng)硬件和系統(tǒng)軟件條件下,提高數(shù)據(jù)庫系統(tǒng)的運行效率的辦法是:
(1) 在數(shù)據(jù)庫物理設(shè)計時,降低范式,增加冗余, 少用觸發(fā)器, 多用存儲過程。
(2) 當(dāng)計算非常復(fù)雜、而且記錄條數(shù)非常巨大時(例如一千萬條),復(fù)雜計算要先在數(shù)據(jù)庫外面,以文件系統(tǒng)方式用C++語言計算處理完成之后,最后才入庫追加到表中去。這是電信計費系統(tǒng)設(shè)計的經(jīng)驗。
(3) 發(fā)現(xiàn)某個表的記錄太多,例如超過一千萬條,則要對該表進(jìn)行水平分割(oracle的分區(qū)表很強大,可代替此操作)。水平分割的做法是,以該表主鍵PK的某個值為界線,將該表的記錄水平分割為兩個表。若發(fā)現(xiàn)某個表的字段太多,例如超過八十個,則垂直分割該表,將原來的一個表分解為兩個表。
(4) 對數(shù)據(jù)庫管理系統(tǒng)DBMS進(jìn)行系統(tǒng)優(yōu)化,即優(yōu)化各種系統(tǒng)參數(shù),如緩沖區(qū)個數(shù)。
(5) 在使用面向數(shù)據(jù)的SQL語言進(jìn)行程序設(shè)計時,盡量采取優(yōu)化算法。
總之,要提高數(shù)據(jù)庫的運行效率,必須從數(shù)據(jù)庫系統(tǒng)級優(yōu)化、數(shù)據(jù)庫設(shè)計級優(yōu)化、程序?qū)崿F(xiàn)級優(yōu)化,這三個層次上同時下功夫。
19.mysql ACID與四種隔離級別歸納總結(jié)
A(atomicity)原子性:
即事務(wù)要么全部做完,要么全部不做,不會出現(xiàn)只做一部分的情形,如A給B轉(zhuǎn)帳,不會出現(xiàn)A的錢少了,B的錢卻沒有增加的情況
C(consistency)一致性:
指的是事務(wù)從一個狀態(tài)到另一個狀態(tài)是一致的,如A減少了100,B不可能只增加30。
I(isolation)隔離性:
即一個事務(wù)在沒有完成數(shù)據(jù)的提交修改時,對其它事務(wù)是不可見的。當(dāng)然這里有個隔離級別的概念,在不同隔離級別下,這里會有不同的表現(xiàn)形式
D(durability)持久性:
一旦事務(wù)提交,則所做修改就會被永久保存到數(shù)據(jù)庫中。
在說隔離級別之前,我們先說如下幾個概念:
臟讀:
一個事務(wù)對數(shù)據(jù)進(jìn)行增刪改,但并沒有提交,但另一事務(wù)卻能讀到未提交的數(shù)據(jù)
不可重復(fù)讀:
一事務(wù)對數(shù)據(jù)進(jìn)行了更新或刪除操作,另一事務(wù)兩次查詢的數(shù)據(jù)不一致
幻讀:
一事務(wù)對數(shù)據(jù)進(jìn)行了新增操作,另一事務(wù)兩次查詢結(jié)果不一致。
我們看到不可重復(fù)讀與幻讀好像好類似,但其實它們是有很大的不同,不可重復(fù)讀主要體現(xiàn)在update與delete,而幻讀主要體現(xiàn)在insert,從實現(xiàn)層面上講,要解決不可重復(fù)讀,我們只需要對查詢的數(shù)據(jù)進(jìn)行加鎖就可以實現(xiàn),此時update與delete這些行都會阻塞等待,但是insert依舊可以,避免不了幻讀,而要解決幻讀,必須對其行與行之前也加鎖,在mysql中,是通過next key lock(行鎖+gap lock)來實現(xiàn)的。
隔離級別:
read uncommited未提交讀:
隔離級別為0,會有臟讀,不可重復(fù)讀,幻讀
read commit提交讀:
隔離級別為1,不會有臟讀,但有不可重復(fù)讀,幻讀
repeatable read可重復(fù)讀:
隔離級別為2,不會有臟讀,不可重復(fù)讀,但依舊會有幻讀。但為什么說mysql中的repeatable read解決了幻讀?本來是會有幻讀的,但是它采用了next key lock加上for update來避免,InnoDB提供了這樣一種機制,通過加鎖去查詢可以得到最新的數(shù)據(jù),如兩個事務(wù)同時開啟,A事務(wù)插入了一條數(shù)據(jù),并提交,B事務(wù)去查select * from t,此時B是不能查詢到A事務(wù)提交的數(shù)據(jù)的,但是加多一個for update,即select * from t for update,就能查找剛剛A事務(wù)插入的數(shù)據(jù)。所以我們才說mysql在repeatable read隔離級別下可以避免幻讀的原因,記得加for update。
serializable可序列化:
隔離級別為3,不會有臟讀,不可重復(fù)讀,幻讀。但效率最低,并發(fā)性能最差,一般情況下不會使用。
20.java虛擬機類加載機制
加載:階段主要完成三件事,即通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流,將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu),在Java堆中生成一個代表此類的Class對象,作為訪問方法區(qū)這些數(shù)據(jù)的入口。
驗證:確保Class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機要求,不會危害虛擬機自身安全。主要包括四種驗證:文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證、符號引用驗證。
準(zhǔn)備:僅僅為類變量(即static修飾的字段變量)分配內(nèi)存并且設(shè)置該類變量的初始值即零值,這里不包含用final修飾的static,因為final在編 譯的時候就會分配了,同時這里也不會為實例變量分配初始化。類變量會分配在方法區(qū)中,而實例變量是會隨著對象一起分配到Java堆中。
解析:主要就是將常量池中的符號引用替換為直接引用的過程。
初始化:階段依舊是初始化類變量和其他資源,這里將執(zhí)行用戶的static字段和靜態(tài)語句塊的賦值操作。這個過程就是執(zhí)行類構(gòu)造器方法的過程。
類加載器的分類:啟動類加載器、擴展類類加載器、應(yīng)用程序類加載器。
21.Lock和synchronized有以下幾點不同
1).Lock是一個接口,而synchronized是Java中的關(guān)鍵字,synchronized是內(nèi)置的語言;
2).synchronized在發(fā)生異常時,會自動釋放線程占有的鎖,因此不會導(dǎo)致死鎖現(xiàn)象的發(fā)生;而Lock在發(fā)生異常時,如果沒有主動通過unlock()去釋放鎖,而很可能造成死鎖的現(xiàn)象,因此使用Lock時需要在finally塊中釋放鎖;
3).Lock可以讓等待鎖的線程響應(yīng)中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應(yīng)中斷;
4).通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
5).Lock可以提高多個線程進(jìn)行讀操作的效率。
在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當(dāng)競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠(yuǎn)遠(yuǎn)優(yōu)于synchronized。所以說,在具體使用時要根據(jù)適當(dāng)情況選擇。
22.緩存穿透,緩存擊穿,緩存雪崩解決方案分析
緩存穿透
緩存穿透是指查詢一個一定不存在的數(shù)據(jù),由于緩存是不命中時被動寫的,并且出于容錯考慮,如果從存儲層查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個不存在的數(shù)據(jù)每次請求都要到存儲層去查詢,失去了緩存的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應(yīng)用,這就是漏洞。
解決方案
有很多種方法可以有效地解決緩存穿透問題,最常見的則是采用布隆過濾器,將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中,一個一定不存在的數(shù)據(jù)會被 這個bitmap攔截掉,從而避免了對底層存儲系統(tǒng)的查詢壓力。另外也有一個更為簡單粗暴的方法(我們采用的就是這種),如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個空結(jié)果進(jìn)行緩存,但它的過期時間會很短,最長不超過五分鐘。
緩存雪崩
緩存雪崩是指在我們設(shè)置緩存時采用了相同的過期時間,導(dǎo)致緩存在某一時刻同時失效,請求全部轉(zhuǎn)發(fā)到DB,DB瞬時壓力過重雪崩。
解決方案
緩存失效時的雪崩效應(yīng)對底層系統(tǒng)的沖擊非??膳隆4蠖鄶?shù)系統(tǒng)設(shè)計者考慮用加鎖或者隊列的方式保證緩存的單線 程(進(jìn)程)寫,從而避免失效時大量的并發(fā)請求落到底層存儲系統(tǒng)上。這里分享一個簡單方案就時講緩存失效時間分散開,比如我們可以在原有的失效時間基礎(chǔ)上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重復(fù)率就會降低,就很難引發(fā)集體失效的事件。