招銀網絡java軟開面經

目錄css

 

一面:html

多態實現前端

生產者消費者手寫java

SQL查詢語句手寫nginx

Mybatis批量查詢手寫web

HashMap,HashTable,ConcurrentHashmap區別,底層源碼面試

HashTableredis

HashMap算法

ConcurrentHashMapspring

內存泄漏的狀況有哪些

classpath,path的區別

JVM運行過程

GC機制講一講

線程池,阻塞隊列

二面:

http ,https區別

分佈式dubbo講一下了解

項目介紹

非對稱加密和對稱加密

如何設計一個服務器(socket相關)

eclipse、IJ開發快捷鍵及使用技巧講幾個

如何使得瀏覽器加載請求能夠穩定打到後臺而不使用瀏覽器緩存(請求中加一個隨機值參數)

spring事務寫在哪一部分,爲何不寫在DAO,Controller層

數據庫驅動爲何使用反射調用不直接new


一面:

多態實現

  多態的概念:同一操做做用於不一樣對象,能夠有不一樣的解釋,有不一樣的執行結果,這就是多態,簡單來講就是:父類的引用指向子類對象。下面先看一段代碼

 

1 package polymorphism;
 2 
 3 class Dance {
 4     public void play(){
 5         System.out.println("Dance.play");
 6     }
 7     public void play(int i){
 8         System.out.println("Dance.play" + i);
 9     }
10 }
11 
12 class Latin extends Dance {
13     public void play(){
14         System.out.println("Latin.play");
15     }
16     public void play(char c){
17         System.out.println("Latin.play" + c);
18     }
19 }
20 class Jazz extends Dance {
21     public void play(){
22         System.out.println("Jazz.play");
23     }
24     public void play(double d){
25         System.out.println("Jazz.play" + d);
26     }
27 }
28 public class Test {
29     public void perform(Dance dance){
30         dance.play();
31     }
32     public static void main(String[] args){
33         new Test().perform(new Latin()); // Upcasting
34     }
35 }
  執行結果:Latin.play。這個時候你可能會發現perform()方法裏面並無相似「if 參數類型 = Dance/Latin」這樣的判斷,其實這就是多態的特性,它消除了類型之間的耦合關係,令咱們能夠把一個對象不當作它所屬的特定類型來對待,而是當作其基類的類型來對待。由於上面的Test代碼徹底能夠這麼寫:
 1 public class Test {
 2     public void perform(Latin dance){
 3         dance.play();
 4     }
 5     public void perform(Jazz dance){
 6         dance.play();
 7     }
 8     public static void main(String[] args){
 9         new Test().perform(new Latin()); // Upcasting
10     }
11 }
可是這樣你會發現,若是增長更多新的相似perform()或者自Dance導出的新類,就會增長大量的工做,而經過比較就會知道第一處代碼會佔優點,這正是多態的優勢所在,它改善了代碼的組織結構和可讀性,同時保證了可擴展性。

  那麼到底JVM是怎麼指向Latin類中play()的呢?爲了解決這個問題,JAVA使用了後期綁定的概念。當向對象發送消息時,在編譯階段,編譯器只保證被調用方法的存在,並對調用參數和返回類型進行檢查,可是並不知道將被執行的確切代碼,被調用的代碼直到運行時才能肯定。拿上面代碼爲例,JAVA在執行後期綁定時,JVM會從方法區中的Latin方法表中取到Latin對象的直接地址,這就是真正執行結果爲何是Latin.play的緣由,在解釋方法表以前,咱們先了解一下綁定的概念。

  將一個方法調用同一個方法主體關聯起來被稱做綁定,JAVA中分爲前期綁定和後期綁定(動態綁定或運行時綁定),在程序執行以前進行綁定(由編譯器和鏈接程序實現)叫作前期綁定,由於在編譯階段被調用方法的直接地址就已經存儲在方法所屬類的常量池中了,程序執行時直接調用,具體解釋請看最後參考資料地址。後期綁定含義就是在程序運行時根據對象的類型進行綁定,想實現後期綁定,就必須具備某種機制,以便在運行時能判斷對象的類型,從而找到對應的方法,簡言之就是必須在對象中安置某種「類型信」,JAVA中除了static方法、final方法(private方法屬於)以外,其餘的方法都是後期綁定。後期綁定會涉及到JVM管理下的一個重要的數據結構——方法表,方法表以數組的形式記錄當前類及其全部父類的可見方法字節碼在內存中的直接地址。

  動態綁定具體的調用過程爲:

    1.首先會找到被調用方法所屬類的全限定名

    2.在此類的方法表中尋找被調用方法,若是找到,會將方法表中此方法的索引項記錄到常量池中(這個過程叫常量池解析),若是沒有,編譯失敗。

    3.根據具體實例化的對象找到方法區中此對象的方法表,再找到方法表中的被調用方法,最後經過直接地址找到字節碼所在的內存空間。

生產者消費者手寫

方法一:

  1. package ProduceConsumer;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. public class Produce {  
  6.       
  7.     public Object object;  
  8.     public ArrayList<Integer> list;//用list存放生產以後的數據,最大容量爲1  
  9.               
  10.     public Produce(Object object,ArrayList<Integer> list ){  
  11.         this.object = object;  
  12.         this.list = list;  
  13.     }  
  14.       
  15.     public void produce() {  
  16.           
  17.         synchronized (object) {  
  18.             /*只有list爲空時纔會去進行生產操做*/  
  19.             try {  
  20.             while(!list.isEmpty()){  
  21.                     System.out.println("生產者"+Thread.currentThread().getName()+" waiting");  
  22.                     object.wait();  
  23.                 }   
  24.             int value = 9999;  
  25.             list.add(value);  
  26.             System.out.println("生產者"+Thread.currentThread().getName()+" Runnable");  
  27.             object.notifyAll();//而後去喚醒因object調用wait方法處於阻塞狀態的線程  
  28.         }catch (InterruptedException e) {  
  29.                 e.printStackTrace();  
  30.             }  
  31.         }  
  32.     }  
  33.   
  34. }  

 

[java] view plain copy

  1. package ProduceConsumer;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. public class Consumer {  
  6.       
  7.     public Object object;  
  8.     public ArrayList<Integer> list;//用list存放生產以後的數據,最大容量爲1  
  9.               
  10.     public Consumer(Object object,ArrayList<Integer> list ){  
  11.         this.object = object;  
  12.         this.list = list;  
  13.     }  
  14.       
  15.     public void consmer() {  
  16.           
  17.         synchronized (object) {  
  18.             try {  
  19.                 /*只有list不爲空時纔會去進行消費操做*/  
  20.                 while(list.isEmpty()){  
  21.                     System.out.println("消費者"+Thread.currentThread().getName()+" waiting");  
  22.                     object.wait();  
  23.                 }   
  24.             list.clear();  
  25.             System.out.println("消費者"+Thread.currentThread().getName()+" Runnable");  
  26.             object.notifyAll();//而後去喚醒因object調用wait方法處於阻塞狀態的線程  
  27.               
  28.         }catch (InterruptedException e) {  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32.     }  
  33.       
  34. }  

 

[java] view plain copy

  1. package ProduceConsumer;  
  2.   
  3. public class ProduceThread extends Thread {  
  4.     private Produce p;  
  5.     public ProduceThread(Produce p){  
  6.         this.p = p;  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         while (true) {  
  11.             p.produce();  
  12.         }  
  13.     }  
  14. }  

 

[java] view plain copy

  1. package ProduceConsumer;  
  2.   
  3. public class ConsumeThread extends Thread {  
  4.     private Consumer c;  
  5.     public ConsumeThread(Consumer c){  
  6.         this.c = c;  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         while (true) {  
  11.             c.consmer();  
  12.         }  
  13.     }  
  14. }  

 

[java] view plain copy

  1. package ProduceConsumer;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. public class Main {  
  6.     public static void main(String[] args) {  
  7.         Object object = new Object();  
  8.         ArrayList<Integer> list = new ArrayList<Integer>();  
  9.       
  10.         Produce p = new Produce(object, list);  
  11.         Consumer c = new Consumer(object, list);  
  12.           
  13.         ProduceThread[] pt = new ProduceThread[2];  
  14.         ConsumeThread[] ct = new ConsumeThread[2];  
  15.           
  16.         for(int i=0;i<2;i++){  
  17.             pt[i] = new ProduceThread(p);  
  18.             pt[i].setName("生產者 "+(i+1));  
  19.             ct[i] = new ConsumeThread(c);  
  20.             ct[i].setName("消費者"+(i+1));  
  21.             pt[i].start();  
  22.             ct[i].start();  
  23.         }  
  24.     }  
  25. }  


方法二:

 

[java] view plain copy

  1. package ProduceConsumer2;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. public class MyService {  
  6.       
  7.     public ArrayList<Integer> list = new ArrayList<Integer>();//用list存放生產以後的數據,最大容量爲1  
  8.     synchronized public void produce() {  
  9.               
  10.         try {  
  11.             /*只有list爲空時纔會去進行生產操做*/  
  12.             while(!list.isEmpty()){  
  13.                     System.out.println("生產者"+Thread.currentThread().getName()+" waiting");  
  14.                     this.wait();  
  15.                 }   
  16.             int value = 9999;  
  17.             list.add(value);  
  18.             System.out.println("生產者"+Thread.currentThread().getName()+" Runnable");  
  19.             this.notifyAll();//而後去喚醒因object調用wait方法處於阻塞狀態的線程  
  20.         }catch (InterruptedException e) {  
  21.                 e.printStackTrace();  
  22.             }  
  23.     }  
  24.       
  25.     synchronized public void consmer() {  
  26.         try {     
  27.             /*只有list不爲空時纔會去進行消費操做*/  
  28.             while(list.isEmpty()){  
  29.                     System.out.println("消費者"+Thread.currentThread().getName()+" waiting");  
  30.                     this.wait();  
  31.             }  
  32.             list.clear();  
  33.             System.out.println("消費者"+Thread.currentThread().getName()+" Runnable");  
  34.             this.notifyAll();//而後去喚醒因object調用wait方法處於阻塞狀態的線程  
  35.         } catch (InterruptedException e) {  
  36.             e.printStackTrace();  
  37.         }  
  38.     }  
  39.       
  40. }  

 

[java] view plain copy

  1. package ProduceConsumer2;  
  2.   
  3. public class ProduceThread extends Thread {  
  4.     private MyService p;  
  5.     public ProduceThread(MyService p){  
  6.         this.p = p;  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         while (true) {  
  11.             p.produce();  
  12.         }  
  13.     }  
  14. }  

 

[java] view plain copy

  1. package ProduceConsumer2;  
  2.   
  3. public class ConsumeThread extends Thread {  
  4.     private MyService c;  
  5.     public ConsumeThread(MyService c){  
  6.         this.c = c;  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         while (true) {  
  11.             c.consmer();  
  12.         }  
  13.     }  
  14. }  

 

用Lock和Condition實現

 

[java] view plain copy

  1. package ConditionProduceConsumer;  
  2.   
  3. import java.util.concurrent.locks.Condition;  
  4. import java.util.concurrent.locks.ReentrantLock;  
  5.   
  6. public class MyService {  
  7.       
  8.     private ReentrantLock lock = new ReentrantLock();  
  9.     private Condition condition = lock.newCondition();  
  10.     private boolean hasValue = false;  
  11.       
  12.       
  13.      public void produce() {  
  14.         lock.lock();  
  15.         try {  
  16.             /*只有list爲空時纔會去進行生產操做*/  
  17.             while(hasValue == true){  
  18.                 System.out.println("生產者"+Thread.currentThread().getName()+" waiting");  
  19.                 condition.await();  
  20.             }  
  21.             hasValue = true;  
  22.             System.out.println("生產者"+Thread.currentThread().getName()+" Runnable");  
  23.             condition.signalAll();//而後去喚醒因object調用wait方法處於阻塞狀態的線程  
  24.         } catch (InterruptedException e) {  
  25.             e.printStackTrace();  
  26.         }finally{  
  27.             lock.unlock();  
  28.         }  
  29.               
  30.     }  
  31.       
  32.      public void consmer() {  
  33.         lock.lock();  
  34.         try {  
  35.             /*只有list爲空時纔會去進行生產操做*/  
  36.             while(hasValue == false){  
  37.                 System.out.println("消費者"+Thread.currentThread().getName()+" waiting");  
  38.                 condition.await();  
  39.             }  
  40.             hasValue = false;  
  41.             System.out.println("消費者"+Thread.currentThread().getName()+" Runnable");  
  42.             condition.signalAll();//而後去喚醒因object調用wait方法處於阻塞狀態的線程  
  43.         } catch (InterruptedException e) {  
  44.             e.printStackTrace();  
  45.         }finally{  
  46.             lock.unlock();  
  47.         }  
  48.       
  49.     }  
  50. }  

 

[java] view plain copy

  1. package ConditionProduceConsumer;  
  2.   
  3. public class ProduceThread extends Thread {  
  4.     private MyService p;  
  5.     public ProduceThread(MyService p){  
  6.         this.p = p;  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         while (true) {  
  11.             p.produce();  
  12.         }  
  13.     }  
  14. }  

[java] view plain copy

  1. package ConditionProduceConsumer;  
  2.   
  3. public class ConsumeThread extends Thread {  
  4.     private MyService c;  
  5.     public ConsumeThread(MyService c){  
  6.         this.c = c;  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         while (true) {  
  11.             c.consmer();  
  12.         }  
  13.     }  
  14. }  

 

[java] view plain copy

  1. package ConditionProduceConsumer;  
  2.   
  3.   
  4. public class Main {  
  5.     public static void main(String[] args) {  
  6.   
  7.         MyService service = new MyService();  
  8.           
  9.         ProduceThread[] pt = new ProduceThread[2];  
  10.         ConsumeThread[] ct = new ConsumeThread[2];  
  11.           
  12.         for(int i=0;i<1;i++){  
  13.             pt[i] = new ProduceThread(service);  
  14.             pt[i].setName("Condition 生產者 "+(i+1));  
  15.             ct[i] = new ConsumeThread(service);  
  16.             ct[i].setName("Condition 消費者"+(i+1));  
  17.             pt[i].start();  
  18.             ct[i].start();  
  19.         }  
  20.     }  
  21. }  

SQL查詢語句手寫

1. 用一條SQL 語句 查詢出每門課都大於80 分的學生姓名

name   kecheng   fenshu 
張三     語文       81
張三     數學       75
李四     語文       76
李四     數學       90
王五     語文       81
王五     數學       100
王五     英語       90

A: select distinct name from table where name not in (select distinct name from table where fenshu<=80)
select name from table group by name having min(fenshu)>80


2. 學生表 以下:
自動編號   學號   姓名 課程編號 課程名稱 分數
1        2005001 張三 0001      數學    69
2        2005002 李四 0001      數學    89
3        2005001 張三 0001      數學    69
刪除除了自動編號不一樣, 其餘都相同的學生冗餘信息

A: delete tablename where 自動編號 not in(select min( 自動編號) from tablename group by 學號, 姓名, 課程編號, 課程名稱, 分數)

3. 一個叫 team 的表,裏面只有一個字段name, 一共有4 條紀錄,分別是a,b,c,d, 對應四個球對,如今四個球對進行比賽,用一條sql 語句顯示全部可能的比賽組合.
你先按你本身的想法作一下,看結果有個人這個簡單嗎?

答:select a.name, b.name 
from team a, team b 
where a.name < b.name

4. 請用SQL 語句實現:從TestDB 數據表中查詢出全部月份的發生額都比101 科目相應月份的發生額高的科目。請注意:TestDB 中有不少科目,都有1 -12 月份的發生額。
AccID :科目代碼,Occmonth :發生額月份,DebitOccur :發生額。
數據庫名:JcyAudit ,數據集:Select * from TestDB

答:select a.*
from TestDB a 
,(select Occmonth,max(DebitOccur) Debit101ccur from TestDB where AccID='101' group by Occmonth) b
where a.Occmonth=b.Occmonth and a.DebitOccur>b.Debit101ccur

************************************************************************************

5. 面試題:怎麼把這樣一個表兒
year   month amount
1991   1     1.1
1991   2     1.2
1991   3     1.3
1991   4     1.4
1992   1     2.1
1992   2     2.2
1992   3     2.3
1992   4     2.4
查成這樣一個結果
year m1   m2   m3   m4
1991 1.1 1.2 1.3 1.4
1992 2.1 2.2 2.3 2.4 

答案1、
select year, 
(select amount from   aaa m where month=1   and m.year=aaa.year) as m1,
(select amount from   aaa m where month=2   and m.year=aaa.year) as m2,
(select amount from   aaa m where month=3   and m.year=aaa.year) as m3,
(select amount from   aaa m where month=4   and m.year=aaa.year) as m4
from aaa   group by year

*******************************************************************************
6.
 說明:複製表( 只複製結構, 源表名:a 新表名:b) 

SQL: select * into b from a where 1<>1       (where1=1,拷貝表結構和數據內容)
ORACLE:create table b

As

Select * from a where 1=2

 

[<>(不等於)(SQL Server Compact)

 

 

比較兩個表達式。 當使用此運算符比較非空表達式時,若是左操做數不等於右操做數,則結果爲 TRUE。 不然,結果爲 FALSE。]

 


7. 說明:拷貝表( 拷貝數據, 源表名:a 目標表名:b) 

SQL: insert into b(a, b, c) select d,e,f from a; 

8. 說明:顯示文章、提交人和最後回覆時間 
SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b 

9. 說明:外鏈接查詢( 表名1 :a 表名2 :b) 

SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUTER JOIN b ON a.a = b.c

ORACLE :select a.a, a.b, a.c, b.c, b.d, b.f from a ,b

where a.a = b.c(+)

10.
 說明:日程安排提早五分鐘提醒 
SQL: select * from 日程安排 where datediff('minute',f 開始時間,getdate())>5 

11. 說明:兩張關聯表,刪除主表中已經在副表中沒有的信息 

SQL: 
Delete from info where not exists (select * from infobz where info.infid=infobz.infid ) 


*******************************************************************************

12. 有兩個表A 和B ,均有key 和value 兩個字段,若是B 的key 在A 中也有,就把B 的value 換爲A 中對應的value
這道題的SQL 語句怎麼寫?

update b set b.value=(select a.value from a where a.key=b.key) where b.id in(select b.id from b,a where b.key=a.key);

***************************************************************************

 

13. 高級sql 面試題

原表: 
courseid coursename score 
------------------------------------- 
1 java 70 
2 oracle 90 
3 xml 40 
4 jsp 30 
5 servlet 80 
------------------------------------- 
爲了便於閱讀, 查詢此表後的結果顯式以下( 及格分數爲60): 
courseid coursename score mark 
--------------------------------------------------- 
1 java 70 pass 
2 oracle 90 pass 
3 xml 40 fail 
4 jsp 30 fail 
5 servlet 80 pass 
--------------------------------------------------- 
寫出此查詢語句


select courseid, coursename ,score ,decode (sign(score-60),-1,'fail','pass') as mark from course

徹底正確 

SQL> desc course_v 
Name Null? Type 
----------------------------------------- -------- ---------------------------- 
COURSEID NUMBER 
COURSENAME VARCHAR2(10) 
SCORE NUMBER 

SQL> select * from course_v; 

COURSEID COURSENAME SCORE 
---------- ---------- ---------- 
1 java 70 
2 oracle 90 
3 xml 40 
4 jsp 30 
5 servlet 80 

SQL> select courseid, coursename ,score ,decode(sign(score-60),-1,'fail','pass') as mark from course_v; 

COURSEID COURSENAME SCORE MARK 
---------- ---------- ---------- ---- 
1 java 70 pass 
2 oracle 90 pass 
3 xml 40 fail 
4 jsp 30 fail 
5 servlet 80 pass

SQL面試題(1)

create table testtable1
(
id int IDENTITY,
department varchar(12) 
)

select * from testtable1
insert into testtable1 values('設計')
insert into testtable1 values('市場')
insert into testtable1 values('售後')
/*
結果
id department
1   設計
2   市場
3   售後 
*/
create table testtable2
(
id int IDENTITY,
dptID int,
name varchar(12)
)
insert into testtable2 values(1,'張三')
insert into testtable2 values(1,'李四')
insert into testtable2 values(2,'王五')
insert into testtable2 values(3,'彭六')
insert into testtable2 values(4,'陳七')
/*
用一條SQL語句,怎麼顯示以下結果
id dptID department name
1   1      設計        張三
2   1      設計        李四
3   2      市場        王五
4   3      售後        彭六
5   4      黑人        陳七
*/

答案:

SELECT testtable2.* , ISNULL(department,'黑人')
FROM testtable1 right join testtable2 on testtable2.dptID = testtable1.ID

也作出來了可比這方法稍複雜。

sql面試題(2)

有表A,結構以下: 
A: p_ID p_Num s_id 
1 10 01 
1 12 02 
2 8 01 
3 11 01 
3 8 03 
其中:p_ID爲產品ID,p_Num爲產品庫存量,s_id爲倉庫ID。請用SQL語句實現將上表中的數據合併,合併後的數據爲: 
p_ID s1_id s2_id s3_id 
1 10 12 0 
2 8 0 0 
3 11 0 8 
其中:s1_id爲倉庫1的庫存量,s2_id爲倉庫2的庫存量,s3_id爲倉庫3的庫存量。若是該產品在某倉庫中無庫存量,那麼就是0代替。

結果:

select p_id ,
sum(case when s_id=1 then p_num else 0 end) as s1_id
,sum(case when s_id=2 then p_num else 0 end) as s2_id
,sum(case when s_id=3 then p_num else 0 end) as s3_id
from myPro group by p_id

SQL面試題(3)

1 .觸發器的做用?

   答:觸發器是一中特殊的存儲過程,主要是經過事件來觸發而被執行的。它能夠強化約束,來維護數據的完整性和一致性,能夠跟蹤數據庫內的操做從而不容許未經許可的更新和變化。能夠聯級運算。如,某表上的觸發器上包含對另外一個表的數據操做,而該操做又會致使該表觸發器被觸發。

2 。什麼是存儲過程?用什麼來調用?

答:存儲過程是一個預編譯的 SQL 語句,優勢是容許模塊化的設計,就是說只需建立一次,之後在該程序中就能夠調用屢次。若是某次操做須要執行屢次 SQL ,使用存儲過程比單純 SQL 語句執行要快。能夠用一個命令對象來調用存儲過程。

3 。索引的做用?和它的優勢缺點是什麼?

答:索引就一種特殊的查詢表,數據庫的搜索引擎能夠利用它加速對數據的檢索。它很相似與現實生活中書的目錄,不須要查詢整本書內容就能夠找到想要的數據。索引能夠是惟一的,建立索引容許指定單個列或者是多個列。缺點是它減慢了數據錄入的速度,同時也增長了數據庫的尺寸大小。

3 。什麼是內存泄漏?

答:通常咱們所說的內存泄漏指的是堆內存的泄漏。堆內存是程序從堆中爲其分配的,大小任意的,使用完後要顯示釋放內存。當應用程序用關鍵字 new 等建立對象時,就從堆中爲它分配一塊內存,使用完後程序調用 free 或者 delete 釋放該內存,不然就說該內存就不能被使用,咱們就說該內存被泄漏了。

4 。維護數據庫的完整性和一致性,你喜歡用觸發器仍是自寫業務邏輯?爲何?

答:我是這樣作的,儘量使用約束,如 check, 主鍵,外鍵,非空字段等來約束,這樣作效率最高,也最方便。其次是使用觸發器,這種方法能夠保證,不管什麼業務系統訪問數據庫均可以保證數據的完整新和一致性。最後考慮的是自寫業務邏輯,但這樣作麻煩,編程複雜,效率低下。

5 。什麼是事務?什麼是鎖?

答:事務就是被綁定在一塊兒做爲一個邏輯工做單元的 SQL 語句分組,若是任何一個語句操做失敗那麼整個操做就被失敗,之後操做就會回滾到操做前狀態,或者是上有個節點。爲了確保要麼執行,要麼不執行,就能夠使用事務。要將有組語句做爲事務考慮,就須要經過 ACID 測試,即原子性,一致性,隔離性和持久性。

   鎖:在因此的 DBMS 中,鎖是實現事務的關鍵,鎖能夠保證事務的完整性和併發性。與現實生活中鎖同樣,它能夠使某些數據的擁有者,在某段時間內不能使用某些數據或數據結構。固然鎖還分級別的。

6 。什麼叫視圖?遊標是什麼?

答:視圖是一種虛擬的表,具備和物理表相同的功能。能夠對視圖進行增,改,查,操做,試圖一般是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得咱們獲取數據更容易,相比多表查詢。

   遊標:是對查詢出來的結果集做爲一個單元來有效的處理。遊標能夠定在該單元中的特定行,從結果集的當前行檢索一行或多行。能夠對結果集當前行作修改。通常不使用遊標,可是須要逐條處理數據的時候,遊標顯得十分重要。

7。爲管理業務培訓信息,創建3個表:

     S(S#,SN,SD,SA)S#,SN,SD,SA分別表明學號,學員姓名,所屬單位,學員年齡

     C(C#,CN)C#,CN分別表明課程編號,課程名稱

      SC(S#,C#,G) S#,C#,G分別表明學號,所選的課程編號,學習成績

    (1)使用標準SQL嵌套語句查詢選修課程名稱爲’稅收基礎’的學員學號和姓名?

          答案:select s# ,sn from s where S# in(select S# from c,sc where c.c#=sc.c# and cn=’稅收基礎’)

      (2) 使用標準SQL嵌套語句查詢選修課程編號爲’C2’的學員姓名和所屬單位?

答:select sn,sd from s,sc where s.s#=sc.s# and sc.c#=’c2’

      (3) 使用標準SQL嵌套語句查詢不選修課程編號爲’C5’的學員姓名和所屬單位?

答:select sn,sd from s where s# not in(select s# from sc where c#=’c5’)

       (4)查詢選修了課程的學員人數

答:select 學員人數=count(distinct s#) from sc

       (5) 查詢選修課程超過5門的學員學號和所屬單位?

答:select sn,sd from s where s# in(select s# from sc group by s# having count(distinct c#)>5)

SQL面試題(4)

1.查詢A(ID,Name)表中第31至40條記錄,ID做爲主鍵多是不是連續增加的列,完整的查詢語句以下:

select top 10 * from A where ID >(select max(ID) from (select top 30 ID from A order by A ) T) order by A

2.查詢表A中存在ID重複三次以上的記錄,完整的查詢語句以下:
select * from(select count(ID) as count from table group by ID)T where T.count>3

SQL面試題(5)

在面試應聘的SQL Server數據庫開發人員時,我運用了一套標準的基準技術問題。下面這些問題是我以爲可以真正有助於淘汰不合格應聘者的問題。它們按照從易到難的順序排列。當你問到關於主鍵和外鍵的問題時,後面的問題都十分有難度,由於答案可能會更難解釋和說明,尤爲是在面試的情形下。

你能向我簡要敘述一下SQL Server 2000中使用的一些數據庫對象嗎?

你但願聽到的答案包括這樣一些對象:表格、視圖、用戶定義的函數,以及存儲過程;若是他們還可以提到像觸發器這樣的對象就更好了。若是應聘者不能回答這個基本的問題,那麼這不是一個好兆頭。

NULL是什麼意思?

NULL(空)這個值是數據庫世界裏一個很是難纏的東西,因此有很多應聘者會在這個問題上跌跟頭您也不要以爲意外。

NULL這個值表示UNKNOWN(未知):它不表示「」(空字符串)。假設您的SQL Server數據庫裏有ANSI_NULLS,固然在默認狀況下會有,對NULL這個值的任何比較都會生產一個NULL值。您不能把任何值與一個 UNKNOWN值進行比較,並在邏輯上但願得到一個答案。您必須使用IS NULL操做符。

什麼是索引?SQL Server 2000裏有什麼類型的索引?

任何有經驗的數據庫開發人員都應該可以很輕易地回答這個問題。一些經驗不太多的開發人員可以回答這個問題,可是有些地方會說不清楚。

簡單地說,索引是一個數據結構,用來快速訪問數據庫表格或者視圖裏的數據。在SQL Server裏,它們有兩種形式:彙集索引和非彙集索引。彙集索引在索引的葉級保存數據。這意味着不論彙集索引裏有表格的哪一個(或哪些)字段,這些字段都會按順序被保存在表格。因爲存在這種排序,因此每一個表格只會有一個彙集索引。非彙集索引在索引的葉級有一個行標識符。這個行標識符是一個指向磁盤上數據的指針。它容許每一個表格有多個非彙集索引。

什麼是主鍵?什麼是外鍵?

主鍵是表格裏的(一個或多個)字段,只用來定義表格裏的行;主鍵裏的值老是惟一的。外鍵是一個用來創建兩個表格之間關係的約束。這種關係通常都涉及一個表格裏的主鍵字段與另一個表格(儘管多是同一個表格)裏的一系列相連的字段。那麼這些相連的字段就是外鍵。

什麼是觸發器?SQL Server 2000有什麼不一樣類型的觸發器?

讓將來的數據庫開發人員知道可用的觸發器類型以及如何實現它們是很是有益的。

觸發器是一種專用類型的存儲過程,它被捆綁到SQL Server 2000的表格或者視圖上。在SQL Server 2000裏,有INSTEAD-OF和AFTER兩種觸發器。INSTEAD-OF觸發器是替代數據操控語言(Data Manipulation Language,DML)語句對錶格執行語句的存儲過程。例如,若是我有一個用於TableA的INSTEAD-OF-UPDATE觸發器,同時對這個表格執行一個更新語句,那麼INSTEAD-OF-UPDATE觸發器裏的代碼會執行,而不是我執行的更新語句則不會執行操做。

AFTER觸發器要在DML語句在數據庫裏使用以後才執行。這些類型的觸發器對於監視發生在數據庫表格裏的數據變化十分好用。

您如何確一個帶有名爲Fld1字段的TableB表格裏只具備Fld1字段裏的那些值,而這些值同時在名爲TableA的表格的Fld1字段裏?

這個與關係相關的問題有兩個可能的答案。第一個答案(並且是您但願聽到的答案)是使用外鍵限制。外鍵限制用來維護引用的完整性。它被用來確保表格裏的字段只保存有已經在不一樣的(或者相同的)表格裏的另外一個字段裏定義了的值。這個字段就是候選鍵(一般是另一個表格的主鍵)。

另一種答案是觸發器。觸發器能夠被用來保證以另一種方式實現與限制相同的做用,可是它很是難設置與維護,並且性能通常都很糟糕。因爲這個緣由,微軟建議開發人員使用外鍵限制而不是觸發器來維護引用的完整性。

對一個投入使用的在線事務處理表格有過多索引須要有什麼樣的性能考慮?

你正在尋找進行與數據操控有關的應聘人員。對一個表格的索引越多,數據庫引擎用來更新、插入或者刪除數據所須要的時間就越多,由於在數據操控發生的時候索引也必需要維護。

你能夠用什麼來確保表格裏的字段只接受特定範圍裏的值?

這個問題能夠用多種方式來回答,可是隻有一個答案是「好」答案。您但願聽到的回答是Check限制,它在數據庫表格裏被定義,用來限制輸入該列的值。

觸發器也能夠被用來限制數據庫表格裏的字段可以接受的值,可是這種辦法要求觸發器在表格裏被定義,這可能會在某些狀況下影響到性能。所以,微軟建議使用Check限制而不是其餘的方式來限制域的完整性。

若是應聘者可以正確地回答這個問題,那麼他的機會就很是大了,由於這代表他們具備使用存儲過程的經驗。

返回參數老是由存儲過程返回,它用來表示存儲過程是成功仍是失敗。返回參數老是INT數據類型。

OUTPUT參數明確要求由開發人員來指定,它能夠返回其餘類型的數據,例如字符型和數值型的值。(能夠用做輸出參數的數據類型是有一些限制的。)您能夠在一個存儲過程裏使用多個OUTPUT參數,而您只可以使用一個返回參數。

什麼是相關子查詢?如何使用這些查詢?

經驗更加豐富的開發人員將可以準確地描述這種類型的查詢。

相關子查詢是一種包含子查詢的特殊類型的查詢。查詢裏包含的子查詢會真正請求外部查詢的值,從而造成一個相似於循環的情況。

SQL面試題(6)

原表: 
courseid coursename score 
------------------------------------- 
1 java 70 
2 oracle 90 
3 xml 40 
4 jsp 30 
5 servlet 80 
------------------------------------- 
爲了便於閱讀,查詢此表後的結果顯式以下(及格分數爲60): 
courseid coursename score mark 
--------------------------------------------------- 
1 java 70 pass 
2 oracle 90 pass 
3 xml 40 fail 
4 jsp 30 fail 
5 servlet 80 pass 
--------------------------------------------------- 
寫出此查詢語句 

ORACLE : select courseid, coursename ,score ,decode(sign(score-60),-1,'fail','pass') as mark from course

(DECODE函數是ORACLE PL/SQL是功能強大的函數之一,目前還只有ORACLE公司的SQL提供了此函數)

(SQL: select courseid, coursename ,score ,(case when score<60 then 'fail' else 'pass' end) as mark from course )

Mybatis批量查詢手寫

個人需求是查出每一個球隊中的助攻數最多的球員信息。

最開始使用配置的sql是:


<select id="selectMaxAssistListByTeamId" resultMap="BaseResultMap" parameterType="java.util.List" >
         
  select 
    <include refid="Base_Column_List" />
    from tab_player
    where  team_id in
    <foreach collection="list" item="item" index="index" separator=","  open="(" close=")">
          #{item,jdbcType=VARCHAR} 
        </foreach>
        Order By assist desc limit 1
  </select>

這個SQL只能查出一條記錄,顯然不合邏輯。應該把order by移進foreach,一塊兒循環:

<select id="selectMaxAssistListByTeamId" resultMap="BaseResultMap" parameterType="java.util.List" >
         
  select 
    <include refid="Base_Column_List" />
    from tab_player
    where  
    <foreach collection="list" item="item" index="index" separator="," >
         team_id = #{item,jdbcType=VARCHAR} Order By assist desc limit 1
        </foreach>
        
  </select>
仍是不行,報錯:...Exception:Undeclared variable:team_id.

百度無結果,都是用的in,顯然不合個人要求,應該把in換掉。想了想,其實tab_player這個表裏team_id

都是關聯自tab_team這個表的team_id,用in的話不可是畫蛇添足而且插敘速度還很慢。

應該繼續改進第二個sql
換個思惟:

用union!把separator的逗號改爲UNION,而且要用括號()把sql包起來,否則報錯:Incorrect usage of UNION and ORDER BY.


<select id="selectMaxAssistListByTeamId" resultMap="BaseResultMap" parameterType="java.util.List" >
         <foreach collection="list" item="item" index="index" separator="UNION" >
      (select 
    <include refid="Base_Column_List" />
    from tab_xsj_player
    where  
         team_id = #{item,jdbcType=VARCHAR} Order By assist desc limit 1)
        </foreach>
        
  </select>


本方法用的是union,有用in能查出來的請獻出你的想法你們共同窗習!

HashMap,HashTable,ConcurrentHashmap區別,底層源碼

HashTable

  • 底層數組+鏈表實現,不管key仍是value都不能爲null,線程安全,實現線程安全的方式是在修改數據時鎖住整個HashTable,效率低,ConcurrentHashMap作了相關優化
  • 初始size爲11,擴容:newsize = olesize*2+1
  • 計算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap

  • 底層數組+鏈表實現,可以存儲null鍵和null值,線程不安全
  • 初始size爲16,擴容:newsize = oldsize*2,size必定爲2的n次冪
  • 擴容針對整個Map,每次擴容時,原來數組中的元素依次從新計算存放位置,並從新插入
  • 插入元素後才判斷該不應擴容,有可能無效擴容(插入後若是擴容,若是沒有再次插入,就會產生無效擴容)
  • 當Map中元素總數超過Entry數組的75%,觸發擴容操做,爲了減小鏈表長度,元素分配更均勻
  • 計算index方法:index = hash & (tab.length – 1)

 

HashMap的初始值還要考慮加載因子:

  •  哈希衝突:若干Key的哈希值按數組大小取模後,若是落在同一個數組下標上,將組成一條Entry鏈,對Key的查找須要遍歷Entry鏈上的每一個元素執行equals()比較。
  • 加載因子:爲了下降哈希衝突的機率,默認當HashMap中的鍵值對達到數組大小的75%時,即會觸發擴容。所以,若是預估容量是100,即須要設定100/0.75=134的數組大小。
  • 空間換時間:若是但願加快Key查找的時間,還能夠進一步下降加載因子,加大初始大小,以下降哈希衝突的機率。

HashMap和Hashtable都是用hash算法來決定其元素的存儲,所以HashMap和Hashtable的hash表包含以下屬性:

  • 容量(capacity):hash表中桶的數量
  • 初始化容量(initial capacity):建立hash表時桶的數量,HashMap容許在構造器中指定初始化容量
  • 尺寸(size):當前hash表中記錄的數量
  • 負載因子(load factor):負載因子等於「size/capacity」。負載因子爲0,表示空的hash表,0.5表示半滿的散列表,依此類推。輕負載的散列表具備衝突少、適宜插入與查詢的特色(可是使用Iterator迭代元素時比較慢)

除此以外,hash表裏還有一個「負載極限」,「負載極限」是一個0~1的數值,「負載極限」決定了hash表的最大填滿程度。當hash表中的負載因子達到指定的「負載極限」時,hash表會自動成倍地增長容量(桶的數量),並將原有的對象從新分配,放入新的桶內,這稱爲rehashing。

HashMap和Hashtable的構造器容許指定一個負載極限,HashMap和Hashtable默認的「負載極限」爲0.75,這代表當該hash表的3/4已經被填滿時,hash表會發生rehashing。

「負載極限」的默認值(0.75)是時間和空間成本上的一種折中:

  • 較高的「負載極限」能夠下降hash表所佔用的內存空間,但會增長查詢數據的時間開銷,而查詢是最頻繁的操做(HashMap的get()與put()方法都要用到查詢)
  • 較低的「負載極限」會提升查詢數據的性能,但會增長hash表所佔用的內存開銷

程序猿能夠根據實際狀況來調整「負載極限」值。

ConcurrentHashMap

  • 底層採用分段的數組+鏈表實現,線程安全
  • 經過把整個Map分爲N個Segment,能夠提供相同的線程安全,可是效率提高N倍,默認提高16倍。(讀操做不加鎖,因爲HashEntry的value變量是 volatile的,也能保證讀取到最新的值。)
  • Hashtable的synchronized是針對整張Hash表的,即每次鎖住整張表讓線程獨佔,ConcurrentHashMap容許多個修改操做併發進行,其關鍵在於使用了鎖分離技術
  • 有些方法須要跨段,好比size()和containsValue(),它們可能須要鎖定整個表而而不只僅是某個段,這須要按順序鎖定全部段,操做完畢後,又按順序釋放全部段的鎖
  • 擴容:段內擴容(段內元素超過該段對應Entry數組長度的75%觸發擴容,不會對整個Map進行擴容),插入前檢測需不須要擴容,有效避免無效擴容

 

Hashtable和HashMap都實現了Map接口,可是Hashtable的實現是基於Dictionary抽象類的。Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。

HashMap基於哈希思想,實現對數據的讀寫。當咱們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,而後找到bucket位置來存儲值對象。當獲取對象時,經過鍵對象的equals()方法找到正確的鍵值對,而後返回值對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞時,對象將會儲存在鏈表的下一個節點中。HashMap在每一個鏈表節點中儲存鍵值對對象。當兩個不一樣的鍵對象的hashcode相同時,它們會儲存在同一個bucket位置的鏈表中,可經過鍵對象的equals()方法來找到鍵值對。若是鏈表大小超過閾值(TREEIFY_THRESHOLD,8),鏈表就會被改造爲樹形結構。

在HashMap中,null能夠做爲鍵,這樣的鍵只有一個,但能夠有一個或多個鍵所對應的值爲null。當get()方法返回null值時,便可以表示HashMap中沒有該key,也能夠表示該key所對應的value爲null。所以,在HashMap中不能由get()方法來判斷HashMap中是否存在某個key,應該用containsKey()方法來判斷。而在Hashtable中,不管是key仍是value都不能爲null。

Hashtable是線程安全的,它的方法是同步的,能夠直接用在多線程環境中。而HashMap則不是線程安全的,在多線程環境中,須要手動實現同步機制。

Hashtable與HashMap另外一個區別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。因此當有其它線程改變了HashMap的結構(增長或者移除元素),將會拋出ConcurrentModificationException,但迭代器自己的remove()方法移除元素則不會拋出ConcurrentModificationException異常。但這並非一個必定發生的行爲,要看JVM。

先看一下簡單的類圖:

  

從類圖中能夠看出來在存儲結構中ConcurrentHashMap比HashMap多出了一個類Segment,而Segment是一個可重入鎖。

ConcurrentHashMap是使用了鎖分段技術來保證線程安全的。

鎖分段技術:首先將數據分紅一段一段的存儲,而後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據的時候,其餘段的數據也能被其餘線程訪問。 

ConcurrentHashMap提供了與Hashtable和SynchronizedMap不一樣的鎖機制。Hashtable中採用的鎖機制是一次鎖住整個hash表,從而在同一時刻只能由一個線程對其進行操做;而ConcurrentHashMap中則是一次鎖住一個桶。

ConcurrentHashMap默認將hash表分爲16個桶,諸如get、put、remove等經常使用操做只鎖住當前須要用到的桶。這樣,原來只能一個線程進入,如今卻能同時有16個寫線程執行,併發性能的提高是顯而易見的。

內存泄漏的狀況有哪些

內存泄漏定義:一個再也不被程序使用的對象或變量還在內存中佔有存儲空間。

因爲java的JVM引入了垃圾回收機制,垃圾回收器會自動回收再也不使用的對象,瞭解JVM回收機制的都知道JVM是使用引用計數法和可達性分析算法來判斷對象是不是再也不使用的對象,本質都是判斷一個對象是否還被引用。那麼對於這種狀況下,因爲代碼的實現不一樣就會出現不少種內存泄漏問題(讓JVM誤覺得此對象還在引用中,沒法回收,形成內存泄漏)。

一、靜態集合類,如HashMap、LinkedList等等。若是這些容器爲靜態的,那麼它們的生命週期與程序一致,則容器中的對象在程序結束以前將不能被釋放,從而形成內存泄漏。簡單而言,長生命週期的對象持有短生命週期對象的引用,儘管短生命週期的對象再也不使用,可是由於長生命週期對象持有它的引用而致使不能被回收。

二、各類鏈接,如數據庫鏈接、網絡鏈接和IO鏈接等。在對數據庫進行操做的過程當中,首先須要創建與數據庫的鏈接,當再也不使用時,須要調用close方法來釋放與數據庫的鏈接。只有鏈接被關閉後,垃圾回收器纔會回收對應的對象。不然,若是在訪問數據庫的過程當中,對Connection、Statement或ResultSet不顯性地關閉,將會形成大量的對象沒法被回收,從而引發內存泄漏。

三、變量不合理的做用域。通常而言,一個變量的定義的做用範圍大於其使用範圍,頗有可能會形成內存泄漏。另外一方面,若是沒有及時地把對象設置爲null,頗有可能致使內存泄漏的發生。

public class UsingRandom {
    
    private String msg;
    public void receiveMsg(){
        readFromNet();// 從網絡中接受數據保存到msg中
        saveDB();// 把msg保存到數據庫中
    }
}
如上面這個僞代碼,經過readFromNet方法把接受的消息保存在變量msg中,而後調用saveDB方法把msg的內容保存到數據庫中,此時msg已經就沒用了,因爲msg的生命週期與對象的生命週期相同,此時msg還不能回收,所以形成了內存泄漏。

實際上這個msg變量能夠放在receiveMsg方法內部,當方法使用完,那麼msg的生命週期也就結束,此時就能夠回收了。還有一種方法,在使用完msg後,把msg設置爲null,這樣垃圾回收器也會回收msg的內存空間。

四、內部類持有外部類,若是一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即便那個外部類實例對象再也不被使用,但因爲內部類持有外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會形成內存泄露。

五、改變哈希值,當一個對象被存儲進HashSet集合中之後,就不能修改這個對象中的那些參與計算哈希值的字段了,不然,對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不一樣了,在這種狀況下,即便在contains方法使用該對象的當前引用做爲的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會致使沒法從HashSet集合中單獨刪除當前對象,形成內存泄露

classpath,path的區別

一、 path是系統用來指定可執行文件的完整路徑,即便不在path中設置JDK的路徑也可執行Java文件,但必須把完整的路徑寫出來,如C:\Program Files\Java\jdk1.6.0_10\bin\javac TheClass.java。path是用來搜索所執行的可執行文件路徑的,若是執行的可執行文件不在當前目錄下,那就會依次搜索path中設置的路徑;而java的各類操做命令是在其安裝路徑中的bin目錄下。因此在path中設置了JDK的安裝目錄後就不用再把java文件的完整路徑寫出來了,它會自動去path中設置的路徑中去找;

二、 classpath是指定你在程序中所使用的類(.class)文件所在的位置,就如在引入一個類時:import javax.swing.JTable這句話是告訴編譯器要引入javax.swing這個包下的JTable類,而classpath就是告訴編譯器該到哪裏去找到這個類(前提是你在classpath中設置了這個類的路徑)。若是你想要編譯在當前目錄下找,就加上「.」,如:.;C:\Program Files\Java\jdk\,這樣編譯器就會到當前目錄和C:\Program Files\Java\jdk\去找javax.swing.JTable這個類;還提下:大多數人都是用Eclipse寫程序,不設classpath也不要緊,由於Eclipse有相關的配置;

JVM運行過程

1、JVM的體系結構

類裝載系統

一、定位和導入二進制class文件

二、驗證導入類的正確性

三、爲類分配初始化內存

四、幫助解析符號引用

執行引擎

執行包在裝載類的方法中的指令,也就是方法

運行區數據

虛擬機會在整個計算機內存中開闢一塊內存存儲JVM須要用到的對象,變量等,運行區數據有分不少小區,分別爲:方法區,虛擬機棧,本地方法棧,堆,程序計數器。

GC

垃圾回收器,是負責回收內存中無用的對象,就是這些對象沒有任何引用了,它就會被視爲垃圾,也就會被刪除。

2、類在JVM的執行流程

那麼類在JVM的執行流程是怎麼作的呢?共有三步:加載、連接和初始化。

加載

JVM將java類的二進制形式加載到內存中,並將他緩存在內存中,以便後面使用,若是沒有找到指定的類就會拋出異常classNotFound,進程在這裏結束。沒有錯誤就繼續在Java堆中生成一個表明這個類的java.lang.Class對象,做爲方法區域數據的訪問入口。

連接

這個階段作三件事:驗證、準備和解析(可選)。

驗證是JVM根據java語言和JVM的語義要求檢查這個二進制形式。例如,若是篡改通過編譯後的類文件,那麼這個類文件可能就不能使用了。

準備是指準備要執行的指定的類,準備階段爲變量分配內存並設置靜態變量的初始化。在這個階段分配的僅爲類的變量(static修飾的變量),而不包括類的實例變量。對非final的變量,JVM會將其設置成「零值」,而不是其賦值語句的值:

public static int num = 8;

那麼在這個階段,num的值爲0,而不是8。 final修飾的類變量將會賦值成真實的值。

解析是檢查指定的類是否引用了其餘的類/接口,是否能找到和加載其餘的類/接口。這些檢查將針對被引用的類/接口遞歸進行,JVM的實施也能夠在後面階段執行解析,即正在執行的代碼真正要使用被引用的類/接口的時候。

初始化

在這最後一步中,JVM用賦值或者缺省值將靜態變量初始化,初始化發生在執行main方法以前。在指定的類初始化前,會先初始化它的父類,此外,在初始化父類時,父類的父類也要這樣初始化。這個過程是遞歸進行的。

簡而言之,整個流程是將類存進內存中,檢查類的對應調用的類和接口是否可正常使用,再對類進行初始化的過程。

類在JVM執行流程

3、Java代碼編譯和執行的整個過程

Java代碼編譯是由Java源碼編譯器來完成,流程圖以下所示:

Java字節碼的執行是由JVM執行引擎來完成,流程圖以下所示:

4、總結

Java虛擬機的生命週期 一個運行中的Java虛擬機有着一個清晰的任務:執行Java程序。

程序開始執行時他才運行,程序結束時他就中止。你在同一臺機器上運行三個程序,就會有三個運行中的Java虛擬機。

Java虛擬機老是開始於一個main()方法,這個方法必須是公有、返回void、直接受一個字符串數組。在程序執行時,你必須給Java虛擬機指明這個包換main()方法的類名。 Main()方法是程序的起點,他被執行的線程初始化爲程序的初始線程。程序中其餘的線程都由他來啓動。

Java中的線程分爲兩種:守護線程(daemon)和普通線程(non-daemon)。守護線程是Java虛擬機本身使用的線程,好比負責垃圾收集的線程就是一個守護線程。固然,你也可 以把本身的程序設置爲守護線程。包含Main()方法的初始線程不是守護線程。

只要Java虛擬機中還有普通的線程在執行,Java虛擬機就不會中止。若是有足夠的權限,你能夠調用exit()方法終止程序。

GC機制講一講

   隨着程序的運行,內存中的實例對象、變量等佔據的內存愈來愈多,若是不及時進行回收,會下降程序運行效率,甚至引起系統異常。

       在上面介紹的五個內存區域中,有3個是不須要進行垃圾回收的:本地方法棧、程序計數器、虛擬機棧。由於他們的生命週期是和線程同步的,隨着線程的銷燬,他們佔用的內存會自動釋放。因此,只有方法區和堆區須要進行垃圾回收,回收的對象就是那些不存在任何引用的對象。

3.1 查找算法
        經典的引用計數算法,每一個對象添加到引用計數器,每被引用一次,計數器+1,失去引用,計數器-1,當計數器在一段時間內爲0時,即認爲該對象能夠被回收了。可是這個算法有個明顯的缺陷:當兩個對象相互引用,可是兩者都已經沒有做用時,理應把它們都回收,可是因爲它們相互引用,不符合垃圾回收的條件,因此就致使沒法處理掉這一塊內存區域。所以,Sun的JVM並無採用這種算法,而是採用一個叫——根搜索算法,如圖:

       基本思想是:從一個叫GC Roots的根節點出發,向下搜索,若是一個對象不能達到GC Roots的時候,說明該對象再也不被引用,能夠被回收。如上圖中的Object五、Object六、Object7,雖然它們三個依然相互引用,可是它們其實已經沒有做用了,這樣就解決了引用計數算法的缺陷。

       補充概念,在JDK1.2以後引入了四個概念:強引用、軟引用、弱引用、虛引用。 
       強引用:new出來的對象都是強引用,GC不管如何都不會回收,即便拋出OOM異常。 
       軟引用:只有當JVM內存不足時纔會被回收。 
       弱引用:只要GC,就會立馬回收,無論內存是否充足。 
       虛引用:能夠忽略不計,JVM徹底不會在意虛引用,你能夠理解爲它是來湊數的,湊夠」四大天王」。它惟一的做用就是作一些跟蹤記錄,輔助finalize函數的使用。

       最後總結,什麼樣的類須要被回收:

a.該類的全部實例都已經被回收;
b.加載該類的ClassLoad已經被回收;
c.該類對應的反射類java.lang.Class對象沒有被任何地方引用。
3.2 內存分區
       內存主要被分爲三塊:新生代(Youn Generation)、舊生代(Old Generation)、持久代(Permanent Generation)。三代的特色不一樣,造就了他們使用的GC算法不一樣,新生代適合生命週期較短,快速建立和銷燬的對象,舊生代適合生命週期較長的對象,持久代在Sun Hotpot虛擬機中就是指方法區(有些JVM根本就沒有持久代這一說法)。 


       新生代(Youn Generation):大體分爲Eden區和Survivor區,Survivor區又分爲大小相同的兩部分:FromSpace和ToSpace。新建的對象都是重新生代分配內存,Eden區不足的時候,會把存活的對象轉移到Survivor區。當新生代進行垃圾回收時會出發Minor GC(也稱做Youn GC)。

       舊生代(Old Generation):舊生代用於存放新生代屢次回收依然存活的對象,如緩存對象。當舊生代滿了的時候就須要對舊生代進行回收,舊生代的垃圾回收稱做Major GC(也稱做Full GC)。

       持久代(Permanent Generation):在Sun 的JVM中就是方法區的意思,儘管大多數JVM沒有這一代。

3.3 GC算法
       常見的GC算法:複製、標記-清除和標記-壓縮

       複製:複製算法採用的方式爲從根集合進行掃描,將存活的對象移動到一塊空閒的區域,如圖所示: 


當存活的對象較少時,複製算法會比較高效(新生代的Eden區就是採用這種算法),其帶來的成本是須要一塊額外的空閒空間和對象的移動。

       標記-清除:該算法採用的方式是從跟集合開始掃描,對存活的對象進行標記,標記完畢後,再掃描整個空間中未被標記的對象,並進行清除。標記和清除的過程以下: 


上圖中藍色部分是有被引用的對象,褐色部分是沒有被引用的對象。在Marking階段,須要進行全盤掃描,這個過程是比較耗時的。 


清除階段清理的是沒有被引用的對象,存活的對象被保留。

標記-清除動做不須要移動對象,且僅對不存活的對象進行清理,在空間中存活對象較多的時候,效率較高,但因爲只是清除,沒有從新整理,所以會形成內存碎片。

       標記-壓縮:該算法與標記-清除算法相似,都是先對存活的對象進行標記,可是在清除後會把活的對象向左端空閒空間移動,而後再更新其引用對象的指針,以下圖所示 


因爲進行了移動規整動做,該算法避免了標記-清除的碎片問題,但因爲須要進行移動,所以成本也增長了。(該算法適用於舊生代)

4、垃圾收集器
       在JVM中,GC是由垃圾回收器來執行,因此,在實際應用場景中,咱們須要選擇合適的垃圾收集器,下面咱們介紹一下垃圾收集器。

4.1 串行收集器(Serial GC)
       Serial GC是最古老也是最基本的收集器,可是如今依然普遍使用,JAVA SE5和JAVA SE6中客戶端虛擬機採用的默認配置。比較適合於只有一個處理器的系統。在串行處理器中minor和major GC過程都是用一個線程進行回收的。它的最大特色是在進行垃圾回收時,須要對全部正在執行的線程暫停(stop the world),對於有些應用是難以接受的,可是若是應用的實時性要求不是那麼高,只要停頓的時間控制在N毫秒以內,大多數應用仍是能夠接受的,並且事實上,它並無讓咱們失望,幾十毫秒的停頓,對於咱們客戶機是徹底能夠接受的,該收集器適用於單CPU、新生代空間較小且對暫停時間要求不是特別高的應用上,是client級別的默認GC方式。

4.2 ParNew GC
       基本和Serial GC同樣,但本質區別是加入了多線程機制,提升了效率,這樣它就能夠被用於服務端上(server),同時它能夠與CMS GC配合,因此,更加有理由將他用於server端。

4.3 Parallel Scavenge GC
       在整個掃描和複製過程採用多線程的方式進行,適用於多CPU、對暫停時間要求較短的應用,是server級別的默認GC方式。

4.4 CMS (Concurrent Mark Sweep)收集器
       該收集器的目標是解決Serial GC停頓的問題,以達到最短回收時間。常見的B/S架構的應用就適合這種收集器,由於其高併發、高響應的特色,CMS是基於標記-清楚算法實現的。

CMS收集器的優勢:併發收集、低停頓,但遠沒有達到完美;

CMS收集器的缺點:

a.CMS收集器對CPU資源很是敏感,在併發階段雖然不會致使用戶停頓,可是會佔用CPU資源而致使應用程序變慢,總吞吐量降低。
b.CMS收集器沒法處理浮動垃圾,可能出現「Concurrnet Mode Failure」,失敗而致使另外一次的Full GC。
c.CMS收集器是基於標記-清除算法的實現,所以也會產生碎片。
4.5 G1收集器
       相比CMS收集器有很多改進,首先,基於標記-壓縮算法,不會產生內存碎片,其次能夠比較精確的控制停頓。

4.6 Serial Old收集器
       Serial Old是Serial收集器的老年代版本,它一樣使用一個單線程執行收集,使用「標記-整理」算法。主要使用在Client模式下的虛擬機。

4.7 Parallel Old收集器
       Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和「標記-整理」算法。

4.8 RTSJ垃圾收集器
       RTSJ垃圾收集器,用於Java實時編程。

5、總結
       深刻理解JVM的內存模型和GC機制有助於幫助咱們編寫高性能代碼和提供代碼優化的思路與方向。

線程池,阻塞隊列

  •  線程池

3種經常使用的線程池:

  1. newSIngleThreadExecutor(建立一個單線程)
  2. newFixedThreadPool(建立固定大小的線程池)
  3. newCacheThreadPool(建立一個可緩存的線程池)若是線程池的大小超過了處理任務所需的線程,那麼就會回收部分空閒(60s不執行任務)的線程,當任務數增長時,此線程又能夠添加新的線程來處理任務。

建立線程:使用Executors類提供的幾個靜態方法來建立線程池。

構造器的各個核心參數的含義:

  corePoolsize:核心池大小

  maxPoolSize:線程池最大線程數

關閉線程:

  shutdown()和shutdownNow()是用來關閉線程的

  • 阻塞隊列:

  對一個隊列滿了以後進行如隊列(阻塞)

  對一個隊列空了以後進行出隊列(阻塞)

  用於消費者(取隊列中元素的線程)生成者(往隊列中添加元素的線程)

  1. ArrayblockingQueue:有界,鎖是沒有分離的,即生產者和消費者是同一把鎖;進行put和take操做,公用同一個鎖對象。也就是說put和take沒法並行執行
  2. DelayQueue:按元素過時時間進行排序(DelayQueue=BlockingQueue+PriorityQueue+Delayed)
  3. LinkedBlockingQueue:對於生產者端和消費者端分別採用了獨立的鎖來控制數據同步,這也意味着在高併發的狀況下生產者和消費者能夠並行地操做隊列中的數據,一次來提升整個隊列的併發性能。
  4. PriorityBlockingQueue:無界,能夠插入空對象(插入對象必須實現Comparable接口)
  5. SynchronousQueue:無界無緩存,不存儲元素,它的size()方法老是返回0。每一個線程插入操做必須等待另外一個線程的插入操做。
  •  死鎖:

  互斥條件(Mutual exclusion):資源不能被共享,只能由一個進程使用。
  請求與保持條件(Hold and wait):已經獲得資源的進程能夠再次申請新的資源。
  非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
  循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每一個進程都在等待相鄰進程正佔用的資源。

二面:

http ,https區別

 超文本傳輸協議HTTP協議被用於在Web瀏覽器和網站服務器之間傳遞信息,HTTP協議以明文方式發送內容,不提供任何方式的數據加密,若是攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文,就能夠直接讀懂其中的信息,所以,HTTP協議不適合傳輸一些敏感信息,好比:信用卡號、密碼等支付信息。

  爲了解決HTTP協議的這一缺陷,須要使用另外一種協議:安全套接字層超文本傳輸協議HTTPS,爲了數據傳輸的安全,HTTPS在HTTP的基礎上加入了SSL協議,SSL依靠證書來驗證服務器的身份,併爲瀏覽器和服務器之間的通訊加密。

1、HTTP和HTTPS的基本概念

  HTTP:是互聯網上應用最爲普遍的一種網絡協議,是一個客戶端和服務器端請求和應答的標準(TCP),用於從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議,它能夠使瀏覽器更加高效,使網絡傳輸減小。

  HTTPS:是以安全爲目標的HTTP通道,簡單講是HTTP的安全版,即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。

  HTTPS協議的主要做用能夠分爲兩種:一種是創建一個信息安全通道,來保證數據傳輸的安全;另外一種就是確認網站的真實性。

2、HTTP與HTTPS有什麼區別?

  HTTP協議傳輸的數據都是未加密的,也就是明文的,所以使用HTTP協議傳輸隱私信息很是不安全,爲了保證這些隱私數據能加密傳輸,因而網景公司設計了SSL(Secure Sockets Layer)協議用於對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。簡單來講,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。

  HTTPS和HTTP的區別主要以下:

  一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。

  二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。

  三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。

  四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

3、HTTPS的工做原理

  咱們都知道HTTPS可以加密信息,以避免敏感信息被第三方獲取,因此不少銀行網站或電子郵箱等等安全級別較高的服務都會採用HTTPS協議。

HTTP與HTTPS的區別-馬海祥博客

 客戶端在使用HTTPS方式與Web服務器通訊時有如下幾個步驟,如圖所示。

  (1)客戶使用https的URL訪問Web服務器,要求與Web服務器創建SSL鏈接。

  (2)Web服務器收到客戶端請求後,會將網站的證書信息(證書中包含公鑰)傳送一份給客戶端。

  (3)客戶端的瀏覽器與Web服務器開始協商SSL鏈接的安全等級,也就是信息加密的等級。

  (4)客戶端的瀏覽器根據雙方贊成的安全等級,創建會話密鑰,而後利用網站的公鑰將會話密鑰加密,並傳送給網站。

  (5)Web服務器利用本身的私鑰解密出會話密鑰。

  (6)Web服務器利用會話密鑰加密與客戶端之間的通訊。

  

4、HTTPS的優勢

  儘管HTTPS並不是絕對安全,掌握根證書的機構、掌握加密算法的組織一樣能夠進行中間人形式的攻擊,但HTTPS還是現行架構下最安全的解決方案,主要有如下幾個好處:

  (1)使用HTTPS協議可認證用戶和服務器,確保數據發送到正確的客戶機和服務器;

  (2)HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程當中不被竊取、改變,確保數據的完整性。

  (3)HTTPS是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增長了中間人攻擊的成本。

  (4)谷歌曾在2014年8月份調整搜索引擎算法,並稱「比起同等HTTP網站,採用HTTPS加密的網站在搜索結果中的排名將會更高」。

5、HTTPS的缺點

  雖說HTTPS有很大的優點,但其相對來講,仍是存在不足之處的:

  (1)HTTPS協議握手階段比較費時,會使頁面的加載時間延長近50%,增長10%到20%的耗電;

  (2)HTTPS鏈接緩存不如HTTP高效,會增長數據開銷和功耗,甚至已有的安全措施也會所以而受到影響;

  (3)SSL證書須要錢,功能越強大的證書費用越高,我的網站、小網站沒有必要通常不會用。

    (4)SSL證書一般須要綁定IP,不能在同一IP上綁定多個域名,IPv4資源不可能支撐這個消耗。

  (5)HTTPS協議的加密範圍也比較有限,在黑客攻擊、拒絕服務攻擊、服務器劫持等方面幾乎起不到什麼做用。最關鍵的,SSL證書的信用鏈體系並不安全,特別是在某些國家能夠控制CA根證書的狀況下,中間人攻擊同樣可行。

6、http切換到HTTPS

  若是須要將網站從http切換到https到底該如何實現呢?

     這裏須要將頁面中全部的連接,例如js,css,圖片等等連接都由http改成https。例如:http://www.baidu.com改成https://www.baidu.com

  BTW,這裏雖然將http切換爲了https,仍是建議保留http。因此咱們在切換的時候能夠作http和https的兼容,具體實現方式是,去掉頁面連接中的http頭部,這樣能夠自動匹配http頭和https頭。例如:將http://www.baidu.com改成//www.baidu.com。而後當用戶從http的入口進入訪問頁面時,頁面就是http,若是用戶是從https的入口進入訪問頁面,頁面即便https的。

分佈式dubbo講一下了解

1. 什麼是Dubbo?

  官網:http://dubbo.io/,DUBBO是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及做爲SOA服務治理的方案,它是阿里巴巴SOA服務化治理方案的核心框架,天天爲2,000+個服務提供3,000,000,000+次訪問量支持,並被普遍應用於阿里巴巴集團的各成員站點。<目前的dubbo社區已中止維護和更新>,它的核心功能包括:

  • #remoting:遠程通信基礎,提供對多種NIO框架抽象封裝,包括「同步轉異步」和「請求-響應」模式的信息交換方式。
  • #cluster: 服務框架核心,提供基於接口方法的遠程過程調用,包括多協議支持,並提供軟負載均衡和容錯機制的集羣支持。
  • #registry: 服務註冊中心,使服務消費方能動態的查找服務提供方,使地址透明,使服務提供方能夠平滑增長或減小機器。

2. dubbo是如何使用來提供服務的?

  web應用架構的發展,從單一的ORM架構(一個應用,將全部功能部署在一塊兒,減小部署的節點和成本)到MVC架構(拆分出互相不相干的幾個應用),再從MVC框架到RPC框架(將業務中的核心業務抽取出來,作爲獨立的服務,漸漸造成服務中心),從RPC架構到SOA架構(增長一個調度中心基於訪問壓力實時管理集羣容量,提升集羣利用率)。

  Dubbo有本身的服務中心,寫好的服務能夠註冊到服務中心,客戶端從服務中心尋找服務,而後再到相應的服務提供者機器獲取服務。經過服務中心能夠實現集羣、負載均衡、高可用(容錯) 等重要功能。服務中心通常使用zookeeper實現,也有redis和其餘一些方式。以使用zookeeper做爲服務中心爲例,服務提供者啓動後會在zookeeper的/dubbo節點下建立提供的服務節點,包含服務提供者ip、port等信息。服務提供者關閉時會從zookeeper中移除對應的服務。服務使用者會從註冊中心zookeeper中尋找服務,同一個服務可能會有多個提供者,Dubbo會幫咱們找到合適的服務提供者。

3. dubbo是如何作集羣容錯的?

  當服務調用失敗時(好比響應超時),根據咱們的業務不一樣,能夠使用不一樣的策略來應對這種失敗。好比咱們調用的服務是一個查詢服務,不會修改數據庫,那麼能夠給該服務設置容錯方式爲failover <失敗重試方式>,當調用失敗時,自動切換到其餘服務提供者去調用,當失敗次數超過指定重試次數,那麼就拋出錯誤。若是服務是更新數據的服務,那就不能使用失敗重試的方式了, 由於這樣可能產生數據重複修改的問題,好比調用提供者A的插入用戶方法,可是該方法業務邏輯複雜,執行過程很慢,致使響應超時,那麼此時若是再去調用另一個服務提供者的插入用戶方法,將會又重複插入同一個用戶。對於這種類型的服務,能夠使用容錯方式爲failfast,若是第一次調用失敗,當即報錯,不須要重試。

    另外還有下面幾種容錯類型,failsafe 出現錯誤,直接忽略,不重試也不報錯; failback 失敗後不報錯,會將該失敗請求,定時重發,適合消息通知類型的服務。forking,並行調用多個服務器,只要在某一臺提供者上面成功,那麼方法返回,適合實時性要求較高的查詢服務,可是要犧牲性能。由於每臺服務器會作同一個操做;broadcast 廣播調用全部服務提供者,逐個調用,任意一臺報錯則報錯。適合與更新每臺提供者上面的緩存,這種類型的服務。

  案例:咱們在點我吧的APP消息推送就是採用的failback方式,點我吧的短信通知則採用的是failover方式。

4. dubbo是如何作負載均衡的?{幾種負載均衡的策略}

  當同一個服務有多個提供者在提供服務時, 客戶端如何正確的選擇提供者實現負載均衡dubbo也給咱們提供了幾種方案:random,隨機選提供者,並能夠給提供者設置權重;roundrobin,輪詢選擇提供者,leastactive,最少活躍調用數,相同活躍數的隨機,活躍數指調用先後計數差。使慢的提供者收到更少請求,由於越慢的提供者的調用先後計數差會越大。consistenthash 一致性hash,相同參數的請求發到同一臺機器上。

  關於一致性hash的幾點學習,咱們知道普通的哈希算法在散列的時候,可能產生間隔,並不能使數據均與分佈開來。一致性哈希算法正是基於哈希算法的缺點所引入的解決方案。一致性hash算法提出了在動態變化的Cache環境中,斷定哈希算法好壞的四個定義:一、平衡性(Balance):平衡性是指哈希的結果可以儘量分佈到全部的緩衝中去,這樣能夠使得全部的緩衝空間都獲得利用。不少哈希算法都可以知足這一條件。二、單調性(Monotonicity):單調性是指若是已經有一些內容經過哈希分派到了相應的緩衝中,又有新的緩衝加入到系統中。哈希的結果應可以保證原有已分配的內容能夠被映射到原有的或者新的緩衝中去,而不會被映射到舊的緩衝集合中的其餘緩衝區。三、分散性(Spread):在分佈式環境中,終端有可能看不到全部的緩衝,而是隻能看到其中的一部分。當終端但願經過哈希過程將內容映射到緩衝上時,因爲不一樣終端所見的緩衝範圍有可能不一樣,從而致使哈希的結果不一致,最終的結果是相同的內容被不一樣的終端映射到不一樣的緩衝區中。這種狀況顯然是應該避免的,由於它致使相同內容被存儲到不一樣緩衝中去,下降了系統存儲的效率。分散性的定義就是上述狀況發生的嚴重程度。好的哈希算法應可以儘可能避免不一致的狀況發生,也就是儘可能下降分散性。四、負載(Load):負載問題其實是從另外一個角度看待分散性問題。既然不一樣的終端可能將相同的內容映射到不一樣的緩衝區中,那麼對於一個特定的緩衝區而言,也可能被不一樣的用戶映射爲不一樣 的內容。與分散性同樣,這種狀況也是應當避免的,所以好的哈希算法應可以儘可能下降緩衝的負荷。在分佈式集羣中,對機器的添加刪除,或者機器故障後自動脫離集羣這些操做是分佈式集羣管理最基本的功能。若是採用經常使用的hash(object)%N算法,那麼在有機器添加或者刪除後,不少原有的數據就沒法找到了,這樣嚴重的違反了單調性原則。接下來主要講解一下一致性哈希算法是如何設計的:

 

如上圖所示,是環形的hash空間,按照經常使用的hash算法來將對應的key哈希到一個具備2^32次方個桶的空間中,即0~(2^32)-1的數字空間中。如今咱們能夠將這些數字頭尾相連,想象成一個閉合的環形。咱們把數據經過hash算法處理後映射到環上,如今咱們將object一、object二、object三、object4四個對象經過特定的Hash函數計算出對應的key值,而後散列到Hash環上。Hash(object1) = key1;Hash(object2) = key2;Hash(object3) = key3;Hash(object4) = key4;

 

普通hash求餘算法最爲不妥的地方就是在有機器的添加或者刪除以後會照成大量的對象存儲位置失效,這樣就大大的不知足單調性了。下面來分析一下一致性哈希算法是如何處理的?它經過按順時針遷移的規則,首先保證其它對象還保持原有的存儲位置。當經過節點的添加和刪除的時候,一致性哈希算法在保持了單調性的同時,仍是數據的遷移達到了最小,這樣的算法對分佈式集羣來講是很是合適的,避免了大量數據遷移,減少了服務器的的壓力。

5. dubbo的多協議方式?

  dubbo提供了多種協議給用戶選擇,如dubbo、hessian、rmi 。並可爲每一個服務指定不一樣的傳輸協議,粒度能夠細化到方法,不一樣服務在性能上適用不一樣協議進行傳輸,好比大數據用短鏈接協議,小數據大併發用長鏈接協議。

  使用Dubbo進行遠程調用實現服務交互,它支持多種協議,如Hessian、HTTP、RMI、Memcached、Redis、Thrift等等。因爲Dubbo將這些協議的實現進行了封裝了,不管是服務端(開發服務)仍是客戶端(調用服務),都不須要關心協議的細節,只須要在配置中指定使用的協議便可,從而保證了服務提供方與服務消費方之間的透明。另外,若是咱們使用Dubbo的服務註冊中心組件,這樣服務提供方將服務發佈到註冊的中心,只是將服務的名稱暴露給外部,而服務消費方只須要知道註冊中心和服務提供方提供的服務名稱,就可以透明地調用服務,後面咱們會看到具體提供服務和消費服務的配置內容,使得雙方之間交互的透明化。

provider-registry-consumer

 

  如圖所示的應用場景,服務方提供一個搜索服務,對服務方來講,它基於SolrCloud構建了搜索服務,包含兩個集羣,ZooKeeper集羣和Solr集羣,而後在前端經過Nginx來進行反向代理,達到負載均衡的目的。服務消費方就是調用服務進行查詢,給出查詢條件。

  基於上面的示例場景,咱們打算使用ZooKeeper集羣做爲服務註冊中心。註冊中心會暴露給服務提供方和服務消費方,因此註冊服務的時候,服務先提供方只須要提供Nginx的地址給註冊中心,可是註冊中心並不會把這個地址暴露給服務消費方。

1 public interface SolrSearchService {
2     String search(String collection, String q, ResponseType type, int start, int rows);
3     public enum ResponseType {JSON, XML}  
4 }

  其中,provider的服務設計:provider所發佈的服務組件,包含了一個SolrCloud集羣,在SolrCloud集羣前端又加了一個反向代理層,使用Nginx來均衡負載。Provider的搜索服務系統,設計以下圖所示:

  solrcloud-cluster

 

     如圖所示,實際nginx中將請求直接轉發到內部的Web Servers上,在這個過程當中,使用ZooKeeper來進行協調:從多個分片(Shard)服務器上並行搜索,最後合併結果。一共配置了3臺Solr服務器,由於SolrCloud集羣中每個節點均可以接收搜索請求,而後由整個集羣去並行搜索。最後,咱們要經過Dubbo服務框架來基於已有的系統來開發搜索服務,並經過Dubbo的註冊中心來發布服務。首選須要實現服務接口,實現代碼以下所示:

複製代碼

 1 package org.shirdrn.platform.dubbo.service.rpc.server;
 2 
 3 import java.io.IOException;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 import org.apache.commons.logging.Log;
 8 import org.apache.commons.logging.LogFactory;
 9 import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
10 import org.shirdrn.platform.dubbo.service.rpc.utils.QueryPostClient;
11 import org.springframework.context.support.ClassPathXmlApplicationContext;
12  
13 public class SolrSearchServer implements SolrSearchService {
14 
15     private static final Log LOG = LogFactory.getLog(SolrSearchServer.class);
16     private String baseUrl;
17     private final QueryPostClient postClient;
18     private static final Map<ResponseType, FormatHandler> handlers = new HashMap<ResponseType, FormatHandler>(0);
19     static {
20         handlers.put(ResponseType.XML, new FormatHandler() {
21             public String format() {
22                 return "&wt=xml";
23             }
24         });
25         handlers.put(ResponseType.JSON, new FormatHandler() {
26             public String format() {
27                 return "&wt=json";
28             }
29         });
30     }
31    public SolrSearchServer() {
32         super();
33         postClient = QueryPostClient.newIndexingClient(null);
34     }
35     public void setBaseUrl(String baseUrl) {
36         this.baseUrl = baseUrl;
37     }
38     public String search(String collection, String q, ResponseType type,
39             int start, int rows) {
40         StringBuffer url = new StringBuffer();    
       url.append(baseUrl).append(collection).append("/select?").append(q);   
       url.append("&start=").append(start).append("&rows=").append(rows);
41         url.append(handlers.get(type).format());
42         LOG.info("[REQ] " + url.toString());
43         return postClient.request(url.toString());
44     }
45     interface FormatHandler {
46         String format();
47     }
48     public static void main(String[] args) throws IOException {
49         String config = SolrSearchServer.class.getPackage().getName().replace('.', '/') + "/search-provider.xml";
50         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
51         context.start();
52         System.in.read();
53     }
54 }

複製代碼

對應的Dubbo配置文件爲search-provider.xml,內容以下所示:

複製代碼

 1 <?xml version="1.0" encoding="UTF-8"?>
 2     <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 4     http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 5     <dubbo:application name="search-provider" />
 6     <dubbo:registry address="zookeeper://slave1:2188?backup=slave3:2188,slave4:2188" />
 7     <dubbo:protocol name="dubbo" port="20880" />
 8     <bean id="searchService" class="org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer">
 9         <property name="baseUrl" value="http://nginx-lbserver/solr-cloud/" />
10     </bean>
11     <dubbo:service interface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService" ref="searchService" />
12 </beans>

複製代碼

上面,Dubbo服務註冊中心指定ZooKeeper的地址:zookeeper://slave1:2188?backup=slave3:2188,slave4:2188,使用Dubbo協議。配置服務接口的時候,能夠按照Spring的Bean的配置方式來配置,注入須要的內容,咱們這裏指定了搜索集羣的Nginx反向代理地址http://nginx-lbserver/solr-cloud/。

6. dubbo的使用特色? 

  dubbo採用全Spring配置方式,透明化接入應用,對應用沒有任何API侵入,只需用Spring加載Dubbo的配置便可,Dubbo基於Spring的Schema擴展進行加載。

7. 總結

  dubbo是高性能的分佈式服務框架,它提供了服務治理的解決方案。它適用於(公司內部)跨部門跨項目遠程調用的場景,

    dubbo穩定而高效,不只支持大規模服務集羣的動態擴展,平滑升級,並且支持load balance,fail over,支持服務質量分級管理,dubbo簡化了服務配置,減小DB鏈接數。

  dubbo能夠作什麼,dubbo是基於NIO和長鏈接的遠程調用實現,dubbo提供的服務暴露和導入,對應用方的代碼無侵入性,dubbo提供多協議支持,如RMI、Hessian、tbr等,dubbo提供了fail over機制,當某個provider出現異常後,會自動切換provider,dubbo提供了load balance機制,採用了權重+隨機或輪詢算法,服務列表動態更新,如步驟三。dubbo解決了服務治理問題,包括provider和consumer之間的匹配問題,dubbo提供了服務的註冊和訂閱功能,dubbo的靈活的路由規則設置,且支持服務列表動態推送功能,且提供了基於web的管理功能。

複製代碼

/*
*   使用Dubbo服務接口
*/

// 首先,在API包中定義服務接口,同時部署於Provider端和Consumer端
public interface HelloService {
    public String sayHello();
}

// 其次,在服務端的Provider實現代碼
public class HelloServiceImpl implements HelloService {
    public String sayHello() {
        return "Welcome to dubbo!";
    }
}

// 配置:提供者暴露服務;消費者消費服務

/*provider端服務實現類*/
<bean id="helloService" class="com.alibaba.hello.impl.HelloServiceImpl" />

/*provider端暴露服務*/
<dubbo:service interface="com.alibaba.hello.HelloService" version="1.0.0"  ref="helloService"/>

/*consumer端引入服務*/
<dubbo:reference id="helloService" interface="com.alibaba.hello.HelloService" version="1.0.0" />

/*consumer端使用服務*/
<bean id="xxxAction" class="com.alibaba.xxx.XxxAction" ><property name="helloService" ref="helloService" /></bean>

複製代碼

咱們對dubbo的性能作出測試,以下:

 

項目介紹

非對稱加密和對稱加密

什麼是對稱加密技術?

對稱加密採用了對稱密碼編碼技術,它的特色是文件加密和解密使用相同的密鑰加密

也就是密鑰也能夠用做解密密鑰,這種方法在密碼學中叫作對稱加密算法,對稱加密算法使用起來簡單快捷,密鑰較短,且破譯困難,除了數據加密標準(DES),另外一個對稱密鑰加密系統是國際數據加密算法(IDEA),它比DES的加密性好,並且對計算機功能要求也沒有那麼高

對稱加密算法在電子商務交易過程當中存在幾個問題:

  一、要求提供一條安全的渠道使通信雙方在首次通信時協商一個共同的密鑰。直接的面對面協商多是不現實並且難於實施的,因此雙方可能須要藉助於郵件和電話等其它相對不夠安全的手段來進行協商;

  二、密鑰的數目難於管理。由於對於每個合做者都須要使用不一樣的密鑰,很難適應開放社會中大量的信息交流;

  三、對稱加密算法通常不能提供信息完整性的鑑別。它沒法驗證發送者和接受者的身份;

  四、對稱密鑰的管理和分發工做是一件具備潛在危險的和煩瑣的過程。對稱加密是基於共同保守祕密來實現的,採用對稱加密技術的貿易雙方必須保證採用的是相同的密鑰,保證彼此密鑰的交換是安全可靠的,同時還要設定防止密鑰泄密和更改密鑰的程序。

  假設兩個用戶須要使用對稱加密方法加密而後交換數據,則用戶最少須要2個密鑰並交換使用,若是企業內用戶有n個,則整個企業共須要n×(n-1) 個密鑰,密鑰的生成和分發將成爲企業信息部門的惡夢。

常見的對稱加密算法有DES、3DES、Blowfish、IDEA、RC四、RC五、RC6和AES 

什麼是非對稱加密技術

與對稱加密算法不一樣,非對稱加密算法須要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。

公開密鑰與私有密鑰是一對,若是用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;若是用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。由於加密和解密使用的是兩個不一樣的密鑰,因此這種算法叫做非對稱加密算法。

非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將其中的一把做爲公用密鑰向其它方公開;獲得該公用密鑰的乙方使用該密鑰對機密信息進行加密後再發送給甲方;甲方再用本身保存的另外一把專用密鑰對加密後的信息進行解密。甲方只能用其專用密鑰解密由其公用密鑰加密後的任何信息。

 非對稱加密的典型應用是數字簽名。

   常見的非對稱加密算法有:RSA、ECC(移動設備用)、Diffie-Hellman、El Gamal、DSA(數字簽名用)

Hash算法(摘要算法)

Hash算法特別的地方在於它是一種單向算法,用戶能夠經過hash算法對目標信息生成一段特定長度的惟一hash值,卻不能經過這個hash值從新得到目標信息。所以Hash算法經常使用在不可還原的密碼存儲、信息完整性校驗等。

常見的Hash算法有MD二、MD四、MD五、HAVAL、SHA

如何設計一個服務器(socket相關)

eclipse、IJ開發快捷鍵及使用技巧講幾個

如何使得瀏覽器加載請求能夠穩定打到後臺而不使用瀏覽器緩存(請求中加一個隨機值參數)

spring事務寫在哪一部分,爲何不寫在DAO,Controller層

數據庫驅動爲何使用反射調用不直接new

相關文章
相關標籤/搜索