【辅导】Task17 查询数据 主要知识点
本任务以示例数据库Sakila为例,介绍如何使用面向对象mysqli,实现对数据库的参数化查询,重点是掌握PHP预处理语句的使用。
1、面向对象mysqli
Task16已经介绍了PHP访问数据库的三种方式:面向过程mysqli,面向对象mysqli,PDO。建议大家使用面向对象mysqli访问MySQL数据库。在需要访问其它类型数据库的时候,建议使用PDO。
使用面向对象mysqli访问(查询)数据库的基本过程如下:
2、query()方法
Mysqli类的query()方法,第2个参数默认值是MYSQLI_STORE_RESULT,另一个可选值是MYSQLI_USE_RESULT。
MYSQLI_STORE_RESULT:到数据库执行查询,并将结果保存到mysqli_result类对象。之后fetch时相当于在本地取数据。
MYSQLI_USE_RESULT:启动逐行检索,实际上本次并没有查询,直到fetch时,每次向数据库请求一个结果行。
总结:MYSQLI_STORE_RESULT 将查询结果缓存,处理效率较高,但内存开销比较大;MYSQLI_USE_RESULT有较低内存需求,但处理过程中需保留数据库连接。建议,使用MYSQLI_STORE_RESULT时优化SQL查询返回尽量少的数据;在需要返回大量数据时使用MYSQLI_USE_RESULT。
参阅:mysql中的MYSQLI_USE_RESULT和MYSQLI_STORE_RESULT模式分析。
2、SQL查询
对数据库的任何操作,不管是DQL(SELECT),还是DML(INSERT,UPDATE,DELETE),或者DDL(CREATE),只要写成SQL语句,交给mysqli类对象的query()方法就可以。因此:
可以执行简单的SELECT的查询,如查询Customer表某些列;
可以执行较为复杂的查询,如多表连接查询;
可以查询视图(因为可以把视图看成是单表);
可以执行存储过程;参看《PHP调用MYSQL存储过程实例》
也可以对数据库进行添加、更新、删除操作,下个任务会讲;
还可以建表、删表、增加或删除数据表列,等等。
只要能描述成SQL语句,都可以交给query()函数去执行。
3、SQL查询时,遇到特殊列,如何处理?
本任务教学视频中提到,当有如下SQL查询时:
对于带有空格的列名,使用$row = $result->fetch_assoc();方法提取记录时,没有问题,可以使用$row['zip code']获取该列值。但使用$row = $result->fetch_object();方法提取记录时,使用$row->zip code或$row->zip_code都是错误的。解决办法有二:
(1)如上图所示,给列名`zip code`起别名zip_code,可以使用$row->zip_code获取该列值。
(2)直接使用$row->{'zip code'}。
4、有参数的SQL语句(参数化查询)
为什么SQL语句需要有参数?
例如:我需要查询Customer表中id号为15的客户信息,SQL语句是:$sql='SELECT first_name,last_name FROM customer WHERE customer_id=15';
但这里的客户ID号一般是由用户在网页表单上输入的,如:
$id = $_POST['id'];
这时你就要把用户输入的$id拼接在原来sql语句字符串里面,写成这样:
$sql='SELECT first_name,last_name FROM customer WHERE customer_id='.$id;
虽然PHP支持字符串里面变量转义,但在原理上是与字符串拼接是一回事的:
$sql="SELECT first_name,last_name FROM customer WHERE customer_id={$id}";
字符串拼接带来的最主要的问题是SQL注入漏洞,造成你的网站存在很大的安全问题。比如,在输入id号的文本框中用户输入的是这样的内容:
20;insert into staff(`username`,`password`) values('hacker', 'cracked')
这样,他就很轻松地在你的数据库里面增加了一个店员(管理员)了。如果你是用MySQL数据库的root账户来建立查询的,他简直就可以为所欲为了(添加一个管理员账户?改root账户密码?)
所有我们必须使用有参数的SQL语句。因为参数限定了用户输入值只能与参数对应列匹配,从而避免了SQL注入。
Mysqli的SQL语句的参数只能使用?, 对参数赋值只能按先后顺序进行赋值。PDO可以使用命名参数。
5、有参数的SQL语句,使用prepare()函数来建立预处理语句
注意几点:
(1)使用mysqli时,bind_param()方法绑定参数的顺序与类型一定要与sql语句中?的顺序与类型保持严格一致;
s-string, i-integer, d-double, b-blob
(2)执行Select查询时,需要使用bind_result()方法绑定结果变量,结果变量顺序与SQL语句中列名顺序一致。
(3)使用execute()方法执行查询后,要使用store_result()方法将结果缓存,保存到mysqli_stmt对象,之后使用fetch()方法才能提取到每行记录的数据。
6、掌握mysqli_stmt对象的以下方法
bind_param():绑定参数变量。
bind_result():绑定结果变量,对select查询需要。
execute():执行预处理语句定义的查询。
store_result():保存查询结果,对select查询必须。
fetch():从结果中提取记录到绑定的结果变量
7、课后练习
先参照课件,完成对Sakila数据库Customer表的参数化查询。不懂的地方再回顾视频,或者QQ上问我。
有基础以后,试试自己编写检索程序,按特定条件查询Sakila数据库其它表的数据(如查询有什么名字的影片,查询xxx主演电影有哪些,顾客中有哪些是中国的)
也可以使用自己创建的数据库,或你前期上其它课程建立的数据库,练习下PHP条件查询的实现。
考虑到大家线下练习比较困难,最近基本上没有布置实验作业,有条件的请根据上述要求做下练习。返校后,将把一些本应布置的实验作业内容整合到实训中去练习。