Joomla 使用預(yù)編譯語句

2023-03-10 11:12 更新

在 Joomla 4 中, Joomla 數(shù)據(jù)庫查詢轉(zhuǎn)變?yōu)槭褂妙A(yù)編譯語句,本文旨在闡明我們這樣做的原因和方式。

為什么要使用預(yù)編譯語句(Prepared Statements)?

簡單的來說,預(yù)編譯語句相比之前的字符串查詢語句將會有兩大優(yōu)勢:

  • 更加的高效
  • 更加的安全

預(yù)編譯語句(Prepared Statements)是什么?

通常我們的一條sql在db接收到最終執(zhí)行完畢返回可以分為下面三個過程:

  • 詞法和語義解析
  • 優(yōu)化sql語句,制定執(zhí)行計劃
  • 執(zhí)行并返回結(jié)果

我們把這種普通語句稱作Immediate Statements。

但是很多情況,我們的一條sql語句可能會反復(fù)執(zhí)行,或者每次執(zhí)行的時候只有個別的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。如果每次都需要經(jīng)過上面的詞法語義解析、語句優(yōu)化、制定執(zhí)行計劃等,則效率就明顯不行了。

所謂預(yù)編譯語句就是將這類語句中的值用占位符替代,可以視為將sql語句模板化或者說參數(shù)化,一般稱這類語句叫Prepared Statements或者Parameterized Statements 。

預(yù)編譯語句的優(yōu)勢歸納為:一次編譯、多次運行,省去了解析優(yōu)化等過程;此外預(yù)編譯語句能防止sql注入。

如何在Joomla中使用預(yù)編譯語句(Prepared Statements)?

joomla在底層的JDatabaseDriver類中已經(jīng)幫我們實現(xiàn)好了預(yù)編譯語句這項功能,開發(fā)者只需要在寫查詢語句的時候調(diào)用即可。以下面的查詢語句為例:

正常的SQL語句寫法:

$query =$this->db->getQuery(true)
    ->select($this->db->quoteName(array('id','password')))
    ->from($this->db->quoteName('#__users'))
    ->where($this->db->quoteName('username') .'=' .$this->db->quote($credentials['username']));

 轉(zhuǎn)換為預(yù)編譯語句的SQL語句寫法:

$query =$this->db->getQuery(true)
    ->select($this->db->quoteName(array('id','password')))
    ->from($this->db->quoteName('#__users'))
    ->where($this->db->quoteName('username') .' = :username')
    ->bind(':username',$credentials['username']);

通過在where中使用占位符,在bind中進行參數(shù)綁定就實現(xiàn)了預(yù)編譯的功能。另外,請注意最后的bind方法,在這里我們不再使用$db的quote(加引號)的方法,因為數(shù)據(jù)庫驅(qū)動將自動的幫我們加上。

Joomla中使用預(yù)編譯語句的一些說明

 JDatabaseDriver 會對一些函數(shù)自動使用預(yù)編譯語句,如 whereIn()和whereNotIn()方法將自動的使用。

典型的代碼如下:

$query =$this->db->getQuery(true)
    ->select($this->db->quoteName(array('id, password')))
    ->from($this->db->quoteName('#__users'))
    ->whereIn($this->db->quoteName('id'), [ 1, 2, 3 ]);

 這個查詢將會轉(zhuǎn)換為預(yù)編譯語句的SQL如下:

SELECT
  `id`, `password`
FROM
  `#__users`
WHERE
  `id`IN (
    :preparedArray1,
    :preparedArray2,
    :preparedArray3
  );

其中的占位符 :preparedArray1-3 將在執(zhí)行時填充 1,2,3。

通過在where中使用占位符,在bind中進行參數(shù)綁定就實現(xiàn)了預(yù)編譯的功能。另外,請注意最后的bind方法,在這里我們不再使用$db的quote(加引號)的方法,因為數(shù)據(jù)庫驅(qū)動將自動的幫我們加上。

另外,以下函數(shù)接受數(shù)組以減少函數(shù)調(diào)用開銷

  • bind()
  • bindArray()
  • whereIn()
  • whereNotIn()

另外在編程中使用預(yù)編譯的一個好處是可以方便的使用循環(huán),下面是一段實例代碼:

$listOfUsernames = ['admin','user1' ];
 
$query =$this->db->getQuery(true)
    ->select($this->db->quoteName(array('id','password')))
    ->from($this->db->quoteName('#__users'))
    ->where($this->db->quoteName('username') .' = :username')
    ->bind(':username',$username);
 
foreach($listOfUsernames as $name)
{
  $username =$name;
  $this->db->setQuery($query);
  $user =$this->db->loadObject();
  print_r($user);
}

在上面的循環(huán)中,給$username賦值,然后重新調(diào)用setQuery方法來獲得數(shù)據(jù),非常的方便。

同樣,也可以使用數(shù)據(jù)組來完成參數(shù)的綁定,代碼如下:

$query =$this->db->getQuery(true)
    ->select($this->db->quoteName(array('id','password')))
    ->from($this->db->quoteName('#__users'))
    ->where($this->db->quoteName('username') .' = :username')
    ->where($this->db->quoteName('id') .' = :id')
    ->bind([':username',':id'], [$credentials['username'], 42], [Joomla\Database\ParameterType::STRING, Joomla\Database\ParameterType::INTEGER]);

在上面的代碼中添加 username 和 id 作為綁定參數(shù),并為每個變量設(shè)置正確的 ParameterType。也可以對所有綁定值和 ParameterType 使用一個變量。 代碼如下:

$query =$this->db->getQuery(true)
    ->select($this->db->quoteName(array('id','password')))
    ->from($this->db->quoteName('#__users'))
    ->where($this->db->quoteName('username') .' = :username')
    ->where($this->db->quoteName('password') .' = :password')
    ->bind([':username',':password], $credentials['username']);

 在上面參數(shù) :username 和 :password 設(shè)置為相同的值和默認的參數(shù)類型。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號