10、PHP的PDO操作数据库prepare()、execute()和bindParam()方法详解

阅读() @2018-01-07 22:20:20

每次将查询发送给MySQL服务器时,都必须解析该查询的语法,确保结构正确并能够执行。这是这个过程中必要的步骤,但也确实带来了一些开销。做一次是必要的,但如果反复地执行相同的查询,批量插入多行并只改变列值时会怎么样呢?预处理语句会在服务器上缓存查询的语法和执行过程,而只在服务器和客户端之间传输有变化的列值,以此来消除这些额外的开销。

PDO为支持此特性的数据库提供了预处理语句功能。因为MySQL支持这个特性,所以可以在适当时使用预处理语句。

预处理语句是使用两个方法实现的:prepare()方法负责准备要执行的查询,execute()方法使用一组给定的列参数反复地执行查询。这些参数可以显式地作为数组传递给execute()方法,也可以使用通过bindParam()方法或bindValue()指定的绑定参数提供给execute()方法。

第一步:使用预处理语句——prepare()方法:

prepare()方法负责准备要执行的查询。语法格式如下:

PDOStatement PDO::prepare(string statement[,array driver_options])

但是,用作准备语句的查询与以住使用的查询略有区别,因为对于每次执行迭代中要改变的值,必须使用占位符而不是具体的列值。

查询支持两种不同的语法:命名参数和问号参数。

使用命名参数的查询如下:

INSERT INTO tb_chengji SET name=:name,age=:age;

其中,:name与:age都是列占位符。

使用问号参数的查询如下:

INSERT INTO tb_chengji SET name=?,age=?;

其中,?也是列占位符。

选择哪一种语法都可以,但是前者更明确一些。

下面使用prepare()方法准备一个用于迭代执行的查询:

$pdo = new PDO("mysql:host=localhost;dbname=list","list","list") or die("连接选择数据库失败".mysql_error());
$query = "insert into member set name=:name,age=:age";
$result = $pdo->prepare($query);

上面的代码将查询准备好了。继续下面的操作。

第二步:执行准备查询——execute()方法:

execute()方法负责执行准备好的查询。语法格式如下:

bool PDOStatement::execute([array input_parameters])

该方法需要有每次迭代执行中替换的输入参数。这可以通过两种方法实现:作为数组将值传递给方法,或者通过bindParam()方法把值绑定到查询中相应的变量名或位置偏移。

下面介绍第一种方法,第二种方法在bindParam()方法中介绍。

实例代码中准备了一条语句并通过execute()方法反复执行,每次使用不同的参数:

$pdo = new PDO("mysql:host=localhost;dbname=list","list","list") or die("连接选择数据库失败".mysql_error());
$query = "insert into member set name=:name,age=:age";
$result = $pdo->prepare($query);//准备
$result->execute(array(":name"=>"john",":age"=>"23"));//执行

看一下数据库信息,通过以上代码,我们已经成功插入一条数据记录了!

通过execute()方法将数据插入到数据库中

如果是通过【?】占位符插入数据的话,写法如下:

$pdo = new PDO("mysql:host=localhost;dbname=list","list","list") or die("连接选择数据库失败".mysql_error());
$query = "insert into member set name=?,age=?";
$result = $pdo->prepare($query);//准备
$result->execute(array("mike","24"));//执行

数据库截图如下:

通过【?】占位符插入数据

下面通过使用bindParam()方法进行绑定来传递查询参数。

绑定参数——bindParam()方法:

execute()方法中的input_parameters参数是可选的,虽然很方便,但是如果需要传递多个变量时,以这种方式提供数组会很快变得难以处理(当数组元素过多时,也就是当数据表中的列过多时,代码设计会变得特别难以阅读或出错)。使用bindParam()方法可以解决这个问题。语法格式如下:

boolean PDOStatement::bindParam(mixed parameter,mixed &variable[,int datatype[,int length[,mixed driver_options]]])

parameter:当在prepare()方法中使用命名参数时,parameter是预处理语句中使用语法(例如:name)指定的列值占位符的名字;使用问号参数时,parameter是查询中列值占位符的索引偏移。

variable:该参数存储将赋给占位符的值。它按引用传递,因为结合准备存储过程使用此方法时,可以根据存储过程的某个动作修改这个值。

datatype:该参数显式地设置参数的数据类型,可以为以下值:

1、PDO_PARAM_BOOL:SQL BOOLEAN类型。

2、PDO_PARAM_INPUT_OUTPUT:参数传递给存储过程时使用此类型,因此,可以在过程执行后修改。

3、PDO_PARAM_INT:SQL INTEGER数据类型。

4、PDO_PARAM_NULL:SQL NULL数据类型。

5、PDO_PARAM_LOB:SQL大对象数据类型。

6、PDO_PARAM_STMT:PDOStatement对象类型,当前不可操作。

7、PDO_PARAM_STR:SQL CHAR、VARCHAR和其它字符串数据类型。

8、length:该参数指定数据类型的长度。只有当赋为PDO_PARAM_INPUT_OUTPUT数据类型时才需要这个参数。

9、driver_options:该参数用来传递任何数据库驱动程序特定的选项。

下面修改前面的实例,使用bindParam()方法来赋列值:

$name1 = "Emily";
$age1 = "21";
$name2 = "Eason";
$age2 = "25";
$pdo = new PDO("mysql:host=localhost;dbname=list","list","list") or die("连接选择数据库失败".mysql_error());
$query = "insert into member set name=:name,age=:age";
$result = $pdo->prepare($query);
$result->bindParam(":name",$name1);
$result->bindParam(":age",$age1);
$result->execute();
$result->bindParam(":name",$name2);
$result->bindParam(":age",$age2);
$result->execute();

最后数据库中的记录如下:

通过【:】占位符bindParam()绑定参数

如果使用问号参数,语句则如下所示:

$query="INSERT INTO tb_chengji SET xuesheng=?,yuwen=?";

因此对应的bindParam()方法调用如下:

$name1 = "Andy";
$age1 = "28";
$name2 = "Joyce";
$age2 = "29";
$pdo = new PDO("mysql:host=localhost;dbname=list","list","list") or die("连接选择数据库失败".mysql_error());
$query = "insert into member set name=?,age=?";
$result = $pdo->prepare($query);
$result->bindParam(1,$name1);
$result->bindParam(2,$age1);
$result->execute();
$result->bindParam(1,$name2);
$result->bindParam(2,$age2);
$result->execute();

再来看看,数据库中的记录如下图:

通过【?】占位符bindParam()绑定参数

也许你已经发现了,上面的代码是逐个绑定参数进行数据插入的,如果需要插入或者是查询的数据太多的话,这样写就很麻烦了,需要有一个相对简单的方法,下面来看:

以查询为例,首先数据库中的学生记录如下图:

查看数据库中的学生记录

查询代码如下:

$age = "21";
$pdo = new PDO("mysql:host=localhost;dbname=list","list","list");
$query = "select * from member where age=:age";//查询年龄为21岁的学生
$result = $pdo->prepare($query);
$result->bindParam(":age",$age);
$result->execute();
$res = $result->fetchAll(PDO::FETCH_ASSOC);//输出关联数组形式的结果集
foreach($res as $k=>$v){
	echo $v['age'].'  ';//21  21  21  21  21  
}

再来看看批量插入数据的写法:

//将需要插入的数据组成多维关联数组
$message = array(
	array(':name'=>'student1',':age'=>'21'),
	array(':name'=>'student2',':age'=>'22'),
	array(':name'=>'student3',':age'=>'23'),
	array(':name'=>'student4',':age'=>'24'),
	array(':name'=>'student5',':age'=>'25')
);
//连接数据库
$pdo = new PDO("mysql:host=localhost;dbname=list","list","list") or die("数据库连接选择失败".mysql_error());
//插入语句
$query = "insert into member set name=:name,age=:age";
//准备
$result = $pdo->prepare($query);
//用foreach循环将每个数组里边的数据都插入到数据库
foreach($message as $key=>$value){
	foreach($value as $k=>$v){
		$result->bindValue($k,$v);
	}
       //执行
	$result->execute();
}

最后,看看数据库中的插入记录:

bindValue将数据批量插入到数据库中

这里注意一下,因为我用到了foreach循环,所以在执行绑定的时候用来bindValue,而不是bindParam,它们两者之间是有区别的,具体可查看《PHP PDO中bindParam()和bindValue()方法的区别》。

微信二维码
锐壳主机