|
在JDBC應(yīng)用中,如果你已經(jīng)是稍有水平開(kāi)發(fā)者,你就應(yīng)該始終以PreparedStatement代替Statement.也就是說(shuō),在任何時(shí)候都不要使用Statement.
基于以下的原因:
一.代碼的可讀性和可維護(hù)性.
雖然用PreparedStatement來(lái)代替Statement會(huì)使代碼多出幾行,但這樣的代碼無(wú)論從可讀性還是可維護(hù)性上來(lái)說(shuō).都比直接用Statement的代碼高很多檔次:
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();
不用我多說(shuō),對(duì)于第一種方法.別說(shuō)其他人去讀你的代碼,就是你自己過(guò)一段時(shí)間再去讀,都會(huì)覺(jué)得傷心.
二.PreparedStatement盡最大可能提高性能.
每一種數(shù)據(jù)庫(kù)都會(huì)盡最大努力對(duì)預(yù)編譯語(yǔ)句提供最大的性能優(yōu)化.因?yàn)轭A(yù)編譯語(yǔ)句有可能被重復(fù)調(diào)用.所以語(yǔ)句在被DB的編譯器編譯后的執(zhí)行代碼被緩存下來(lái),那么下次調(diào)用時(shí)只要是相同的預(yù)編譯語(yǔ)句就不需要編譯,只要將參數(shù)直接傳入編譯過(guò)的語(yǔ)句執(zhí)行代碼中(相當(dāng)于一個(gè)涵數(shù))就會(huì)得到執(zhí)行.這并不是說(shuō)只有一個(gè) Connection中多次執(zhí)行的預(yù)編譯語(yǔ)句被緩存,而是對(duì)于整個(gè)DB中,只要預(yù)編譯的語(yǔ)句語(yǔ)法和緩存中匹配.那么在任何時(shí)候就可以不需要再次編譯而可以直接執(zhí)行.而statement的語(yǔ)句中,即使是相同一操作,而由于每次操作的數(shù)據(jù)不同所以使整個(gè)語(yǔ)句相匹配的機(jī)會(huì)極小,幾乎不太可能匹配.比如:
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即使是相同操作但因?yàn)閿?shù)據(jù)內(nèi)容不一樣,所以整個(gè)個(gè)語(yǔ)句本身不能匹配,沒(méi)有緩存語(yǔ)句的意義.事實(shí)是沒(méi)有數(shù)據(jù)庫(kù)會(huì)對(duì)普通語(yǔ)句編譯后的執(zhí)行代碼緩存.這樣每執(zhí)行一次都要對(duì)傳入的語(yǔ)句編譯一次.
當(dāng)然并不是所以預(yù)編譯語(yǔ)句都一定會(huì)被緩存,數(shù)據(jù)庫(kù)本身會(huì)用一種策略,比如使用頻度等因素來(lái)決定什么時(shí)候不再緩存已有的預(yù)編譯結(jié)果.以保存有更多的空間存儲(chǔ)新的預(yù)編譯語(yǔ)句.
三.最重要的一點(diǎn)是極大地提高了安全性.
即使到目前為止,仍有一些人連基本的惡義SQL語(yǔ)法都不知道.
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我們把[' or '1' = '1]作為varpasswd傳入進(jìn)來(lái).用戶(hù)名隨意,看看會(huì)成為什么?
select * from tb_name = '隨意' and passwd = '' or '1' = '1';
因?yàn)?1'='1'肯定成立,所以可以任何通過(guò)驗(yàn)證.更有甚者:
把[';drop table tb_name;]作為varpasswd傳入進(jìn)來(lái),則:
select * from tb_name = '隨意' and passwd = '';drop table tb_name;有些數(shù)據(jù)庫(kù)是不會(huì)讓你成功的,但也有很多數(shù)據(jù)庫(kù)就可以使這些語(yǔ)句得到執(zhí)行.
而如果你使用預(yù)編譯語(yǔ)句.你傳入的任何內(nèi)容就不會(huì)和原來(lái)的語(yǔ)句發(fā)生任何匹配的關(guān)系.(前提是數(shù)據(jù)庫(kù)本身支持預(yù)編譯,但上前可能沒(méi)有什么服務(wù)端數(shù)據(jù)庫(kù)不支持編譯了,只有少數(shù)的桌面數(shù)據(jù)庫(kù),就是直接文件訪問(wèn)的那些)只要全使用預(yù)編譯語(yǔ)句,你就用不著對(duì)傳入的數(shù)據(jù)做任何過(guò)慮.而如果使用普通的statement, 有可能要對(duì)drop,;等做費(fèi)盡心機(jī)的判斷和過(guò)慮.
上面的幾個(gè)原因,還不足讓你在任何時(shí)候都使用PreparedStatement嗎?
有的新人可能此時(shí)對(duì)于用法還不太理解下面給個(gè)小例子
Code Fragment 1:
String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE ′Colombian′";
stmt.executeUpdate(updateString);
Code Fragment 2:
PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
set中的1對(duì)應(yīng)第一個(gè)? 2對(duì)應(yīng)第二個(gè)? 同時(shí)注意你set 的類(lèi)型 是int還是string 哈哈很簡(jiǎn)單吧
原文出處:http://blog.csdn.net/spcusa/archive/2009/05/09/4164076.aspx
//ValueObject類(lèi)
//調(diào)用任務(wù)類(lèi)
//主函數(shù)
個(gè)人賬戶(hù)類(lèi):
主函數(shù)測(cè)試:
Memcached,人所皆知的remote distribute cache(不知道的可以javaeye一下下,或者google一下下,或者baidu一下下,但是鑒于baidu的排名商業(yè)味道太濃(從最近得某某事件可以看出),所以還是建議javaeye一下下),使用起來(lái)也非常的簡(jiǎn)單,它被用在了很多網(wǎng)站上面,幾乎很少有大型的網(wǎng)站不會(huì)使用memcached。
清零取位要用與,某位置一可用或
若要取反和交換,輕輕松松用異或
移位運(yùn)算
要點(diǎn) 1 它們都是雙目運(yùn)算符,兩個(gè)運(yùn)算分量都是整形,結(jié)果也是整形。
2 "<<" 左移:右邊空出的位上補(bǔ)0,左邊的位將從字頭擠掉,其值相當(dāng)于乘2。
3 ">>"右移:右邊的位被擠掉。對(duì)于左邊移出的空位,如果是正數(shù)則空位補(bǔ)0,若為負(fù)數(shù),可能補(bǔ)0或補(bǔ)1,這取決于所用的計(jì)算機(jī)系統(tǒng)。
4 ">>>"運(yùn)算符,右邊的位被擠掉,對(duì)于左邊移出的空位一概補(bǔ)上0。
位運(yùn)算符的應(yīng)用 (源操作數(shù)s 掩碼mask)
(1) 按位與-- &
1 清零特定位 (mask中特定位置0,其它位為1,s=s&mask)
2 取某數(shù)中指定位 (mask中特定位置1,其它位為0,s=s&mask)
(2) 按位或-- |
常用來(lái)將源操作數(shù)某些位置1,其它位不變。 (mask中特定位置1,其它位為0 s=s|mask)
(3) 位異或-- ^
1 使特定位的值取反 (mask中特定位置1,其它位為0 s=s^mask)
2 不引入第三變量,交換兩個(gè)變量的值 (設(shè) a=a1,b=b1)
目 標(biāo) 操 作 操作后狀態(tài)
a=a1^b1 a=a^b a=a1^b1,b=b1
b=a1^b1^b1 b=a^b a=a1^b1,b=a1
a=b1^a1^a1 a=a^b a=b1,b=a1
二進(jìn)制補(bǔ)碼運(yùn)算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)^((x^y)&((x-y)^x))
x<=y: (x|~y)&((x^y)|~(y-x))
x< y: (~x&y)|((~x|y)&(x-y))//無(wú)符號(hào)x,y比較
x<=y: (~x|y)&((x^y)|~(y-x))//無(wú)符號(hào)x,y比較
應(yīng)用舉例
(1) 判斷int型變量a是奇數(shù)還是偶數(shù)
a&1 = 0 偶數(shù)
a&1 = 1 奇數(shù)
(2) 取int型變量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1
(3) 將int型變量a的第k位清0,即a=a&~(1<<k)
(4) 將int型變量a的第k位置1, 即a=a|(1<<k)
(5) int型變量循環(huán)左移k次,即a=a<<k|a>>16-k (設(shè)sizeof(int)=16)
(6) int型變量a循環(huán)右移k次,即a=a>>k|a<<16-k (設(shè)sizeof(int)=16)
(7)整數(shù)的平均值
對(duì)于兩個(gè)整數(shù)x,y,如果用 (x+y)/2 求平均值,會(huì)產(chǎn)生溢出,因?yàn)?x+y 可能會(huì)大于INT_MAX,但是我們知道它們的平均值是肯定不會(huì)溢出的,我們用如下算法:
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
(8)判斷一個(gè)整數(shù)是不是2的冪,對(duì)于一個(gè)數(shù) x >= 0,判斷他是不是2的冪
boolean power2(int x)
{
return ((x&(x-1))==0)&&(x!=0);
}
(9)不用temp交換兩個(gè)整數(shù)
void swap(int x , int y)
{
x ^= y;
y ^= x;
x ^= y;
}
(10)計(jì)算絕對(duì)值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ; //or: (x+y)^y
}
(11)取模運(yùn)算轉(zhuǎn)化成位運(yùn)算 (在不產(chǎn)生溢出的情況下)
a % (2^n) 等價(jià)于 a & (2^n - 1)
(12)乘法運(yùn)算轉(zhuǎn)化成位運(yùn)算 (在不產(chǎn)生溢出的情況下)
a * (2^n) 等價(jià)于 a<< n
(13)除法運(yùn)算轉(zhuǎn)化成位運(yùn)算 (在不產(chǎn)生溢出的情況下)
a / (2^n) 等價(jià)于 a>> n
例: 12/8 == 12>>3
(14) a % 2 等價(jià)于 a & 1
(15) if (x == a) x= b;
else x= a;
等價(jià)于 x= a ^ b ^ x;
(16) x 的 相反數(shù) 表示為 (~x+1)
線程,是指正在執(zhí)行的一個(gè)指點(diǎn)令序列。在java平臺(tái)上是指從一個(gè)線程對(duì)象的start()開(kāi)始。運(yùn)行run方法體中的那一段相對(duì)獨(dú)立的過(guò)程。
在過(guò)去的電腦都已單CPU作為主要的處理方式,無(wú)論是PC或者是服務(wù)器都是如此。系統(tǒng)調(diào)用某一個(gè)時(shí)刻只能有一個(gè)線程運(yùn)行。當(dāng)然這當(dāng)中采用了比較多的策略來(lái)做時(shí)間片輪詢(xún)。通過(guò)不斷的調(diào)度切換來(lái)運(yùn)行線程運(yùn)行,而這種方式就叫做并發(fā)(concurrent)。
隨著工藝水平的逐漸提升,CPU的技術(shù)也在不斷增進(jìn)。因此在如今多個(gè)CPU已經(jīng)不是什么特別的,而大家常常以SMP的方式來(lái)形容多個(gè)CPU來(lái)處理兩個(gè)或者兩個(gè)以上的線程運(yùn)行方式就稱(chēng)為并行(parallel)。
繼承Thread,實(shí)現(xiàn)start()方法
要實(shí)現(xiàn)線程運(yùn)行,JAVA中有兩種方式:
實(shí)現(xiàn)Runnable,然后再傳遞給Thread實(shí)例
注意:線程對(duì)象和線程是兩個(gè)截然不同的概念。
線程對(duì)象是JVM產(chǎn)生的一個(gè)普通的Object子類(lèi)
線程是CPU分配給這個(gè)對(duì)象的一個(gè)運(yùn)行過(guò)程
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
mt.join();
Thread.sleep(3000);
mt.start();
}
}
當(dāng)線程對(duì)象mt運(yùn)行完成后,我們讓主線程休息一下,然后我們?cè)俅卧谶@個(gè)線程對(duì)象上啟動(dòng)線程.結(jié)果我們看到:
Exception in thread "main" java.lang.IllegalThreadStateException
根本原因是在以下源代碼中找出:
public synchronized void start() {
if (started)
throw new IllegalThreadStateException();
started = true;
group.add(this);
start0();
}
一個(gè)Thread的實(shí)例一旦調(diào)用start()方法,這個(gè)實(shí)例的started標(biāo)記就標(biāo)記為true,事實(shí)中不管這個(gè)線程后來(lái)有沒(méi)有執(zhí)行到底,只要調(diào)用了一次start()就再也沒(méi)有機(jī)會(huì)運(yùn)行了,這意味著:
【通過(guò)Thread實(shí)例的start(),一個(gè)Thread的實(shí)例只能產(chǎn)生一個(gè)線程】
當(dāng)一個(gè)線程對(duì)象調(diào)用interrupt()方法,它對(duì)應(yīng)的線程并沒(méi)有被中斷,只是改變了它的中斷狀態(tài)。使當(dāng)前線程的狀態(tài)變以中斷狀態(tài),如果沒(méi)有其它影響,線程還會(huì)自己繼續(xù)執(zhí)行。只有當(dāng)線程執(zhí)行到sleep,wait,join等方法時(shí),或者自己檢查中斷狀態(tài)而拋出異常的情況下,線程才會(huì)拋出異常。
join()方法,正如第一節(jié)所言,在一個(gè)線程對(duì)象上調(diào)用join方法,是當(dāng)前線程等待這個(gè)線程對(duì)象對(duì)應(yīng)的線程結(jié)束
例如:有兩個(gè)工作,工作A要耗時(shí)10秒鐘,工作B要耗時(shí)10秒或更多。我們?cè)诔绦蛑邢壬梢粋€(gè)線程去做工作B,然后做工作A。
new B().start();//做工作B
A();//做工作A
工作A完成后,下面要等待工作B的結(jié)果來(lái)進(jìn)行處理。如果工作B還沒(méi)有完成我就不能進(jìn)行下面的工作C,所以:
B b = new B();
b.start();//做工作B
A();//做工作A
b.join();//等工作B完成.
C();//繼續(xù)工作C
原則:【join是測(cè)試其它工作狀態(tài)的唯一正確方法】
yield()方法也是類(lèi)方法,只在當(dāng)前線程上調(diào)用,理由同上,它主是讓當(dāng)前線程放棄本次分配到的時(shí)間片,調(diào)用這個(gè)方法不會(huì)提高任何效率,只是降低了CPU的總周期上面介紹的線程一些方法,基于(基礎(chǔ)篇)而言只能簡(jiǎn)單提及。以后具體應(yīng)用中我會(huì)結(jié)合實(shí)例詳細(xì)論述。
原則:【不是非常必要的情況下,沒(méi)有理由調(diào)用它】
首先明確一點(diǎn)他們的屬于普通對(duì)象方法,并非是線程對(duì)象方法;其次它們只能在同步方法中調(diào)用。線程要想調(diào)用一個(gè)對(duì)象的wait()方法就要先獲得該對(duì)象的監(jiān)視鎖,而一旦調(diào)用wait()后又立即釋放該鎖。
多個(gè)線程同時(shí)操作某一對(duì)象時(shí),一個(gè)線程對(duì)該對(duì)象的操作可能會(huì)改變其狀態(tài),而該狀態(tài)會(huì)影響另一線程對(duì)該對(duì)象的真正結(jié)果。
把一個(gè)單元聲明為synchornized,就可以讓在同一時(shí)間只有一個(gè)線程操作該方法。作為記憶可以把synchronized看作是一個(gè)鎖。但是我們要理解鎖是被動(dòng)的,還是主動(dòng)的呢?換而言之它到底鎖什么了?鎖誰(shuí)了?
例如:
synchronized(obj){
//todo…
}
如果代碼運(yùn)行到此處,synchronized首先獲取obj參數(shù)對(duì)象的鎖,若沒(méi)有獲取線程只能等待,如果多個(gè)線程運(yùn)行到這只能有一個(gè)線程獲取obj的鎖,然后再執(zhí)行{}中的代碼。因此obj作用范圍不同,控制程序也不同。
如果一個(gè)方法聲明為synchornized的,則等同于把在為個(gè)方法上調(diào)用synchornized(this)。
如果一個(gè)靜態(tài)方法被聲明為synchornized,則等同于把在為個(gè)方法上調(diào)用synchornized(類(lèi).class)
要讓一個(gè)線程得到真正意義的停止,需要了解當(dāng)前的線程在干什么,如果線程當(dāng)前沒(méi)有做什么,那立刻讓對(duì)方退出,當(dāng)然是沒(méi)有任何問(wèn)題,但是如果對(duì)方正在手頭趕工,那就必須讓他停止,然后收拾殘局。因此,首先需要了解步驟:
1. 正常運(yùn)行;
2. 處理結(jié)束前的工作,也就是準(zhǔn)備結(jié)束;
3. 結(jié)束退出。
注:以上部分概括出自某位牛人大哥的筆記,經(jīng)常拜讀他的博客對(duì)于這本書(shū)的閱讀,說(shuō)來(lái)也很慚愧。過(guò)去黎敏基本對(duì)于他翻譯過(guò)的書(shū),都有郵寄送給我,書(shū)拿到手后,都是內(nèi)心的高興——哇,不用花錢(qián)的書(shū),爽!(自己YY下)唯一要求就是能夠讀后能寫(xiě)個(gè)讀后感,但是很多次都抱歉的忽悠了他。盡管如此他這次翻譯的書(shū)還是一如既往的郵寄給我(當(dāng)然也是在我厚臉皮的去索要的前提下,哈哈),同樣答應(yīng)寫(xiě)一篇讀后感,可是遲到的讀后感一直到現(xiàn)在才肯出爐,確實(shí)有點(diǎn)對(duì)不住他。這本書(shū)是在我每天早早擠車(chē)一個(gè)星期多讀出來(lái)的,那個(gè)汽車(chē)真叫熱啊,嘿嘿。切入正題,談?wù)剬?duì)于本書(shū)的一個(gè)看法和意見(jiàn)。
這本書(shū)整體風(fēng)格基本還是沿襲了第一版本的套路,把每個(gè)重點(diǎn)都寫(xiě)成一個(gè)條目來(lái)針對(duì)性的闡述,本書(shū)總共條目為七十八條(第一版書(shū)共有五十七條)。當(dāng)中很多是在JDK5基礎(chǔ)上作為第一版的更新(與第一版比較明顯特征是把原有第一版的第五章,第六章的結(jié)構(gòu)化特征和方法換成JDK5的新特性:泛型,枚舉,方法)。
這本書(shū)我到現(xiàn)在都懷疑出版社沒(méi)有花很多時(shí)間在排版上,為什么這么說(shuō)?在黎敏在翻譯階段也就有拿書(shū)的樣稿給我看過(guò),我第一看到就是封面問(wèn)題——居然是黃色的,當(dāng)時(shí)就跟他提出來(lái),這個(gè)需要他和出版社去很好的斟酌一番。當(dāng)時(shí)黎敏也說(shuō)已經(jīng)跟出版社商量過(guò),哪知道最后拿到手上的居然還是“黃色”。可見(jiàn)出版社不知道是出于什么來(lái)考慮,讓我來(lái)猜想下:難道是怕大伙都是色盲非要用黃色來(lái)提醒大家嗎?更為失望的居然標(biāo)題使用紅色,暈啊!其次就要說(shuō)書(shū)紙張也未免太扯淡了吧?我第一感覺(jué)紙張就是草稿紙一般,實(shí)在無(wú)語(yǔ)。在代碼處理方面,顯得不如第一版的那種爽朗,是不是出版社考慮節(jié)省紙張啊?非要把很多代碼的間隔弄的特小,這樣對(duì)于可讀性來(lái)說(shuō)確實(shí)很有疲勞感。所以這里向提醒以后的出版社——你忽悠是可以,但是別把讀者當(dāng)傻瓜。
上面是談到在書(shū)的編排和效果的問(wèn)題。現(xiàn)在談?wù)剷?shū)中內(nèi)容的一些感受。整體上說(shuō)書(shū)翻譯還是可以,不過(guò)當(dāng)中也不乏一些乏味用詞過(guò)當(dāng)?shù)膯?wèn)題,這里要說(shuō)到最明顯的就是書(shū)中出現(xiàn)很多在每一個(gè)條目后的總結(jié)詞匯都或多或少帶有“本條目”一詞,個(gè)人覺(jué)得偶爾寫(xiě)寫(xiě)是沒(méi)很大問(wèn)題,但是過(guò)多重復(fù)顯得機(jī)械化的審美疲勞,甚至有時(shí)候過(guò)多這樣的詞匯對(duì)于閱讀流暢性稍微欠佳。像這樣類(lèi)似的詞匯還有——“不嚴(yán)格地講”,“簡(jiǎn)而言之”,這些詞匯確實(shí)稍微影響閱讀感。這里小糾下不爽或者錯(cuò)誤的位置:P240處第二段第三行和第四行中出現(xiàn)兩個(gè)“現(xiàn)在”,這個(gè)可能在校正時(shí)沒(méi)有很好去潤(rùn)色。P216倒數(shù)第二段第三行有一個(gè)估計(jì)是印刷錯(cuò)誤:【原】?jī)H僅一個(gè)異常就會(huì)導(dǎo)致該方法不得不外于… 如果沒(méi)有錯(cuò)的話,這個(gè)字應(yīng)該是:處。
還有類(lèi)似第二章談到的:靜態(tài)工廠方法與構(gòu)造器不同的第三的優(yōu)勢(shì)在于,它們可以返回原返回類(lèi)型的任何子類(lèi)型的對(duì)象。就這句話,老實(shí)講我真看了很久才明白啥意思。
以上是談到一些不足的細(xì)微之處,不過(guò)閱讀此書(shū)后,確實(shí)對(duì)于以前一些不起眼的所謂了解語(yǔ)法也很好的得到一次重新的認(rèn)識(shí)。比如以前在使用非檢測(cè)警告上,以前很習(xí)慣的直接在整個(gè)類(lèi)上直接使用標(biāo)記表示;對(duì)于了解for-each的循環(huán)上得到進(jìn)一步的認(rèn)識(shí);對(duì)于枚舉類(lèi)型的使用上更加靈活。這些都是個(gè)人對(duì)于此書(shū)泛讀之后的一些淺薄的看法。如果對(duì)于譯者有不敬之處還望原諒!
摘要: Xml Schema的用途 1. 定義一個(gè)Xml文檔中都有什么元素 2. 定義一個(gè)Xml文檔中都會(huì)有什么屬性 3. 定義某個(gè)節(jié)點(diǎn)的都有什么樣的子節(jié)點(diǎn),可以有多少個(gè)子節(jié)點(diǎn),子節(jié)點(diǎn)出現(xiàn)的順序 4. 定義元素或者屬性的數(shù)據(jù)類(lèi)型 5. 定義元素或者屬性的默認(rèn)值或者固定值 Xml Schema的根元素: <?xml version="1.... 閱讀全文