第 13 章 Zend_Db

目录

13.1. Zend_Db_Adapter
13.1.1. 简介
13.1.2. 添加引号防止数据库攻击
13.1.3. 直接查询
13.1.4. 事务处理
13.1.5. 插入数据行
13.1.6. 更新数据行
13.1.7. 删除数据行
13.1.8. 取回查询结果
13.2. Zend_Db_Statement
13.2.1. Creating a Statement
13.2.2. Executing a Statement
13.2.3. Fetching Results from a SELECT Statement
13.2.3.1. Fetching a Single Row from a Result Set
13.2.3.2. Fetching a Complete Result Set
13.2.3.3. Changing the Fetch Mode
13.2.3.4. Fetching a Single Column from a Result Set
13.2.3.5. Fetching a Row as an Object
13.3. Zend_Db_Profiler
13.3.1. Introduction
13.3.2. Using the Profiler
13.3.3. Advanced Profiler Usage
13.3.3.1. Filter by query elapsed time
13.3.3.2. Filter by query type
13.3.3.3. Retrieve profiles by query type
13.3.4. Specialized Profilers
13.3.4.1. Profiling with Firebug
13.4. Zend_Db_Select
13.4.1. 简介
13.4.2. 同一表中查询多列数据
13.4.3. 多表联合查询
13.4.4. WHERE条件
13.4.5. GROUP BY分句
13.4.6. HAVING 条件
13.4.7. ORDER BY 分句
13.4.8. 通过总数和偏移量进行LIMIT限制
13.4.9. 通过页数和总数进行LIMIT限制
13.5. Zend_Db_Table
13.5.1. 简介
13.5.2. 开始
13.5.3. 表名和主键
13.5.4. 插入数据
13.5.5. 更新数据
13.5.6. Deleting Rows
13.5.7. 根据主键查找数据
13.5.8. 取回一条记录
13.5.9. 取回多条记录
13.5.10. Adding Domain Logic
13.6. Zend_Db_Table_Row
13.6.1. 简介
13.6.2. 取回一条记录
13.6.3. 修改数据
13.7. Zend_Db_Table_Rowset
13.7.1. 简介
13.7.2. 取回结果集
13.7.3. 遍历结果集
13.8. Zend_Db_Table Relationships
13.8.1. Introduction
13.8.2. Defining Relationships
13.8.3. Fetching a Dependent Rowset
13.8.4. Fetching a Parent Row
13.8.5. Fetching a Rowset via a Many-to-many Relationship
13.8.6. Cascading Write Operations
13.8.6.1. Notes Regarding Cascading Operations

13.1. Zend_Db_Adapter

13.1.1. 简介

Zend_Db_Adapter是zendfrmaeword的数据库抽象层api. 基于pdo, 你可以使用 Zend_Db_Adapter 连接和处理多种 数据库,包括:microsoft SQL Server,MySql,SQLite等等.

要针对不同的数据库实例化一个 Zend_Db_Adapter 对象, 需要 将adapter的名字和描述数据库连接的参数数组作为参数,静态调用 Zend_Db::factory()方法。例如,连接到一个数据库名称为 “camelot”,用户名为“malory”的本地mysql数据库,可以进行如下操作:

<?php

require_once 'Zend/Db.php';

$params = array ('host'     => '127.0.0.1',
                 'username' => 'malory',
                 'password' => '******',
                 'dbname'   => 'camelot');

$db = Zend_Db::factory('PDO_MYSQL', $params);

?>

同样,连接到一个库名为“camelot”的SQLite数据库:

<?php

require_once 'Zend/Db.php';

$params = array ('dbname' => 'camelot');

$db = Zend_Db::factory('PDO_SQLITE', $params);

?>

任一种方法都可以让你使用同样的api查询数据库。

13.1.2. 添加引号防止数据库攻击

你应该处理将在sql语句中使用的条件值;这对于防止sql语句攻击是很有好处的。 Zend_Db_Adapter (通过pdo)提供了两种方法帮助你手动的为条件值加上引号。

第一种是quote() 方法. 该方法会根据数据库adapter为标量加上 合适的引号;假如你试图对一个数组做quote操作, 它将为数组中 每个元素加上引号,并用","分隔返回. (对于参数很多的函数来说,这点是很有帮助的).

<?php

// 创建一个$db对象,假设数据库adapter为mysql.

// 为标量加引号
$value = $db->quote('St John"s Wort');
// $value 现在变成了 '"St John\"s Wort"' (注意两边的引号)

// 为数组加引号
$value = $db->quote(array('a', 'b', 'c');
// $value 现在变成了 '"a", "b", "c"' (","分隔的字符串)

?>

第二种是 quoteInto() 方法. 你提供一个包含问号占 位符的基础字符串 , 然后在该位置加入带引号的标量或者数组. 该 方法对于随需构建查询sql语句和条件语句是很有帮助的. 使用 quoteInto处理过的标量和数组返回结果与quote() 方法相同.

<?php

// 创建一个$db对象,假设数据库adapter为mysql.

// 在where语句中为标量加上引号
$where = $db->quoteInto('id = ?', 1);
// $where 现在为 'id = "1"' (注意两边的引号)

// 在where语句中为数组加上引号
$where = $db->quoteInto('id IN(?)', array(1, 2, 3));
// $where 现在为 'id IN("1", "2", "3")' (一个逗号分隔的字符串)

?>

13.1.3. 直接查询

一旦你得到了一个Zend_Db_Adapter 实例, 你可以直接 执行sql语句进行查询. Zend_Db_Adapter 传送这些sql语 句到底层的PDO对象,由PDO对象组合并执行他们,在有查询结果的情况 下,返回一个PDOStatement对象以便对结果进行处理。

<?php

// 创建一个$db对象,然后查询数据库
// 使用完整的sql语句直接进行查询.
$sql = $db->quoteInto(
    'SELECT * FROM example WHERE date > ?',
    '2006-01-01'
);
$result = $db->query($sql);

// 使用PDOStatement对象$result将所有结果数据放到一个数组中
$rows = $result->fetchAll();

?>

你可以将数据自动的绑定到你的查询中。这意味着你在查询中可以设定 多个指定的占位符,然后传送一个数组数据以代替这些占位符。这些替 换的数据是自动进行加引号处理的,为防止数据库攻击提供了更强的安 全性。

<?php

// 创建一个$db对象,然后查询数据库.
// 这一次,使用绑定的占位符.
$result = $db->query(
    'SELECT * FROM example WHERE date > :placeholder',
    array('placeholder' => '2006-01-01')
);

// 使用PDOStatement对象$result将所有结果数据放到一个数组中
$rows = $result->fetchAll();

?>

或者,你也可以手工设置sql语句和绑定数据到sql语句。这一功能通过 prepare() 方法得到一个设定好的PDOStatement对象,以便直 接进行数据库操作.

<?php

// 创建一个$db对象,然后查询数据库.
// 这次, 设定一个 PDOStatement 对象进行手工绑定.
$stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder');
$stmt->bindValue('placeholder', '2006-01-01');
$stmt->execute();

// 使用PDOStatement对象$result将所有结果数据放到一个数组中
$rows = $stmt->fetchAll();

?>

13.1.4. 事务处理

默认情况下,PDO(因此 Zend_Db_Adapter 也是)是采用自动commit模式。 也就是说,所有的数据库操作执行时就做了commit操作。假如你试图执行事务处理,最 简单的是调用 beginTransaction() 方法,然后选择commit或者rollback。 之后,Zend_Db_Adapter会回到自动commit模式下,直到你再次调用 beginTransaction()方法

<?php

// 创建一个 $db对象, 然后开始做一个事务处理.
$db->beginTransaction();

// 尝试数据库操作.
// 假如成功,commit该操作;
// 假如, roll back.
try {
    $db->query(...);
    $db->commit();
} catch (Exception $e) {
    $db->rollBack();
    echo $e->getMessage();
}

?>

13.1.5. 插入数据行

为了方便起见,你可以使用 insert()方法将要插入的数据绑定并创建 一个insert语句(绑定的数据是自动进行加引号处理以避免数据库攻击的)

返回值并 不是 最后插入的数据的id,这样做的原因在于一些表 并没有一个自增的字段;相反的,这个插入的返回值是改变的数据行数(通常情况为1)。 假如你需要最后插入的数据id,可以在insert执行后调用 lastInsertId() 方法。

<?php

//
// INSERT INTO round_table
//     (noble_title, first_name, favorite_color)
//     VALUES ("King", "Arthur", "blue");
//

// 创建一个 $db对象, 然后...
// 以"列名"=>"数据"的格式格式构造插入数组,插入数据行
$row = array (
    'noble_title'    => 'King',
    'first_name'     => 'Arthur',
    'favorite_color' => 'blue',
);

// 插入数据的数据表
$table = 'round_table';

// i插入数据行并返回行数
$rows_affected = $db->insert($table, $row);
$last_insert_id = $db->lastInsertId();

?>

13.1.6. 更新数据行

为了方便起见,你可以使用 update() 方法确定需要update的数据并且创建一个 update语句(确定的数据是自动加引号处理以避免数据库攻击的)。

你可以提供一个可选的where语句说明update的条件(注意:where语句并 不是一个绑定参数,所以你需要自己数据进行加引号的操作)。

<?php

//
// UPDATE round_table
//     SET favorite_color = "yellow"
//     WHERE first_name = "Robin";
//

// 创建一个 $db对象, 然后...
// 以"列名"=>"数据"的格式构造更新数组,更新数据行
$set = array (
    'favorite_color' => 'yellow',
);

// 更新的数据表
$table = 'round_table';

// where语句
$where = $db->quoteInto('first_name = ?', 'Robin');

// 更新表数据,返回更新的行数
$rows_affected = $db->update($table, $set, $where);

?>

13.1.7. 删除数据行

为了方便起见,你可以使用 delete() 方法创建一个delete语句;你 也可以提供一个where语句以说明数据的删除条件。(注意:where语句并不是一个绑 定参数,所以你需要自己进行数据加引号处理)。

<?php

//
// 需要删除数据的表
//     WHERE first_name = "Patsy";
//

// 创建一个 $db对象, 然后...
// 设定需要删除数据的表
$table = 'round_table';

// where条件语句
$where = $db->quoteInto('first_name = ?', 'Patsy');

// 删除数据并得到影响的行数
$rows_affected = $db->delete($table, $where);

?>

13.1.8. 取回查询结果

尽管你可以使用query()方法直接对数据库进行操作,但是通常情况 下,仍然还是需要选择数据行并返回结果。以fetch开头的一系列的 方法可以实现这个要求。对于每一种 fetch系列 的方法来说,你需 要传送一个select的sql语句;假如你在操作语句中使用指定的占位符,你也可以 传送一个绑定数据的数组对你的操作语句进行处理和替换。 Fetch系列 的方法包括:

  • fetchAll()

  • fetchAssoc()

  • fetchCol()

  • fetchOne()

  • fetchPairs()

  • fetchRow()

<?php

// 创建一个 $db对象, 然后...

// 取回结果集中所有字段的值,作为连续数组返回
$result = $db->fetchAll(
    "SELECT * FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// 取回结果集中所有字段的值,作为关联数组返回
// 第一个字段作为码
$result = $db->fetchAssoc(
    "SELECT * FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// 取回所有结果行的第一个字段名
$result = $db->fetchCol(
    "SELECT first_name FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// 只取回第一个字段值
$result = $db->fetchOne(
    "SELECT COUNT(*) FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// 取回一个相关数组,第一个字段值为码
// 第二个字段为值
$result = $db->fetchPairs(
    "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// 只取回结果集的第一行
$result = $db->fetchRow(
    "SELECT * FROM round_table WHERE first_name = :name",
    array('name' => 'Lancelot')
);

?>