對於javaSE的理解
是整個JAVA的基礎和核心,是剛接觸java要學習的基礎知識
1.1 控制數據的流向,將前台傳過來的數據包起來,然后一個一個地插入數據庫永久保存。
1.2 從數據庫中用jdbc取出數據,然后包起來,最終傳遞到前台頁面進行公開展覽
where、having之間的區別和用法
聚合函數是比較where、having 的關鍵。
若須引入聚合函數來對group by 結果進行過濾 則只能用having
select sum(score) from student where sex='man' group by name having sum(score)>210
where 后不能跟聚合函數,因為where執行順序大於聚合函數
dubbo
調用關系說明:
0. 服務容器負責啟動,加載,運行服務提供者。
1. 服務提供者在啟動時,向注冊中心注冊自己提供的服務。 --寫入自己的URL地址。
2. 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。 --訂閱提供者的URL地址,並寫入自己的URL地址。
3. 注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基於長連接推送變更數據給消費者。
4. 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
5. 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鍾發送一次統計數據到監控中心。
Dubbo建議使用Zookeeper作為服務的注冊中心。
Dubbo的將注冊中心進行抽象,是得它可以外接不同的存儲媒介給注冊中心提供服務,有ZooKeeper,Redis等
首先是負載均衡,單注冊中心的承載能力是有限的,在流量達到一定程度的時 候就需要分流,負載均衡就是為了分流而存在的,一個ZooKeeper群配合相應的Web應用就可以很容易達到負載均衡;資源同步,單單有負載均衡還不夠,節點之間的數據和資源需要同步
負載均衡策略
RandomLoadBalance:隨機負載均衡算法,Dubbo默認的負載均衡策略
按權重設置隨機概率。在一個截面上碰撞的概率較高,但調用越大分布越均勻
RoundRobinLoadBalance:輪詢負載均衡算法,按公約后的權重設置輪循比率
這種模式下,在權重設置不合理的情況下,會導致某些節點無法負載請求,另外,如果有些機器性能比較低,會存在請求阻塞的情況
ConsistentHashLoadBalance: 一致性Hash,相同參數的請求總是發到同一提供者。
當某一台提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。
Zookeeper的作用:
zookeeper用來注冊服務和進行負載均衡,哪一個服務由哪一個機器來提供必需讓調用者知道,簡單來說就是ip地址和服務名稱的對應關系。當然也可以 通過硬編碼的方式把這種對應關系在調用方業務代碼中實現,但是如果提供服務的機器掛掉調用者無法知曉,如果不更改代碼會繼續請求掛掉的機器提供服務。 zookeeper通過心跳機制可以檢測掛掉的機器並將掛掉機器的ip和服務對應關系從列表中刪除。
java小例子: int a=2,b=2;
硬編碼:if(a==2) return false;
非硬編碼 if(a==b) return true; (就是把數值寫成常數而不是變量 )
一個簡單的版本:如求圓的面積 的問題 PI(3.14)
那么3.14*r*r 就是硬編碼,而PI*r*r 就不是硬編碼。
ZooKeeper的特性引進來。
首先是負載均衡,單注冊中心的承載能力是有限的,在流量達到一定程度的時 候就需要分流,負載均衡就是為了分流而存在的,一個ZooKeeper群配合相應的Web應用就可以很容易達到負載均衡
資源同步 節點之間的數據和資源需要同步,ZooKeeper集群就天然具備有這樣的功能
Zookeeper做了什么?
配置管理 如果程序分散部署在多台機器上,要逐個改變配置就變得困難。現在把這些配置全部放到zookeeper上去,保存在 Zookeeper 的某個目錄節點中,然后所有相關應用程序對這個目錄節點進行監聽,一旦配置信息發生變化,每個應用程序就會收到 Zookeeper 的通知
集群管理 是否有機器退出和加入、選舉master。
分布式鎖 一個是保持獨占,另一個是控制時序。
dubbo協議
適用范圍:傳入傳出參數數據包較小(建議小於100K),消費者比提供者個數多(並發量高),單一消費者無法壓滿提供者,盡量不要用dubbo協議傳輸大文件或超大字符串。
適用場景:常規遠程服務方法調用
1、dubbo默認采用dubbo協議,dubbo協議采用單一長連接和NIO異步通訊,適合於小數據量大並發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的情況
2、他不適合傳送大數據量的服務,比如傳文件,傳視頻等,除非請求量很低。
3、Dubbo協議缺省每服務每提供者每消費者使用單一長連接,如果數據量較大,可以使用多個連接。
4、為防止被大量連接撐掛,可在服務提供方限制大接收連接數,以實現服務提供方自我保護
為什么采用異步單一長連接?
因為服務的現狀大都是服務提供者少,通常只有幾台機器,而服務的消費者多,可能整個網站都在訪問該服務,比如Morgan的提供者只有6台提供者,卻有上百台消費者,每天有1.5億次調用,如果采用常規的hessian服務,服務提供者很容易就被壓跨,通過單一連接,保證單一消費者不會壓死提供者,長連接,減少連接握手驗證等
什么時候用長連接,短連接?
長連接多用於操作頻繁,點對點的通訊,而且連接數不能太多情況。每個TCP連接都需要三步握手,這需要時間,如果每個操作都是先連接,再操作的話那么處理速度會降低很多,所以每個操作完后都不斷開,次處理時直接發送數據包就OK了,不用建立TCP連接。例如:數據庫的連接用長連接,如果用短連接頻繁的通信會造成socket錯誤,而且頻繁的socket 創建也是對資源的浪費。
而像WEB網站的http服務一般都用短鏈接,因為長連接對於服務端來說會耗費一定的資源,而像WEB網站這么頻繁的成千上萬甚至上億客戶端的連接用短連接會更省一些資源,如果用長連接,而且同時有成千上萬的用戶,如果每個用戶都占用一個連接的話,那可想而知吧。所以並發量大,但每個用戶無需頻繁操作情況下需用短連好。
短連接:通信雙方有數據交互時,就建立一個TCP連接,數據發送完成后,則斷開此TCP連接
單例模式:確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例
枚舉(單例模式)
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
// 餓漢式單例
public class Singleton1 {
// 私有構造
private Singleton1() {}
private static Singleton1 single = new Singleton1();
// 靜態工廠方法
public static Singleton1 getInstance() {
return single;
}
}
應用剛啟動的時候,不管外部有沒有調用該類的實例方法,該類的實例就已經創建好了。以空間換時間
寫法簡單,在多線程下也能保證單例實例的唯一性,不用同步,運行效率高。
當類被加載時,靜態變量instance會被初始化,此時類的私有構造函數會被調用,單例類的唯一實例將被創建。
懶漢式:
應用剛啟動的時候,並不創建實例,當外部調用該類的實例或者該類實例方法的時候,才創建該類的實例。是以時間換空間。
實例在被使用的時候才被創建,可以節省系統資源,體現了延遲加載的思想。
/**
* 飽漢式(懶漢式)----就是有錢,豪,用的時候再new(線程不安全)
* <p>
* Created by lxk on 2017/3/23
*/
public class SingletonPattern2 {
private static SingletonPattern2 singletonInstance;
private SingletonPattern2() {
}
public static SingletonPattern2 getSingletonInstance() {
if (singletonInstance == null) {
singletonInstance = new SingletonPattern2();
}
return singletonInstance;
}
///**
// * 為了應對上述的不安全,可以簡單的如下操作給方法添加[synchronized],使之成為同步函數。
// * 但是:
// * 在很多線程的情況下,就每個線程訪問都得判斷鎖,效率就是問題。所以,才有后面的[雙重鎖形式]
// */
//public static synchronized SingletonPattern2 getSingletonInstance() {
// if (singletonInstance == null) {
// singletonInstance = new SingletonPattern2();
// }
// return singletonInstance;
//}
在任何需要生成復雜對象的地方,都可以使用工廠方法模式(比如 計算器的加減乘除)
步驟 1
創建一個接口:
Shape.java
public interface Shape { void draw(); }
步驟 2
創建實現接口的實體類。
Rectangle.java
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }
Square.java
public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } }
Circle.java
public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }
步驟 3
創建一個工廠,生成基於給定信息的實體類的對象。
ShapeFactory.java
public class ShapeFactory { //使用 getShape 方法獲取形狀類型的對象
public Shape getShape(String shapeType){
if(shapeType == null){ return null; }
if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } }
步驟 4
使用該工廠,通過傳遞類型信息來獲取實體類的對象。
FactoryPatternDemo.java
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory(); //獲取 Circle 的對象,並調用它的 draw 方法
Shape shape1 = shapeFactory.getShape("CIRCLE"); //調用 Circle 的 draw 方法 shape1.draw(); //獲取 Rectangle 的對象,並調用它的 draw 方法
Shape shape2 = shapeFactory.getShape("RECTANGLE"); //調用 Rectangle 的 draw 方法 shape2.draw(); //獲取 Square 的對象,並調用它的 draw 方法
Shape shape3 = shapeFactory.getShape("SQUARE"); //調用 Square 的 draw 方法 shape3.draw();
}
}
步驟 5
執行程序,輸出結果:
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
sql優化
SELECT子句中避免使用‘*’;
表設計--合理的增加冗余的字段(減少表的聯接查詢);
在業務密集的SQL當中盡量不采用IN操作符,用EXISTS替代IN、用NOT EXISTS替代NOT IN;
用UNION-ALL 替換UNION /or( 如果有可能的話);
最左匹配原則
兩個字段(name,age)建立聯合索引,如果where age=12這樣的話,是沒有利用到索引的,這里我們可以簡單的理解為先是對name字段的值排序,然后對age的數據排序,如果直接查age的話,這時就沒有利用到索引了,查詢條件where name=’xxx’ and age=xx 這時的話,就利用到索引了
失效條件
條件是or,如果還想讓or條件生效,給or每個字段加個索引
避免在索引列上使用計算。WHERE子句中,如果索引列是函數的一部分。優化器將不使用索引而使用全表掃描;
低效: SELECT … FROM DEPT WHERE SAL * 12 > 25000; 高效: SELECT … FROM DEPT WHERE SAL > 25000/12;
模糊查詢like 關鍵詞%yue%,由於yue前面用到了“%”,因此該查詢必然走全表掃描,除非必要,否則不要在關鍵詞前加%;
注意:like ‘…%’,是會使用索引的;左模糊like
考慮索引重建場合
索引最大的好處是提高查詢速度,
缺點是更新數據時效率低,因為要同時更新索引
對數據進行頻繁查詢進建立索引,如果要頻繁更改數據不建議使用索引。
表上頻繁發生update,delete操作。
表上發生了alter table ..move操作(move操作導致了rowid變化)
為什么要分庫分表,主從復制,讀寫分離
針對大數據量並且訪問頻繁的表,將其分為若干個表
當一張表的數據達到幾千萬時,你查詢一次所花的時間會變多,如果有聯合查詢的話,我想有可能會死在那兒了。分表的目的就在於此,減小數據庫的負擔,縮短查詢時間;
主從結構,一主多備,讀寫分離,讀從庫,寫主庫
在實際的應用中,絕大部分情況都是讀遠大於寫。Mysql提供了讀寫分離的機制,所有的寫操作都必須對應到Master,讀操作可以在 Master和Slave機器上進行,Slave與Master的結構完全一樣,
所有的寫操作都是先在Master上操作,然后同步更新到Slave上,所以從Master同步到Slave機器有一定的延遲
提高數據庫的吞吐量
非關系型數據庫中,我們查詢一條數據,結果出來一個數組,關系型數據庫中,查詢一條數據結果是一個對象。
關系型數據庫
SQLite、Oracle、mysql
特性:關系型數據庫的最大特點就是事務的一致性;
優點:通用的SQL語言使得操作關系型數據庫非常方便,大大減低了數據冗余和數據不一致的概率;
缺點:為了維護一致性所付出的巨大代價就是其讀寫性能比較差,海量數據的高效率讀寫;
非關系型數據庫
MongoDb、redis、HBase
特性:使用鍵值對存儲數據;嚴格上不是一種數據庫,應該是一種數據結構化存儲方法的集合
優點:無需經過sql層的解析,讀寫性能很高,nosql的存儲格式是key,value形式、文檔形式、圖片形式等等,文檔形式、圖片形式等等,而關系型數據庫則只支持基礎類型。
缺點:不提供sql支持,學習和使用成本較高,無事務處理,附加功能bi和報表等支持也不好
數據庫事務必須具備ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔離性,Durability持久性
事務的四大特性
原子性--事務包含的所有操作要么全部成功,要么全部失敗回滾
一致性--事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之后都必須處於一致性狀態。
拿轉賬來說,假設用戶A和用戶B兩者的錢加起來一共是5000,那么不管A和B之間如何轉賬,轉幾次賬,事務結束后兩個用戶的錢相加起來應該還得是5000,這就是事務的一致性。
隔離性--多個用戶並發訪問數據庫時,比如操作同一張表時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個並發事務之間要相互隔離.
持久性--一個事務一旦被提交了,那么對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。
臟讀:事務B讀取事務A還沒有提交的數據
不可重復讀:兩次事務讀的數據不一致
幻讀:事務A修改了數據,事務B也修改了數據,這時在事務A看來,明明修改了數據,昨不一樣,
隔離級別
① Serializable (串行化):可避免臟讀、不可重復讀、幻讀的發生。
② Repeatable read (可重復讀):可避免臟讀、不可重復讀的發生。
③ Read committed (讀已提交):可避免臟讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
Spring 框架
spring管理的bean在默認情況下是會在服務器啟動的時候初始化的。
bean設置了scope為prototype(原型)之后,會每次使用時生產一個
bean設置了lazy-init=”true”后,啟動服務器不會馬上實例化,而是在用到的時候被實例化
具體來說Spring是一個輕量級的容器,用於管理業務相關對象的。核心功能主要為:IOC,AOP,MVC。
Spring 的基礎是ioc和 aop,ioc 提供了依賴注入的容器, aop解決了面向橫切面的編程
控制反轉IoC(Inversion of Control)
是說創建對象的控制權進行轉移,以前創建對象的主動權和創建時機是由自己把控的,而現在這種權力轉移到第三方,比如轉移交給了IoC容器,它就是一個專門用來創建對象的工廠,你要什么對象,它就給你什么對象,有了 IoC容器,依賴關系就變了,原先的依賴關系就沒了,它們都依賴IoC容器了,通過IoC容器來建立它們之間的關系,讓容器管理對象的生命周期如創建,初始化,銷毀等。
DI(依賴注入)其實就是IOC的另外一種說法
Spring MVC提供了一種輕度耦合的方式來開發web應用。它是Spring的一個模塊,是一個web框架。通過Dispatcher Servlet, ModelAndView 和 View Resolver,開發web應用變得很容易
SpringBoot實現了自動配置,降低了項目搭建的復雜度。它主要是為了解決使用Spring框架需要進行大量的配置太麻煩的問題,所以它並不是用來替代Spring的解決方案,而是和Spring框架緊密結合用於提升Spring開發者體驗的工具
spring-colud是一種雲端分布式架構解決方案,基於spring boot,在spring boot做較少的配置,便可成為 spring cloud 中的一個微服務。
什么是AOP?
面向切面編程(AOP)完善spring的依賴注入(DI),面向切面編程在spring中主要表現為兩個方面
1.面向切面編程提供聲明式事務管理
2.spring支持用戶自定義的切面
Spring AOP的核心實現原理就是采用的動態代理,根據被代理對象是否實現了所要被代理的接口這個條件,動態代理會選擇不同的實現方案。
java中最常見的動態代理模式:jdk原生動態代理和cgLlb動態代理
JDK原生:不需要任何外部依賴,但只能基於接口進行代理,實現一個InvocationHandler,方法調用會被轉發到該類的invoke()方法,在需要使用對象實例的時候,通過JDK動態代理獲取實例的代理對象
cgLlb:通過繼承的方式實現,無論目標對象有沒有實現接口都可以代理,但是無法處理final的情況
其實最核心的還是java的反射機制,通過獲取對象實例,調用對應的方法,前者通過接口來做橋梁,后者通過中間類轉發,都只是形式而已
面向切面編程(aop)是對面向對象編程(oop)的補充,
面向對象編程將程序分解成各個層次的對象,面向切面編程將程序運行過程分解成各個切面。
AOP從程序運行角度考慮程序的結構,提取業務處理過程的切面,oop是靜態的抽象,aop是動態的抽象,
是對應用執行過程中的步驟進行抽象,,從而獲得步驟之間的邏輯划分。
aop框架具有的兩個特征:
1.各個步驟之間的良好隔離性
2.源代碼無關性
SpringMVC工作流程
1、用戶發送請求至前端控制器DispatcherServlet
2、DispatcherServlet收到請求調用HandlerMapping處理器映射器。
3、處理器映射器找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一並返回給DispatcherServlet。
4、DispatcherServlet調用HandlerAdapter處理器適配器
5、HandlerAdapter經過適配調用具體的處理器(Controller,也叫后端控制器)。
6、Controller執行完成返回ModelAndView
7、HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet
8、DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
9、ViewReslover解析后返回具體View
10、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。
11、DispatcherServlet響應用戶
簡單:系統啟動的時候根據配置文件創建spring的容器, 首先是發送http請求到核心控制器DispatcherServlet,spring容器通過映射器去尋找業務控制器,
使用適配器找到相應的業務類,在進業務類時進行數據封裝,在封裝前可能會涉及到類型轉換,執行完業務類后使用ModelAndView進行視圖轉發,
數據放在model中,用map傳遞數據進行頁面顯示。
值傳遞和引用傳遞的區別
值傳遞僅僅傳遞的是值。
引用傳遞,傳遞的是內存地址,修改后會改變內存地址對應儲存的值。
用數組來舉例就最清楚了,例如我們定義一個數組a[]={1,2};那么a[0]=1, a[1=2].
如果我們把數組a里的元素值作為參數傳遞,實際上只是進行了值傳遞,對數組本身沒有影響
如果我們把 數組a的指針作為參數傳遞,那么假如處理的函數就可以直接修改數組a里的值。
== 和equals區別?
當“==”運算符的兩個操作數都是包裝器類型的引用,則是比較執行的是否是同於個對象,而如果兩者比較中有一個操作數是表達式(含運算符)則比較的是數值(會自動觸發拆箱的過程)
equals 用於判斷兩個變量是否是對同一個對象的引用
Session和Cookie的區別?
session是存放在服務器端的,cookie是存放在客戶端的,cookie的安全性不高,雖然它已經加了密,但是還是可以偽造的。
死鎖產生發生:
線程死鎖是指由於兩個或者多個線程互相持有對方所需要的資源,導致這些線程處於等待狀態,無法前往執行。當線程進入對象的synchronized代碼塊時,便占有了資源,直到它退出該代碼塊或者調用wait方法,才釋放資源,在此期間,其他線程將不能進入該代碼塊。當線程互相持有對方所需要的資源時,會互相等待對方釋放資源,如果線程都不主動釋放所占有的資源,將產生死鎖。
如何避免:
1、加鎖順序:
2、加鎖時限:
解決方案:簡單粗暴 找到進程號,kill 進程
String,StringBuffer和StringBuilder的區別
1、運行速度,或者說是執行速度,在這方面運行速度快慢為:StringBuilder > StringBuffer > String。
2、線程安全上,StringBuilder是線程不安全的,而StringBuffer是線程安全的。
適用場景分析:
String:適用於少量的字符串操作的情況
StringBuilder:適用於單線程下在字符緩沖區進行大量操作的情況
StringBuffer:適用多線程下在字符緩沖區進行大量操作的情況
mybatis如何處理結果集
MyBatis的結果集是通過反射來實現的
MyBatis里面的核心處理類叫做SqlSession
MyBatis(IBatis)的好處是什么
把sql語句從Java源程序中獨立出來,放在單獨的XML文件中編寫,給程序的維護帶來了很大便利。
封裝了底層JDBC API的調用細節,並能自動將結果集轉換成JavaBean對象,大大簡化了Java數據庫編程的重復工作
需要程序員自己去編寫sql語句,程序員可以結合數據庫自身的特點靈活控制sql語句,更高的查詢效率
#{}與${}的區別
1. #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:order by #{user_id},如果傳入的值是111,那么解析成sql時的值為order by “111”, 如果傳入的值是id,則解析成的sql為order by “id”.
2. $將傳入的數據直接顯示生成在sql中。如:order by ${user_id},如果傳入的值是111,那么解析成sql時的值為order by 111, 如果傳入的值是id,則解析成的sql為order by id.
${}方式會引發SQL注入的問題、同時也會影響SQL語句的預編譯,所以從安全性和性能的角度出發,能使用#{}的情況下就不要使用${}。
在mapper中如何傳遞多個參數
第一種:使用 @param 注解 第二種:多個參數封裝成map
分布式鎖一般有三種實現方式:(樂觀鎖,自己實現,通過版本號 )
1. 數據庫樂觀鎖;2. 基於Redis的分布式鎖;3. 基於ZooKeeper的分布式鎖
首先,為了確保分布式鎖可用,我們至少要確保鎖的實現同時滿足以下四個條件:
互斥性。在任意時刻,只有一個客戶端能持有鎖。
不會發生死鎖。即使有一個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證后續其他客戶端能加鎖。
具有容錯性。只要大部分的Redis節點正常運行,客戶端就可以加鎖和解鎖。
解鈴還須系鈴人。加鎖和解鎖必須是同一個客戶端,客戶端自己不能把別人加的鎖給解了。
加鎖
1. 當前沒有鎖(key不存在),那么就進行加鎖操作,並對鎖設置個有效期,同時value表示加鎖的客戶端。
2. 已有鎖存在,不做任何操作。
解鎖
首先獲取鎖對應的value值,檢查是否與requestId相等,如果相等則刪除鎖(解鎖)
深入探索SpringApplication執行流程
如果我們使用的是SpringApplication的靜態run方法,那么,這個方法里面首先要創建一個SpringApplication對象實例,然后調用這個創建好的SpringApplication的實例方法。在SpringApplication實例初始化的時候,它會提前做幾件事情:
根據classpath里面是否存在某個特征類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應該創建一個為Web應用使用的ApplicationContext類型。
使用SpringFactoriesLoader在應用的classpath中查找並加載所有可用的ApplicationContextInitializer。實現了這個接口的這些實例將在上下文初始化的時候prepareContext被使用。
使用SpringFactoriesLoader在應用的classpath中查找並加載所有可用的ApplicationListener。這個接口表示這個接口將監聽對應的ApplicationEvent事件
推斷並設置main方法的定義類。
Spring 框架中的單例 Beans 是線程安全的么?
Spring 框架並沒有對單例 bean 進行任何多線程的封裝處理。關於單例 bean 的線程安全和並
發問題需要開發者自行去搞定。但實際上,大部分的 Spring bean 並沒有可變的狀態(比如
Serview類和DAO類),所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean
有多種狀態的話(比如 View Model 對象),就需要自行保證線程安全。
最淺顯的解決辦法就是將多態 bean 的作用域由“singleton”變更為“prototype”。
spring開發web 時要注意,默認Controller、Dao、Service都是單例的
@SpringBootApplication是一個復合注解,包括@ComponentScan,和@SpringBootConfiguration,@EnableAutoConfiguration。
@Autowired和@Resource(java原生)開啟基於注解的自動裝配
@Autowired是Spring的注解,@Resource是J2EE的注解
@Component是所有受Spring 管理組件的通用形式,@Component注解可以放在類的頭上,@Component不推薦使用。
@Service對應的是業務層Bean
@Controller對應表現層的Bean
@RequestMapping 表明所有的請求路徑都要基於該路徑
Java集合類
(1)List 支持null元素和重復元素的動態擴容列表,jdk提供的實現類有:ArrayList, LinkedList, Stack,CopyOnWriteArrayList、Vector
(2)Set 不支持重復元素的動態擴容列表,jdk提供的實現類有:EnumSet, TreeSet, HashSet, LinkedHashSet、 NavigableSet、ConcurrentSkipListSet、CopyOnWriteArraySet
(3)map 是存儲鍵/值對的映射集,jdk提供的實現類有:HashMap, TreeMap,LinkedHashMap、ConcurrentHashMap、HashTable、ConcurrentSkipListMap
(4)queue/deque queue是在集合尾部添加元素,在頭部刪除元素的隊列,deque是可在頭部和尾部添加或者刪除元素的雙端隊列
List 線程不安全的子類:ArrayList, LinkedList,
ArrayList:是一個容量動態擴張的集合,實現了RandomAccess接口,支持隨機訪問,可以通過List list = Collections.synchronizedList(new ArrayList(...))把它轉成線程安全的集合,當然只是封裝了對ArrayList的操作,保存同步而已,性能不是很高,所有的修改操作都要一個個同步。
LinkedList:內部是鏈表結果,非線程安全,添加元素的方法只是新增一個節點然后改變尾部節點和新增節點的引用鏈接,所以新增和刪除操作比較快,但是不支持隨機訪問,同時實現List和Deque接口,所以即可以當一個雙端隊列使用,也可以當List使用
set 線程不安全的子類:EnumSet, TreeSet, HashSet, LinkedHashSet、 NavigableSet
treeSet是有序集合,內部通過TreeMap來存儲元素,把元素存儲在map的key里,通過TreeMap存儲Key的有序性和無重復性來實現自己的有序性和Set的的元素無重復性
HashSet不是線程安全的
map 線程不安全的子類:HashMap, TreeMap,LinkedHashMap,鍵值對、鍵唯一、值不唯一
HashMap是線程不安全的提供所有Map操作的集合容器,支持Null為key或者value,並且是無序的。
HashMap是線程不安全的,不要在並發的環境中同時操作HashMap,建議使用ConcurrentHashMap。
jdk1.8后HashMap的存儲結構,因為和1.7之前都不太一樣,性能也不一樣。
jdk1.8之前,hashMap的存儲結構是數組+鏈表,也就是發生hash沖突后的元素后插入到鏈表里,而不是存儲在數組,這樣的的話如果對於hash沖突比較嚴重的數據時,hashMap的查詢速度就不是o(1)了,而是o('n');
jdk1.8后,HashMap的存儲結構是數組+鏈表or平衡樹,因為平衡樹的時間復雜度是o(log('n')),是1.8后HashMap的查詢復雜度是O(1)~O(log('n' ))。
loadFactor是觸發HashMap擴容的負載因子,默認是0.75,擴容是非常耗時的事情,所以這個負載因子很重要,0.75是性能比較好的一個數
如果你經常會使用索引來對容器中的元素進行訪問,那么 List 是你的正確的選擇。如果你已經知道索引了的話,那么 List 的實現類比如 ArrayList 可以提供更快速的訪問,如果經常添加刪除元素的,那么肯定要選擇LinkedList。
如果你想容器中的元素能夠按照它們插入的次序進行有序存儲,那么還是 List,因為 List 是一個有序容器,它按照插入順序進行存儲。
如果你想保證插入元素的唯一性,也就是你不想有重復值的出現,那么可以選擇一個 Set 的實現類,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的實現類都遵循了統一約束比如唯一性,而且還提供了額外的特性比如 TreeSet 還是一個 SortedSet,所有存儲於 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 進行排序。LinkedHashSet 也按照元素的插入順序對它們進行存儲。
如果你以鍵和值的形式進行數據存儲那么 Map 是你正確的選擇。你可以根據你的后續需要從 Hashtable、HashMap、TreeMap 中進行選擇。
Comparable和Comparator區別比較
Comparable是排序接口,若一個類實現了Comparable接口,就意味着“該類支持排序”。而Comparator是比較器,我們若需要控制某個類的次序,可以建立一個“該類的比較器”來進行排序。
Comparable相當於“內部比較器”,而Comparator相當於“外部比較器”。
兩種方法各有優劣, 用Comparable 簡單, 只要實現Comparable 接口的對象直接就成為一個可以比較的對象,但是需要修改源代碼。 用Comparator 的好處是不需要修改源代碼, 而是另外實現一個比較器, 當某個自定義的對象需要作比較的時候,把比較器和對象一起傳遞過去就可以比大小了, 並且在Comparator 里面用戶可以自己實現復雜的可以通用的邏輯,使其可以匹配一些比較簡單的對象,那樣就可以節省很多重復勞動了。
jdk1.8 lambam表達式
// 以前的循環方式
for (String player : players) {
System.out.print(player + "; ");
}
// 使用 lambda 表達式以及函數操作(functional operation)
players.forEach((player) -> System.out.print(player + "; "));
使用Lambdas排序集合
// 1.3 也可以采用如下形式:
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));
readExcelList.stream().forEach(p->{ xxx });
java通過Stream對list集合分組
CompleteDtos.stream().collect(Collectors.groupingBy(CompleteRateDto::getIdKey)).values().forEach(p->{ xxx });
kafaka
Apache開發的一種發布訂閱消息系統,它是一個分布式的、分區的和重復的日志服務。
nginx
在正向代理中,Proxy和Client同屬於一個LAN(圖中方框內),隱藏了客戶端信息;
在反向代理中,Proxy和Server同屬於一個LAN(圖中方框內),隱藏了服務端信息;
負載均衡調度算法:
weight輪詢(默認):接收到的請求按照順序逐一分配到不同的后端服務器,即使在使用過程中,某一台后端服務器宕機,Nginx會自動將該服務器剔除出隊列,請求受理情況不會受到任何影響。
ip_hash:每個請求按照發起客戶端的ip的hash結果進行匹配,這樣的算法下一個固定ip地址的客戶端總會訪問到同一個后端服務器
(1)保證內網的安全,通常將反向代理作為公網訪問地址,Web服務器是內網
(2)負載均衡,通過反向代理服務器來優化網站的負載
Tomcat在高並發環境下處理動態請求時性能很低,而在處理靜態頁面更加脆弱,但是通過Nginx來處理靜態頁面要比通過Tomcat處理在性能方面好很多
Nginx可以通過兩種方式來實現與Tomcat的耦合。
將靜態頁面請求交給Nginx,動態請求交給后端Tomcat處理。
將所有請求都交給后端的Tomcat服務器處理,同時利用Nginx自身的負載均衡功能,進行多台Tomcat服務器的負載均衡。
Servlet程序是由WEB服務器調用,web服務器收到客戶端的Servlet訪問請求后:
①Web服務器首先檢查是否已經裝載並創建了該Servlet的實例對象。如果是,則直接執行第④步,否則,執行第②步。
②裝載並創建該Servlet的一個實例對象。
③調用Servlet實例對象的init()方法。
④創建一個用於封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然后調用Servlet的service()方法並將請求和響應對象作為參數傳遞進去。
⑤WEB應用程序被停止或重新啟動之前,Servlet引擎將卸載Servlet,並在卸載之前調用Servlet的destroy()方法。
Servlet是一個供其他Java程序(Servlet引擎)調用的Java類,它不能獨立運行,它的運行完全由Servlet引擎來控制和調度。
針對客戶端的多次Servlet請求,通常情況下,服務器只會創建一個Servlet實例對象,也就是說Servlet實例對象一旦創建,它就會駐留在內存中,為后續的其它請求服務,直至web容器退出,servlet實例對象才會銷毀。
ConcurentHashMap原理?
線程不安全的HashMap-- 因為多線程環境下,使用Hashmap進行put操作會引起死循環,導致CPU利用率接近100%,所以在並發情況下不能使用HashMap。 底層數組+鏈表實現,線程不安全
效率低下的HashTable容器 -- HashTable容器使用synchronized來保證線程安全,但在線程競爭激烈的情況下HashTable的效率非常低下。因為當一個線程訪問HashTable的同步方法時,其他線程訪問HashTable的同步方法時,可能會進入阻塞或輪詢狀態
底層數組+鏈表實現 線程安全
ConcurrentHashMap --底層采用分段的數組+鏈表實現,線程安全,jdk 1.8后 變更為table數組+單向鏈表+紅黑樹的結構,負載因子恆定為0.75
通過把整個Map分為N個Segment,可以提供相同的線程安全,但是效率提升N倍,默認提升16倍。
鎖分段技術:首先將數據分成一段一段的存儲,然后給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段數據的時候,其他段的數據也能被其他線程訪問。
ConcurrentHashMap提供了與Hashtable和SynchronizedMap不同的鎖機制。Hashtable中采用的鎖機制是一次鎖住整個hash表,從而在同一時刻只能由一個線程對其進行操作;而ConcurrentHashMap中則是一次鎖住一個桶。
諸如get、put、remove等常用操作只鎖住當前需要用到的桶。這樣,原來只能一個線程進入,現在卻能同時有16個寫線程執行,並發性能的提升是顯而易見的
spring事務和jdbc事務的優缺點
Spring提供了對事務的聲明式事務管理,只需要在配置文件中做一些配置,即可把操作納入到事務管理當中,解除了和代碼的耦合。
Spring聲明式事務管理,核心實現就是基於Aop。
Spring聲明式事務管理是粗粒度的事務控制,只能給整個方法應用事務,不可以對方法的某幾行應用事務。
1.xml方式聲明事務 2.注解方式聲明事務
JDBC事務
JDBC的一切行為包括事務是基於一個Connection
的,在JDBC中是通過Connection
對象進行事務管理。在JDBC中,常用的和事務相關的方法是: setAutoCommit
、commit
、rollback
等。
JDBC為使用Java進行數據庫的事務操作提供了最基本的支持。通過JDBC事務,我們可以將多個SQL語句放到同一個事務中,保證其ACID特性。JDBC事務的主要優點就是API比較簡單,可以實現最基本的事務操作,性能也相對較好。
但是,JDBC事務有一個局限:一個 JDBC 事務不能跨越多個數據庫
http原理
HTTP的工作過程
一次HTTP操作稱為一個事務,其工作過程可分為四步:
1)首先客戶機與服務器需要建立連接。只要單擊某個超級鏈接,HTTP的工作開始。
2)建立連接后,客戶機發送一個請求給服務器,請求方式的格式為:統一資源標識符(URL)、協議版本號,后邊是MIME信息包括請求修飾符、客戶機信息和可能的內容。
3)服務器接到請求后,給予相應的響應信息,其格式為一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,后邊是MIME信息包括服務器信息、實體信息和可能的內容。
4)客戶端接收服務器所返回的信息通過瀏覽器顯示在用戶的顯示屏上,然后客戶機與服務器斷開連接。
如果在以上過程中的某一步出現錯誤,那么產生錯誤的信息將返回到客戶端,有顯示屏輸出。對於用戶來說,這些過程是由HTTP自己完成的,用戶只要用鼠標點擊,等待信息顯示就可以了。
設計模式分哪幾種
總體來說設計模式分為三大類:
創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
Socket並發解決方案?
多線程同步實現?
synchronized和volatile的使用區別?
一旦一個共享變量(類的成員變量、類的靜態成員變量)被volatile修飾之后,那么就具備了兩層語義:
1)保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了某個變量的值,這新值對其他線程來說是
立即可見的。
2)禁止進行指令重排序。
volatile本質是在告訴jvm當前變量在寄存器(工作內存)中的值是不確定的,需要從主存中讀取;
synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住。
1.volatile僅能使用在變量級別;
synchronized則可以使用在變量、方法、和類級別的
2.volatile僅能實現變量的修改可見性,並不能保證原子性;
synchronized則可以保證變量的修改可見性和原子性
3.volatile不會造成線程的阻塞;
synchronized可能會造成線程的阻塞。
mybatis和hibernate的優缺點
Hibernate的優點:
1、hibernate是全自動,hibernate完全可以通過對象關系模型實現對數據庫的操作,擁有完整的JavaBean對象與數據庫的映射結構來自動生成sql。
2、數據庫移植性良好。
Hibernate的缺點:
1、學習門檻高,精通門檻更高,程序員如何設計O/R映射,在性能和對象模型之間如何取得平衡,以及怎樣用好Hibernate方面需要的經驗和能力都很強才行
2、hibernate的sql很多都是自動生成的,無法直接維護sql;雖然有hql查詢,但功能還是不及sql強大,見到報表等變態需求時,hql查詢要虛,也就是說hql查詢是有局限的;hibernate雖然也支持原生sql查詢,但開發模式上卻與orm不同,需要轉換思維,因此使用上有些不方便。總之寫sql的靈活度上hibernate不及mybatis。
Mybatis的優點:
1、易於上手和掌握,提供了數據庫查詢的自動對象綁定功能,而且延續了很好的SQL使用經驗,對於沒有那么高的對象模型要求的項目來說,相當完美。
2、sql寫在xml里,便於統一管理和優化, 解除sql與程序代碼的耦合。
3、提供xml標簽,支持編寫動態sql。
4、速度相對於Hibernate的速度較快
Mybatis的缺點:
1、關聯表多時,字段多的時候,sql工作量很大。
2、sql依賴於數據庫,導致數據庫移植性差。
3、對象關系映射標簽和字段映射標簽僅僅是對映射關系的描述,具體實現仍然依賴於sql。
4、編寫動態sql時,不方便調試,尤其邏輯復雜時。
java線程池有哪些?線程池的原理,什么場景下不適用線程池
ThreadLocal的理解
向ThreadLocal里面存東西就是向它里面的Map存東西的,然后ThreadLocal把這個Map掛到當前的線程底下,這樣Map就僅僅屬於這個線程了。
mysql和oracle的區別
最重要的區別
MySQL是輕量型數據庫,並且免費,沒有服務恢復數據。
Oracle是重量型數據庫,收費,Oracle公司對Oracle數據庫有任何服務。
對事務的提交
MySQL默認是自動提交,而Oracle默認不自動提交,需要用戶手動提交,需要在寫commit;指令或者點擊commit按鈕
分頁查詢
MySQL是直接在SQL語句中寫"select... from ...where...limit x, y",有limit就可以實現分頁;而Oracle則是需要用到偽列ROWNUM和嵌套查詢
JVM
類加載的幾個過程
加載、驗證、准備、解析、初始化。然后是使用和卸載了
堆里面的分區:Eden,survival (from+ to),老年代,各自的特點?
堆里面分為新生代和老生代(java8取消了永久代,采用了Metaspace),新生代包含Eden+Survivor區,survivor區里面分為from和to區,內存回收時,如果用的是復制算法,從from復制到to,當經過一次或者多次GC之后,存活下來的對象會被移動到老年區,當JVM內存不夠用的時候,會觸發Full GC,清理JVM老年區
當新生區滿了之后會觸發YGC,先把存活的對象放到其中一個Survice
區,然后進行垃圾清理。因為如果僅僅清理需要刪除的對象,這樣會導致內存碎
片,因此一般會把Eden 進行完全的清理,然后整理內存。那么下次GC 的時候,
就會使用下一個Survive,這樣循環使用。如果有特別大的對象,新生代放不下,
就會使用老年代的擔保,直接放到老年代里面。因為JVM 認為,一般大對象的存
活時間一般比較久遠。
容器
HashMap 底層實現。
HashMap的底層通過位桶實現,位桶里面存的是鏈表(1.7以前)或者紅黑樹(有序,1.8開始) ,其實就是數組加鏈表(或者紅黑樹)的格式,通過判斷hashCode定位位桶中的下標,通過equals定位目標值在鏈表中的位置,,當添加一個元素(key-value)時,就首先計算元素key的hash值,以此確定插入數組中的位置,但是可能存在同一hash值的元素已經被放在數組同一位置了,這時就添加到同一hash值的元素的后面,他們在數組的同一位置,但是形成了鏈表,同一各鏈表上的Hash值是相同的,所以說數組存放的是鏈表。而當鏈表長度太長時,鏈表就轉換為紅黑樹,這樣大大提高了查找的效率。
當鏈表數組的容量超過初始容量的0.75時,再散列將鏈表數組擴大2倍,把原鏈表數組的搬移到新的數組中。
HasMap的擴容機制resize()?
構造hash表時,如果不指明初始大小,默認大小為16(即Node數組大小16),如果Node[]數組中的元素達到(填充比*Node.length)重新調整HashMap大小 變為原來2倍大小,擴容很耗時
什么時候擴容:當向容器添加元素的時候,會判斷當前容器的元素個數,如果大於等於閾值---即當前數組的長度乘以加載因子的值的時候,就要自動擴容啦。
擴容(resize)就是重新計算容量,向HashMap對象里不停的添加元素,而HashMap對象內部的數組無法裝載更多的元素時,對象就需要擴大數組的長度,以便能裝入更多的元素。方法是使用一個新的數組代替已有的容量小的數組,就像我們用一個小桶裝水,如果想裝更多的水,就得換大水桶。
Linux系統查看當前運行java的進程?
在Linux下查看所有java進程命令:ps -ef | grep java
停止特定java進程命令:kill -9 java進程序號
停止所有java進程命令:pkill - 9 java
HashSet類是如何實現添加元素保證不重復的?---哈希碼的原理
當你利用HashSet創建一個對象時,在HashSet的構造方法中,先用hashCode方法計算出該對象的哈希碼。
比較順序以及原理
(1).如果該對象哈希碼與集合已存在對象的哈希碼不一致,則該對象沒有與其他對象重復,添加到集合中!
(2).如果存在於該對象相同的哈希碼,那么通過equals方法判斷兩個哈希碼相同的對象是否為同一對象(判斷的標准是:屬性是否相同)
1>.相同對象,不添加!
2>.不同對象,添加!
final finally finalize區別
1、final修飾符(關鍵字)。被final修飾的類,就意味着不能再派生出新的子類,不能作為父類而被子類繼承
2、finally是在異常處理時提供finally塊來執行任何清除操作。不管有沒有異常被拋出、捕獲,finally塊都會被執行
3、finalize是方法名。在垃圾收集器刪除對象之前對這個對象調用的,將對象從內存中清除出去之前做必要的清理工作。
一 反射機制的概念:
指在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法,對於任意一個對象,都能調用它的任意一個方法.這種動態獲取信息,以及動態調用對象方法的功能叫java語言的反射機制.
二 反射機制的應用:
生成動態代理,面向切片編程(在調用方法的前后各加棧幀).
三 反射機制的原理:
1 首先明確的概念: 一切皆對象----類也是對象.
2 然后知道類中的內容 :modifier constructor field method.
3 其次明白加載: 當Animal.class在硬盤中時,是一個文件,當載入到內存中,可以認為是一個對象,是java.lang.class的對象.
Hash沖突?
由於哈希算法被計算的數據是無限的,而計算后的結果范圍有限,因此總會存在不同的數據經過計算后得到的值相同,這就是哈希沖突
Spring框架分為哪七大模塊以及各模塊的主要功能作用?
1. Spring Core: Core封裝包是框架的最基礎部分,提供IOC和依賴注入特性。這里的基礎概念是BeanFactory,它提供對Factory模式的經典實現來消除對程序性單例模式的需要,並真正地允許你從程序邏輯中分離出依賴關系和配置。
2.Spring Context: 構建於Core封裝包基礎上的 Context封裝包,提供了一種框架式的對象訪問方法,有些象JNDI注冊器。Context封裝包的特性得自於Beans封裝包,並添加了對國際化(I18N)的支持(例如資源綁定),事件傳播,資源裝載的方式和Context的透明創建,比如說通過Servlet容器。
3.Spring DAO: DAO (Data Access Object)提供了JDBC的抽象層,它可消除冗長的JDBC編碼和解析數據庫廠商特有的錯誤代碼。 並且,JDBC封裝包還提供了一種比編程性更好的聲明性事務管理方法,不僅僅是實現了特定接口,而且對所有的POJOs(plain old Java objects)都適用。
4.Spring ORM: ORM 封裝包提供了常用的“對象/關系”映射APIs的集成層。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封裝包,可以混合使用所有Spring提供的特性進行“對象/關系”映射,如前邊提到的簡單聲明性事務管理。
5.Spring AOP: Spring的 AOP 封裝包提供了符合AOP Alliance規范的面向方面的編程實現,讓你可以定義,例如方法攔截器(method-interceptors)和切點(pointcuts),從邏輯上講,從而減弱代碼的功能耦合,清晰的被分離開。而且,利用source-level的元數據功能,還可以將各種行為信息合並到你的代碼中。
6.Spring Web: Spring中的 Web 包提供了基礎的針對Web開發的集成特性,例如多方文件上傳,利用Servlet listeners進行IOC容器初始化和針對Web的ApplicationContext。當與WebWork或Struts一起使用Spring時,這個包使Spring可與其他框架結合。
7.Spring Web MVC: Spring中的MVC封裝包提供了Web應用的Model-View-Controller(MVC)實現。Spring的MVC框架並不是僅僅提供一種傳統的實現,它提供了一種清晰的分離模型,在領域模型代碼和Web Form之間。並且,還可以借助Spring框架的其他特性。