1、servlet生命周期
(1) 初始化階段,調(diào)用init()
方法
(2) 響應(yīng)客戶端請(qǐng)求階段,調(diào)用service()
方法
(3) 終止階段,調(diào)用destroy()
方法
servlet容器裝載servlet
- Servlet容器啟動(dòng)時(shí)自動(dòng)裝載某些Servlet箕戳,實(shí)現(xiàn)它只需要在web.XML文件中的<Servlet></Servlet>之間添加如下代碼:
<loadon-startup>1</loadon-startup>
- 在Servlet容器啟動(dòng)后,客戶首次向Servlet發(fā)送請(qǐng)求
- Servlet類文件被更新后国撵,重新裝載Servlet陵吸,Servlet被裝載后,Servlet容器創(chuàng)建一個(gè)Servlet實(shí)例并且調(diào)用Servlet的init()方法進(jìn)行初始化介牙。在Servlet的整個(gè)生命周期內(nèi)壮虫,init()方法只被調(diào)用一次。
servlet工作原理
首先客戶發(fā)送一個(gè)請(qǐng)求环础,servlet
調(diào)用service()
方法對(duì)請(qǐng)求進(jìn)行響應(yīng)囚似,service()
方法對(duì)請(qǐng)求的方式進(jìn)行匹配,選擇調(diào)用doGet()
, doPost()
這些方线得。servlet接口中沒(méi)有 doGet,doPost這些方法饶唤,httpServlet中有這些方法,但返回值都是error信息贯钩,所有需要將doPost,doGet重寫(xiě)募狂。
每一個(gè)自定義的servlet都需要實(shí)現(xiàn)servlet接口(init,service,destory就在這個(gè)接口中)。GenericServlet是一個(gè)通用的角雷、不特定于任何協(xié)議的servlet祸穷,它實(shí)現(xiàn)了servlet接口,而httpServlet又繼承與GenericServlet勺三,所以我們定義servlet時(shí)只需要繼承httpServlet即可雷滚。
httpServlet是特定于http協(xié)議的類,它實(shí)現(xiàn)了service()方法吗坚,并將servletRequest和servletResponse強(qiáng)轉(zhuǎn)為httpRequest和httpResponse祈远。
2呆万、sql 左外連接、右外連接车份、內(nèi)連接谋减、全連接
--左外連接,就算emp表中員工的deptno沒(méi)有與dept表中的deptno對(duì)應(yīng)也會(huì)查出來(lái)躬充,不過(guò)顯示emp表中的字段
select e.*,d.*
from emp e left join dept d on e.deptno=d.deptno;
--右外連接,就算emp表中員工的deptno沒(méi)有與dept表中的deptno對(duì)應(yīng)也會(huì)查出來(lái)讨便,不過(guò)顯示dept表中的字段
select e.*,d.*
from emp e right join dept d on e.deptno=d.deptno;
-- 內(nèi)連接充甚,只會(huì)查詢出兩表deptno一一對(duì)應(yīng)的數(shù)據(jù)
select e.*,d.*
from emp e inner join dept d on e.deptno=d.deptno;
-- 全連接,不管兩張表的數(shù)據(jù)是否一一對(duì)應(yīng)霸褒,全都會(huì)查出來(lái)
select e.*,d.*
from emp e full join dept d on e.deptno=d.deptno;
3伴找、數(shù)據(jù)庫(kù)并發(fā)問(wèn)題
數(shù)據(jù)庫(kù)帶來(lái)的并發(fā)問(wèn)題有:
- 丟失更新。
- 未確認(rèn)的相關(guān)性(臟讀)废菱。
- 不一致的分析(非重復(fù)讀)技矮。
- 幻讀。
1.1 丟失更新
當(dāng)兩個(gè)或多個(gè)事務(wù)選擇同一行殊轴,然后基于最初選定的值進(jìn)行更新衰倦,會(huì)發(fā)生丟失更新問(wèn)題。每個(gè)事務(wù)都不知道其實(shí)事務(wù)的存在旁理。最后進(jìn)行提交的事務(wù)會(huì)將之前的更新覆蓋樊零,導(dǎo)致數(shù)據(jù)丟失。
此時(shí)需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行加鎖孽文,兩種方式驻襟,一種是一開(kāi)始就鎖住,防的很徹底芋哭,但是一旦鎖的時(shí)間過(guò)長(zhǎng)會(huì)影響他人操作沉衣;另一種是在最后做更新提交時(shí)上鎖,將更新失敗視為小概率事件减牺,只在最后一步才上鎖豌习。
1.1.1 悲觀鎖
當(dāng)我們對(duì)數(shù)據(jù)進(jìn)行修改時(shí),首先需要將數(shù)據(jù)查詢出來(lái)拔疚,在查詢語(yǔ)中加鎖斑鸦,即 select .......for update nowwait
,在一開(kāi)始的查詢中就開(kāi)始加鎖草雕,避免其他用戶更新
1.1.2 樂(lè)觀鎖
(a)舊值條件法:
在更新語(yǔ)句中巷屿,使用舊的狀態(tài)值作為更新的條件(不推薦)
(b)版本列法:
當(dāng)我們?cè)O(shè)計(jì)表的時(shí)候往往會(huì)多設(shè)置兩個(gè)number/date類型的列,以便以后對(duì)表進(jìn)行拓展墩虹。我們將一個(gè)number列作為版本列嘱巾,每次修改數(shù)據(jù)時(shí)憨琳,以 限制條件 = 主鍵 + 版本列號(hào)
的形式進(jìn)行修改,同時(shí)每修改一次數(shù)據(jù)旬昭,都對(duì)版本號(hào)進(jìn)行更新篙螟。
我們通常在沖突較為嚴(yán)重的系統(tǒng)中使用悲觀鎖,其他情況優(yōu)先使用樂(lè)觀鎖问拘。
2.1 未確認(rèn)的相關(guān)性(臟讀)
當(dāng)一個(gè)事務(wù)讀取到另一個(gè)事務(wù)還未提交的修改時(shí)候遍略,產(chǎn)生臟讀。
張三的工資原本是2000骤坐,財(cái)務(wù)不小心將張三工資改成了5000绪杏,此時(shí)尚未提交,張三查詢時(shí)發(fā)現(xiàn)自己工資變成5000后很開(kāi)心纽绍,此時(shí)財(cái)務(wù)發(fā)現(xiàn)數(shù)據(jù)異常蕾久,回滾事務(wù),張三工資又變成了2000拌夏,這就叫臟讀僧著。
解決辦法:在事務(wù)提交之前,其他任何事務(wù)都不能讀取其修改過(guò)的值障簿。
3.1 不一致的分析(非重復(fù)讀)
4.1 幻讀
4盹愚、線程的兩種創(chuàng)建方式
第一種:new Thread 重寫(xiě) Thread 中的 run() 方法。
Thread thread = new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("1: " + Thread.currentThread().getName());
System.out.println("2: " + this.getName());
}
}
};
第二種:Thread 的構(gòu)造方法中有一個(gè)是以 Runnable對(duì)象為參數(shù)站故,Runnable是一個(gè)接口杯拐,當(dāng)中有run()方法,Thread是implements了Runnable接口世蔗,繼而實(shí)現(xiàn)了run()方法端逼,我們可以在new Thread的時(shí)候,通過(guò)構(gòu)造方法傳一個(gè)Runnable對(duì)象污淋,而Runnable對(duì)象中又有run()方法顶滩,通過(guò)這種方式,也能實(shí)現(xiàn)線程的創(chuàng)建寸爆。
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("3: " + Thread.currentThread().getName());
}
}
});
5礁鲁、SVN多用戶開(kāi)發(fā) --- 代碼沖突&解決
修改同一文件的不同位置引發(fā)的沖突
現(xiàn)在有兩個(gè)用戶:zhangsan 和 lisi。他們需要同時(shí)修改一個(gè)文件赁豆,原始代碼如下:
public void Test{
System.out.println("Test!");
return 1;
}
此時(shí) zhangsan 需要修改第二行代仅醇,
public void Test{
System.out.println("Test!xingoo");
return 1;
}
lisi 則修改第三行代碼,
public void Test{
System.out.println("Test!");
return 0;
}
假設(shè) zhangsan 先提交代碼魔种,當(dāng) lisi 提交代碼時(shí)析二,會(huì)提示錯(cuò)誤:
提示用戶該文件已經(jīng)過(guò)期,需要先更新文件。
此時(shí) lisi 需要先進(jìn)行更新代碼叶摄,再提交代碼属韧。
這種情況,是最簡(jiǎn)單的代碼沖突樣例蛤吓。不同用戶修改了不同位置的代碼宵喂,因此只需要在提交前進(jìn)行更新,就可以解決沖突会傲。
修改同一文件相同位置引發(fā)的沖突
還是這個(gè)例子锅棕,zhangsan 當(dāng)前代碼如下,版本號(hào)為9淌山,
public void Test{
System.out.println("Test!xingoo");
return 1;
}
lisi 代碼如下裸燎,版本號(hào)為10,
public void Test{
System.out.println("Test!xingoo");
return 0;
}
此時(shí) lisi 的代碼是最新的版本艾岂。
這時(shí)顺少,zhangsan 想要修改第三行的返回值如下朋其,
public void Test{
System.out.println("Test!xingoo");
return 2;
}
這時(shí)提交代碼會(huì)出現(xiàn)提示王浴,發(fā)生錯(cuò)誤,需要更新梅猿,OK氓辣,更新之后再次提交還是報(bào)錯(cuò),提示 文件存在沖突袱蚓!
觀察文件目錄钞啸,會(huì)發(fā)現(xiàn)多了三個(gè)文件
分別打開(kāi)三個(gè)文件:
其中<<<<<<.mine到====之間為當(dāng)前用戶修改的內(nèi)容;
====到>>>>>.r10為版本庫(kù)中的內(nèi)容:
public void Test{
System.out.println("Test!xingoo");
<<<<<<< .mine
return 2;
=======
return 0;
>>>>>>> .r10
}
test.txt.mine 記錄當(dāng)前用戶修改后的文件內(nèi)容快照
public void Test{
System.out.println("Test!xingoo");
return 2;
}
test.txt.r9 記錄當(dāng)前用戶修改前喇潘,版本庫(kù)中的內(nèi)容快照
public void Test{
System.out.println("Test!xingoo");
return 1;
}
test.txt.r10 記錄當(dāng)前版本庫(kù)中內(nèi)容快照
public void Test{
System.out.println("Test!xingoo");
return 0;
}
通過(guò)這四個(gè)文件就可以很快速的發(fā)現(xiàn)体斩,哪里有沖突。
至于如何修改:
直接拷貝mine文件颖低,然后把r10文件的r10后綴去掉絮吵,進(jìn)行更新。更新后忱屑,對(duì)比mine中的內(nèi)容在進(jìn)行修改蹬敲。
也可以直接與其他人員進(jìn)行協(xié)商溝通;更新版本庫(kù)中的內(nèi)容莺戒。
6伴嗡、排序算法
冒泡排序
左右相鄰的兩個(gè)數(shù)進(jìn)行比較,將大的放到右邊从铲,小的放到左邊瘪校,每次排序都會(huì)將最大的數(shù)放到序列的最后,最差時(shí)間復(fù)雜度為 O(n^2)名段,最好情況為 O(n)
public class BubbleSort {
public static void sort(int[] num) {
for (int i = 0; i < num.length - 1; i++) {
int demo = 0;
for(int j = 0; j < num.length -1-i; j++) {
if (num[j] > num[j + 1]) {
demo = num[j];
num[j] = num[j + 1];
num[j + 1] = demo;
}
}
}
for(int k = 0; k < num.length; k++) {
System.out.print(num[k] + ", ");
}
}
public static void main(String[] args) {
int[] num = {8, 2, 3, 1, 6, 9, 7};
sort(num);
}
}
插入排序
將序列的第一個(gè)數(shù)默認(rèn)為已排序序列渣淤,從第二個(gè)數(shù)開(kāi)始(目標(biāo)數(shù)get)赏寇,對(duì)已排序序列進(jìn)行從后往前的比較,如果已排序序列的當(dāng)前數(shù)大于get价认,則該元素移動(dòng)到下一位嗅定,重復(fù)比較,直到已排序序列的當(dāng)前數(shù)小于get用踩,則在該元素后一個(gè)位置將get插入渠退。
最好空間復(fù)雜度為 O(n),最壞為O(n^2)脐彩,與冒泡排序類似碎乃。
這個(gè)過(guò)程類似與打撲克摸手牌,此時(shí)已排序序列表左手已經(jīng)抓好的牌惠奸,get表示右手新摸到的牌梅誓,從右往左進(jìn)行比較,直到有小于get的牌佛南,在其后插入get梗掰。
public class InsertionSort {
public static void insertion(int[] arr) {
int len = arr.length;
for(int i = 1; i < len; i++) {
int get = arr[i];
int j = i -1;
while(j >= 0 && get < arr[j]) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = get;
}
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 6};
insertion(arr);
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}