主要區(qū)別: Statement執(zhí)行一條sql就得編譯一次,PrepareStatement只編譯一次,;常用后者原因在于參數(shù)設(shè)置非常方便,;執(zhí)行一條sql就得編譯一次,后者只編譯一次,;還有就是sql放置的位置不同; 常用后者原因在于參數(shù)設(shè)置非常方便,;
特性: jdbc的api中的主要的四個(gè)類之一的java.sql.statement要求開發(fā)者付出大量的時(shí)間和精力,。在使用statement獲取jdbc訪問時(shí)所具有的一個(gè)共通的問題是輸入適當(dāng)格式的日期和時(shí)間戳:2002-02-05 20:56 或者 02/05/02 8:56 pm。 通過使用java.sql.preparedstatement,,這個(gè)問題可以自動(dòng)解決,。一個(gè)preparedstatement是從 java.sql.connection對象和所提供的sql字符串得到的,sql字符串中包含問號(?),,這些問號標(biāo)明變量的位置,,然后提供變量的值, 最后執(zhí)行語句,,例如: stringsql = 'select * from people p where p.id = ? and p.name = ?'; preparedstatement ps = connection.preparestatement(sql); ps.setint(1,id); ps.setstring(2,name); resultset rs = ps.executequery();
使用preparedstatement的另一個(gè)優(yōu)點(diǎn)是字符串不是動(dòng)態(tài)創(chuàng)建的,。下面是一個(gè)動(dòng)態(tài)創(chuàng)建字符串的例子: stringsql = 'select * from people p where p.i = '+id; preparedstatement也提供數(shù)據(jù)庫無關(guān)性。當(dāng)顯示聲明的sql越少,,那么潛在的sql語句的數(shù)據(jù)庫依賴性就越小,。 由于preparedstatement具備很多優(yōu)點(diǎn),開發(fā)者可能通常都使用它,,只有在完全是因?yàn)樾阅茉蚧蛘呤窃谝恍衧ql語句中沒有變量的時(shí)候才使用通常的statement,。 一個(gè)完整的preparedstatement的例子: package jstarproject; import java.sql.*; public class mypreparedstatement { private final string db_driver='com.microsoft.jdbc.sqlserver.sqlserverdriver'; private final string url = 'jdbc:microsoft:sqlserver://127.0.0.1:1433;databasename=pubs'; public mypreparedstatement() { } public void query() throws sqlexception{ connection conn = this.getconnection(); string strsql = 'select emp_id from employee where emp_id = ?'; preparedstatement pstmt = conn.preparestatement(strsql); pstmt.setstring(1,'pma42628m'); resultset rs = pstmt.executequery(); while(rs.next()){ string fname = rs.getstring('emp_id'); system.out.println('the fname is ' + fname); } rs.close(); pstmt.close(); conn.close();
} private connection getconnection() throws sqlexception{ // class. connection conn = null; try { class.forname(db_driver); conn = drivermanager.getconnection(url,'sa','sa'); } catch (classnotfoundexception ex) {} return conn; } //main public static void main(string[] args) throws sqlexception { mypreparedstatement jdbctest1 = new mypreparedstatement(); jdbctest1.query(); } }
為什么要始終使用PreparedStatement代替Statement?為什么要始終使用PreparedStatement代替Statement? 基于以下的原因:一.代碼的可讀性和可維護(hù)性. 雖然用PreparedStatement來代替Statement會(huì)使代碼多出幾行,但這樣的代碼無論從可讀性還是可維護(hù)性上來說.都比直接用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();
二.PreparedStatement盡最大可能提高性能. 每一種數(shù)據(jù)庫都會(huì)盡最大努力對預(yù)編譯語句提供最大的性能優(yōu)化.因?yàn)轭A(yù)編譯語句有可能被重復(fù)調(diào)用.所以語句在被DB的編譯器編譯后的執(zhí)行代碼被緩存下來,那么 下次調(diào)用時(shí)只要是相同的預(yù)編譯語句就不需要編譯,只要將參數(shù)直接傳入編譯過的語句執(zhí)行代碼中(相當(dāng)于一個(gè)涵數(shù))就會(huì)得到執(zhí)行.這并不是說只有一個(gè) Connection中多次執(zhí)行的預(yù)編譯語句被緩存,而是對于整個(gè)DB中,只要預(yù)編譯的語句語法和緩存中匹配.那么在任何時(shí)候就可以不需要再次編譯而可以 直接執(zhí)行.而statement的語句中,即使是相同一操作,而由于每次操作的數(shù)據(jù)不同所以使整個(gè)語句相匹配的機(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è)語句本身不能匹配,沒有緩存語句的意義.事實(shí)是沒有數(shù)據(jù)庫會(huì)對普通語句編譯后的執(zhí)行代碼緩存.
當(dāng)然并不是所以預(yù)編譯語句都一定會(huì)被緩存,數(shù)據(jù)庫本身會(huì)用一種策略,比如使用頻度等因素來決定什么時(shí)候不再緩存已有的預(yù)編譯結(jié)果.以保存有更多的空間存儲(chǔ)新的預(yù)編譯語句.
三.最重要的一點(diǎn)是極大地提高了安全性.
即使到目前為止,仍有一些人連基本的惡義SQL語法都不知道. String sql = 'select * from tb_name where name= ''+varname+'' and passwd=''+varpasswd+'''; 如果我們把[' or '1' = '1]作為varpasswd傳入進(jìn)來.用戶名隨意,看看會(huì)成為什么?
select * from tb_name = '隨意' and passwd = '' or '1' = '1'; 因?yàn)?1'='1'肯定成立,所以可以任何通過驗(yàn)證.更有甚者: 把[';drop table tb_name;]作為varpasswd傳入進(jìn)來,則: select * from tb_name = '隨意' and passwd = '';drop table tb_name;有些數(shù)據(jù)庫是不會(huì)讓你成功的,但也有很多數(shù)據(jù)庫就可以使這些語句得到執(zhí)行.
而如果你使用預(yù)編譯語句.你傳入的任何內(nèi)容就不會(huì)和原來的語句發(fā)生任何匹配的關(guān)系.只要全使用預(yù)編譯語句,你就用不著對傳入的數(shù)據(jù)做任何過慮.而如果使用普通的statement,有可能要對drop,;等做費(fèi)盡心機(jī)的判斷和過慮.
|