預編譯就是把格式固定的SQL編譯后,存放在內存池中即數據庫緩沖池,當我們再次執行相同的SQL語句時就不需預編譯的過程。
1.
JDBC的話使用PReparedStatement代替Statement實現預編譯,會加快訪問數據庫的速度
使用PreparedStatement對象可以大大提高代碼的可讀性和可維護性
使用PreparedStatement對象的方法
String sql ="insert into student values(null,?,?)";
java.sql.PreparedStatement pstmt=conn.preparedStatement(sql);
pstmt.setString(1,var1);pstmt.setString(2,var2);pstmt.executeUpdate();
使用占位符?代替
將參數與SQL語句分離出來,這樣就可以方便對程序的更改和延續,同樣,也可以減少不必要的錯誤。
最后就是安全性了。以下轉自百度文庫:傳遞給PreparedStatement對象的參數可以被強制進行類型轉換,使開發人員可以確保在插入或查詢數據時與底層的數據庫格式匹配。
2.首先Mybatis,指定了傳入的參數類型parameterType來防止Sql注入,
另外自帶預編譯功能,sql注入只能對編譯過程起作用,
<select id=“getBlogById“ resultType=“Blog“ parameterType=”
int
”><br>
select id,title,author,content from blog where id=#{id}
</select>其實在框架底層,是jdbc中的PreparedStatement類在起作用,
另外內聯參數的格式由“#{xxx}”變為了${xxx}是不能防止SQL注入的
<select id=“orderBlog“ resultType=“Blog“ parameterType=”map”>
select id,title,author,content from blog order by ${orderParam}
</select>在mybatis中,”${xxx}”這樣格式的參數會直接參與sql編譯,從而不能避免注入攻擊。但涉及到動態表名和列名時,只能使用“${xxx}”這樣的參數格式,所以,這樣的參數需要我們在代碼中手工進行處理來防止注入。如何處理?
對于like語句,難免要使用$寫法,
1. 對于Oracle可以通過'%'||'#param#'||'%'避免;
2. 對于MySQL可以通過CONCAT('%',#param#,'%')避免;
3. MSSQL中通過'%'+#param#+'% 。
如下3種SQL語句:
123 | mysql: select * from user where name like concat( '%' ,#name #, '%' ) oracle: select * from user where name like '%' ||#name #|| '%' SQL Server:select * from user where name like '%' +#name #+'% |
3.Hibernate關于實現預編譯的SQL寫法,有四種
A、 按參數名稱綁定: 在HQL語句中定義命名參數要用”:”開頭,形式如下: Query query=session.createQuery(“from User user where user.name=:customername and user:customerage=:age ”); query.setString(“customername”,name); query.setInteger(“customerage”,age); 上面代碼中用:customername和:customerage分別定義了命名參數customername和customerage,然后用Query接口的setXXX()方法設定名參數值,setXXX()方法包含兩個參數,分別是命名參數名稱和命名參數實際值。 B、 按參數位置邦定: 在HQL查詢語句中用”?”來定義參數位置,形式如下: Query query=session.createQuery(“from User user where user.name=? and user.age =? ”); query.setString(0,name); query.setInteger(1,age); 同樣使用setXXX()方法設定綁定參數,只不過這時setXXX()方法的第一個參數代表邦定參數在HQL語句中出現的位置編號(由0開始編號),第二個參數仍然代表參數實際值。 注:在實際開發中,提倡使用按名稱邦定命名參數,因為這不但可以提供非常好的程序可讀性,而且也提高了程序的易維護性,因為當查詢參數的位置發生改變時,按名稱邦定名參數的方式中是不需要調整程序代碼的。 C、 setParameter()方法: 在Hibernate的HQL查詢中可以通過setParameter()方法邦定任意類型的參數,如下代碼: String hql=”from User user where user.name=:customername ”; Query query=session.createQuery(hql); query.setParameter(“customername”,name,Hibernate.STRING); 如上面代碼所示,setParameter()方法包含三個參數,分別是命名參數名稱,命名參數實際值,以及命名參數映射類型。對于某些參數類型setParameter()方法可以根據參數值的Java類型,猜測出對應的映射類型,因此這時不需要顯示寫出映射類型,像上面的例子,可以直接這樣寫: query.setParameter(“customername”,name);但是對于一些類型就必須寫明映射類型,比如java.util.Date類型,因為它會對應Hibernate的多種映射類型,比如Hibernate.DATA或者Hibernate.TIMESTAMP。 D、 setProperties()方法:(setEntity()) 在Hibernate中可以使用setProperties()方法,將命名參數與一個對象的屬性值綁定在一起,如下程序代碼: Customer customer=new Customer(); customer.setName(“pansl”); customer.setAge(80); Query query=session.createQuery(“from Customer c where c.name=:name and c.age=:age ”); query.setProperties(customer); setProperties()方法會自動將customer對象實例的屬性值匹配到命名參數上,但是要求命名參數名稱必須要與實體對象相應的屬性同名。 這里還有一個特殊的setEntity()方法,它會把命名參數與一個持久化對象相關聯,如下面代碼所示: Customer customer=(Customer)session.load(Customer.class,”1”); Query query=session.createQuery(“from Order order where order.customer=:customer ”); query. setEntity(“customer”,customer); List list=query.list(); 上面的代碼會生成類似如下的SQL語句: Select * from order where customer_ID=’1’; E、 使用綁定參數的優勢: 我們為什么要使用綁定命名參數?任何一個事物的存在都是有其價值的,具體到綁定參數對于HQL查詢來說,主要有以下兩個主要優勢: ①、 可以利用數據庫實施性能優化,因為對Hibernate來說在底層使用的是PrepareStatement來完成查詢,因此對于語法相同參數不同的SQL語句,可以充分利用預編譯SQL語句緩存,從而提升查詢效率。 ②、 可以防止SQL Injection安全漏洞的產生: SQL Injection是一種專門針對SQL語句拼裝的攻擊方式,比如對于我們常見的用戶登錄,在登錄界面上,用戶輸入用戶名和口令,這時登錄驗證程序可能會生成如下的HQL語句: “from User user where user.name=’”+name+”’ and user.passWord=’”+password+”’ ” 這個HQL語句從邏輯上來說是沒有任何問題的,這個登錄驗證功能在一般情況下也是會正確完成的,但是如果在登錄時在用戶名中輸入”zhaoxin or ‘x’=’x”,這時如果使用簡單的HQL語句的字符串拼裝,就會生成如下的HQL語句: “from User user where user.name=’zhaoxin’ or ‘x’=’x’ and user.password=’admin’ ”; 顯然這條HQL語句的where字句將會永遠為真,而使用戶口令的作用失去意義,這就是SQL Injection攻擊的基本原理。 而使用綁定參數方式,就可以妥善處理這問題,當使用綁定參數時,會得到下面的HQL語句: from User user where user.name=’’zhaoxin’’ or ‘’x=’’x’’ ‘ and user.password=’admin’;由此可見使用綁定參數會將用戶名中輸入的單引號解析成字符串(如果想在字符串中包含單引號,應使用重復單引號形式),所以參數綁定能夠有效防止SQL Injection安全漏洞。
新聞熱點
疑難解答