codecamp

Joomla 使用预编译语句

在 Joomla 4 中, Joomla 数据库查询转变为使用预编译语句,本文旨在阐明我们这样做的原因和方式。

为什么要使用预编译语句(Prepared Statements)?

简单的来说,预编译语句相比之前的字符串查询语句将会有两大优势:

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

预编译语句(Prepared Statements)是什么?

通常我们的一条sql在db接收到最终执行完毕返回可以分为下面三个过程:

  • 词法和语义解析
  • 优化sql语句,制定执行计划
  • 执行并返回结果

我们把这种普通语句称作Immediate Statements。

但是很多情况,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。

所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化,一般称这类语句叫Prepared Statements或者Parameterized Statements 。

预编译语句的优势归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。

如何在Joomla中使用预编译语句(Prepared Statements)?

joomla在底层的JDatabaseDriver类中已经帮我们实现好了预编译语句这项功能,开发者只需要在写查询语句的时候调用即可。以下面的查询语句为例:

正常的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']));

 转换为预编译语句的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中进行参数绑定就实现了预编译的功能。另外,请注意最后的bind方法,在这里我们不再使用$db的quote(加引号)的方法,因为数据库驱动将自动的帮我们加上。

Joomla中使用预编译语句的一些说明

 JDatabaseDriver 会对一些函数自动使用预编译语句,如 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 ]);

 这个查询将会转换为预编译语句的SQL如下:

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

其中的占位符 :preparedArray1-3 将在执行时填充 1,2,3。

通过在where中使用占位符,在bind中进行参数绑定就实现了预编译的功能。另外,请注意最后的bind方法,在这里我们不再使用$db的quote(加引号)的方法,因为数据库驱动将自动的帮我们加上。

另外,以下函数接受数组以减少函数调用开销

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

另外在编程中使用预编译的一个好处是可以方便的使用循环,下面是一段实例代码:

$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);
}

在上面的循环中,给$username赋值,然后重新调用setQuery方法来获得数据,非常的方便。

同样,也可以使用数据组来完成参数的绑定,代码如下:

$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 作为绑定参数,并为每个变量设置正确的 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']);

 在上面参数 :username 和 :password 设置为相同的值和默认的参数类型。


Joomla 获得请求数据
Joomla 调试查询
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

处理URL请求参数

Joomla 错误和调试

Joomla 缓存

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }