上一節(jié),大概了解了Zend Framework完成數(shù)據(jù)庫(kù)操作的常用類(lèi),下面一一簡(jiǎn)單介紹其用法。
Zend_Db_Adapter是我們操作數(shù)據(jù)庫(kù)的常用方式,以下是幾個(gè)比較重要的功能使用說(shuō)明:
1.建立數(shù)據(jù)庫(kù)鏈接
require_once 'Zend/Db.php'; $params = array ('host' => '127.0.0.1', 'username' => 'root', 'password' => '', 'dbname' => 'test'); $db = Zend_Db::factory('PDO_MYSQL', $params);
public static function factory($adapter, $config = array())
第一個(gè)參數(shù)是采用何種方式鏈接。
第二個(gè)參數(shù)是指定傳遞的鏈接參數(shù)。
我們采用的是‘PDO_MYSQL’連接方式。具體參數(shù)規(guī)則如下:
/* * Form full adapter class name */ $adapterNamespace = 'Zend_Db_Adapter'; if (isset($config['adapterNamespace'])) { if ($config['adapterNamespace'] != '') { $adapterNamespace = $config['adapterNamespace']; } unset($config['adapterNamespace']); } // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606 $adapterName = $adapterNamespace . '_'; $adapterName .= str_replace(' ', '_', ucwords(str_replace('_', ' ', strtolower($adapter)))); /* * Load the adapter class. This throws an exception * if the specified class cannot be loaded. */ if (!class_exists($adapterName)) { require_once 'Zend/Loader.php'; Zend_Loader::loadClass($adapterName); }
以下是常見(jiàn)的方式,取Zend_Db_Adapter_后面的名字作為參數(shù)。
Zend_Db_Adapter_Pdo_Sqlite
Zend_Db_Adapter_Pdo_Pgsql
Zend_Db_Adapter_Pdo_Mssql
Zend_Db_Adapter_Mysqli
Zend_Db_Adapter_Db2
Zend_Db_Adapter_Oracle
Zend_Db_Adapter_Sqlsrv
具體的配置參數(shù)可以使用查看Zend_Db_Adapter_Abstract源碼的$config。當(dāng)然你可以把配置參數(shù)放到application.ini配置文件,這里不再累述。
具體的實(shí)現(xiàn)方法如下:
/** * Factory for Zend_Db_Adapter_Abstract classes. * * First argument may be a string containing the base of the adapter class * name, e.g. 'Mysqli' corresponds to class Zend_Db_Adapter_Mysqli. This * name is currently case-insensitive, but is not ideal to rely on this behavior. * If your class is named 'My_Company_Pdo_Mysql', where 'My_Company' is the namespace * and 'Pdo_Mysql' is the adapter name, it is best to use the name exactly as it * is defined in the class. This will ensure proper use of the factory API. * * First argument may alternatively be an object of type Zend_Config. * The adapter class base name is read from the 'adapter' property. * The adapter config parameters are read from the 'params' property. * * Second argument is optional and may be an associative array of key-value * pairs. This is used as the argument to the adapter constructor. * * If the first argument is of type Zend_Config, it is assumed to contain * all parameters, and the second argument is ignored. * * @param mixed $adapter String name of base adapter class, or Zend_Config object. * @param mixed $config OPTIONAL; an array or Zend_Config object with adapter parameters. * @return Zend_Db_Adapter_Abstract * @throws Zend_Db_Exception */ public static function factory($adapter, $config = array()) { if ($config instanceof Zend_Config) { $config = $config->toArray(); } /* * Convert Zend_Config argument to plain string * adapter name and separate config object. */ if ($adapter instanceof Zend_Config) { if (isset($adapter->params)) { $config = $adapter->params->toArray(); } if (isset($adapter->adapter)) { $adapter = (string) $adapter->adapter; } else { $adapter = null; } } /* * Verify that adapter parameters are in an array. */ if (!is_array($config)) { /** * @see Zend_Db_Exception */ require_once 'Zend/Db/Exception.php'; throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object'); } /* * Verify that an adapter name has been specified. */ if (!is_string($adapter) || empty($adapter)) { /** * @see Zend_Db_Exception */ require_once 'Zend/Db/Exception.php'; throw new Zend_Db_Exception('Adapter name must be specified in a string'); } /* * Form full adapter class name */ $adapterNamespace = 'Zend_Db_Adapter'; if (isset($config['adapterNamespace'])) { if ($config['adapterNamespace'] != '') { $adapterNamespace = $config['adapterNamespace']; } unset($config['adapterNamespace']); } // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606 $adapterName = $adapterNamespace . '_'; $adapterName .= str_replace(' ', '_', ucwords(str_replace('_', ' ', strtolower($adapter)))); /* * Load the adapter class. This throws an exception * if the specified class cannot be loaded. */ if (!class_exists($adapterName)) { require_once 'Zend/Loader.php'; Zend_Loader::loadClass($adapterName); } /* * Create an instance of the adapter class. * Pass the config to the adapter class constructor. */ $dbAdapter = new $adapterName($config); /* * Verify that the object created is a descendent of the abstract adapter type. */ if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) { /** * @see Zend_Db_Exception */ require_once 'Zend/Db/Exception.php'; throw new Zend_Db_Exception("Adapter class '$adapterName' does not extend Zend_Db_Adapter_Abstract"); } return $dbAdapter; }
2.常見(jiàn)的方法
主要在Zend_Db_Adapter_Abstract抽象父類(lèi)和具體的實(shí)現(xiàn)類(lèi)。
以pdo方式的mysql文件,說(shuō)明常用的功能:
<?phpabstract class Zend_Db_Adapter_Abstract{ public function query($sql, $bind = array()) public function beginTransaction() public function commit() public function rollBack() public function insert($table, array $bind) public function update($table, array $bind, $where = '') public function delete($table, $where = '') public function select() public function getFetchMode() public function fetchAll($sql, $bind = array(), $fetchMode = null) public function fetchRow($sql, $bind = array(), $fetchMode = null) public function fetchAssoc($sql, $bind = array()) public function fetchCol($sql, $bind = array()) public function fetchPairs($sql, $bind = array()) public function fetchOne($sql, $bind = array()) public function quote($value, $type = null) public function quoteInto($text, $value, $type = null, $count = null) public function quoteIdentifier($ident, $auto=false) public function quoteColumnAs($ident, $alias, $auto=false) public function quoteTableAs($ident, $alias = null, $auto = false) }
<?phpabstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract{ public function isConnected() public function closeConnection() public function prepare($sql) public function lastInsertId($tableName = null, $primaryKey = null) public function query($sql, $bind = array()) public function exec($sql) public function setFetchMode($mode) public function supportsParameters($type) public function getServerVersion() }
<?phpclass Zend_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Abstract{ public function limit($sql, $count, $offset = 0)}
3.常見(jiàn)的方法的使用舉例
你應(yīng)該處理將在sql語(yǔ)句中使用的條件值;這對(duì)于防止sql語(yǔ)句攻擊是很有好處的。 Zend_Db_Adapter
(通過(guò)pdo)提供了兩種方法幫助你手動(dòng)的為條件值加上引號(hào)。
第一種是quote()
方法. 該方法會(huì)根據(jù)數(shù)據(jù)庫(kù)adapter為標(biāo)量加上 合適的引號(hào);假如你試圖對(duì)一個(gè)數(shù)組做quote操作, 它將為數(shù)組中 每個(gè)元素加上引號(hào),并用","分隔返回. (對(duì)于參數(shù)很多的函數(shù)來(lái)說(shuō),這點(diǎn)是很有幫助的).
<?php// 創(chuàng)建一個(gè)$db對(duì)象,假設(shè)數(shù)據(jù)庫(kù)adapter為mysql.// 為標(biāo)量加引號(hào)$value = $db->quote('St John"s Wort');// $value 現(xiàn)在變成了 '"St John"s Wort"' (注意兩邊的引號(hào))// 為數(shù)組加引號(hào)$value = $db->quote(array('a', 'b', 'c');// $value 現(xiàn)在變成了 '"a", "b", "c"' (","分隔的字符串)?>
quoteInto()
方法. 你提供一個(gè)包含問(wèn)號(hào)占 位符的基礎(chǔ)字符串 , 然后在該位置加入帶引號(hào)的標(biāo)量或者數(shù)組. 該 方法對(duì)于隨需構(gòu)建查詢(xún)sql語(yǔ)句和條件語(yǔ)句是很有幫助的. 使用 quoteInto處理過(guò)的標(biāo)量和數(shù)組返回結(jié)果與quote()
方法相同.<?php// 創(chuàng)建一個(gè)$db對(duì)象,假設(shè)數(shù)據(jù)庫(kù)adapter為mysql.// 在where語(yǔ)句中為標(biāo)量加上引號(hào)$where = $db->quoteInto('id = ?', 1);// $where 現(xiàn)在為 'id = "1"' (注意兩邊的引號(hào))// 在where語(yǔ)句中為數(shù)組加上引號(hào)$where = $db->quoteInto('id IN(?)', array(1, 2, 3));// $where 現(xiàn)在為 'id IN("1", "2", "3")' (一個(gè)逗號(hào)分隔的字符串)?>
一旦你得到了一個(gè)Zend_Db_Adapter
實(shí)例, 你可以直接 執(zhí)行sql語(yǔ)句進(jìn)行查詢(xún).Zend_Db_Adapter
傳送這些sql語(yǔ) 句到底層的PDO對(duì)象,由PDO對(duì)象組合并執(zhí)行他們,在有查詢(xún)結(jié)果的情況 下,返回一個(gè)PDOStatement對(duì)象以便對(duì)結(jié)果進(jìn)行處理。
<?php// 創(chuàng)建一個(gè)$db對(duì)象,然后查詢(xún)數(shù)據(jù)庫(kù)// 使用完整的sql語(yǔ)句直接進(jìn)行查詢(xún).$sql = $db->quoteInto( 'SELECT * FROM example WHERE date > ?', '2006-01-01');$result = $db->query($sql);// 使用PDOStatement對(duì)象$result將所有結(jié)果數(shù)據(jù)放到一個(gè)數(shù)組中$rows = $result->fetchAll();?>
你可以將數(shù)據(jù)自動(dòng)的綁定到你的查詢(xún)中。這意味著你在查詢(xún)中可以設(shè)定 多個(gè)指定的占位符,然后傳送一個(gè)數(shù)組數(shù)據(jù)以代替這些占位符。這些替 換的數(shù)據(jù)是自動(dòng)進(jìn)行加引號(hào)處理的,為防止數(shù)據(jù)庫(kù)攻擊提供了更強(qiáng)的安 全性。
<?php// 創(chuàng)建一個(gè)$db對(duì)象,然后查詢(xún)數(shù)據(jù)庫(kù).// 這一次,使用綁定的占位符.$result = $db->query( 'SELECT * FROM example WHERE date > :placeholder', array('placeholder' => '2006-01-01'));// 使用PDOStatement對(duì)象$result將所有結(jié)果數(shù)據(jù)放到一個(gè)數(shù)組中$rows = $result->fetchAll();?>
或者,你也可以手工設(shè)置sql語(yǔ)句和綁定數(shù)據(jù)到sql語(yǔ)句。這一功能通過(guò) prepare()
方法得到一個(gè)設(shè)定好的PDOStatement對(duì)象,以便直 接進(jìn)行數(shù)據(jù)庫(kù)操作.
<?php// 創(chuàng)建一個(gè)$db對(duì)象,然后查詢(xún)數(shù)據(jù)庫(kù).// 這次, 設(shè)定一個(gè) PDOStatement 對(duì)象進(jìn)行手工綁定.$stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder');$stmt->bindValue('placeholder', '2006-01-01');$stmt->execute();// 使用PDOStatement對(duì)象$result將所有結(jié)果數(shù)據(jù)放到一個(gè)數(shù)組中$rows = $stmt->fetchAll();?>
默認(rèn)情況下,PDO(因此 Zend_Db_Adapter
也是)是采用自動(dòng)commit模式。 也就是說(shuō),所有的數(shù)據(jù)庫(kù)操作執(zhí)行時(shí)就做了commit操作。假如你試圖執(zhí)行事務(wù)處理,最 簡(jiǎn)單的是調(diào)用 beginTransaction()
方法,然后選擇commit或者rollback。 之后,Zend_Db_Adapter
會(huì)回到自動(dòng)commit模式下,直到你再次調(diào)用beginTransaction()
方法
<?php// 創(chuàng)建一個(gè) $db對(duì)象, 然后開(kāi)始做一個(gè)事務(wù)處理.$db->beginTransaction();// 嘗試數(shù)據(jù)庫(kù)操作.// 假如成功,commit該操作;// 假如, roll back.try { $db->query(...); $db->commit();} catch (Exception $e) { $db->rollBack(); echo $e->getMessage();}?>
為了方便起見(jiàn),你可以使用 insert()
方法將要插入的數(shù)據(jù)綁定并創(chuàng)建 一個(gè)insert語(yǔ)句(綁定的數(shù)據(jù)是自動(dòng)進(jìn)行加引號(hào)處理以避免數(shù)據(jù)庫(kù)攻擊的)
返回值并 不是 最后插入的數(shù)據(jù)的id,這樣做的原因在于一些表 并沒(méi)有一個(gè)自增的字段;相反的,這個(gè)插入的返回值是改變的數(shù)據(jù)行數(shù)(通常情況為1)。 假如你需要最后插入的數(shù)據(jù)id,可以在insert執(zhí)行后調(diào)用lastInsertId()
方法。
<?php//// INSERT INTO round_table// (noble_title, first_name, favorite_color)// VALUES ("King", "Arthur", "blue");//// 創(chuàng)建一個(gè) $db對(duì)象, 然后...// 以"列名"=>"數(shù)據(jù)"的格式格式構(gòu)造插入數(shù)組,插入數(shù)據(jù)行$row = array ( 'noble_title' => 'King', 'first_name' => 'Arthur', 'favorite_color' => 'blue',);// 插入數(shù)據(jù)的數(shù)據(jù)表$table = 'round_table';// i插入數(shù)據(jù)行并返回行數(shù)$rows_affected = $db->insert($table, $row);$last_insert_id = $db->lastInsertId();?>
為了方便起見(jiàn),你可以使用 update()
方法確定需要update的數(shù)據(jù)并且創(chuàng)建一個(gè) update語(yǔ)句(確定的數(shù)據(jù)是自動(dòng)加引號(hào)處理以避免數(shù)據(jù)庫(kù)攻擊的)。
你可以提供一個(gè)可選的where語(yǔ)句說(shuō)明update的條件(注意:where語(yǔ)句并 不是一個(gè)綁定參數(shù),所以你需要自己數(shù)據(jù)進(jìn)行加引號(hào)的操作)。
<?php//// UPDATE round_table// SET favorite_color = "yellow"// WHERE first_name = "Robin";//// 創(chuàng)建一個(gè) $db對(duì)象, 然后...// 以"列名"=>"數(shù)據(jù)"的格式構(gòu)造更新數(shù)組,更新數(shù)據(jù)行$set = array ( 'favorite_color' => 'yellow',);// 更新的數(shù)據(jù)表$table = 'round_table';// where語(yǔ)句$where = $db->quoteInto('first_name = ?', 'Robin');// 更新表數(shù)據(jù),返回更新的行數(shù)$rows_affected = $db->update($table, $set, $where);?>
為了方便起見(jiàn),你可以使用 delete()
方法創(chuàng)建一個(gè)delete語(yǔ)句;你 也可以提供一個(gè)where語(yǔ)句以說(shuō)明數(shù)據(jù)的刪除條件。(注意:where語(yǔ)句并不是一個(gè)綁 定參數(shù),所以你需要自己進(jìn)行數(shù)據(jù)加引號(hào)處理)。
<?php//// 需要?jiǎng)h除數(shù)據(jù)的表// WHERE first_name = "Patsy";//// 創(chuàng)建一個(gè) $db對(duì)象, 然后...// 設(shè)定需要?jiǎng)h除數(shù)據(jù)的表$table = 'round_table';// where條件語(yǔ)句$where = $db->quoteInto('first_name = ?', 'Patsy');// 刪除數(shù)據(jù)并得到影響的行數(shù)$rows_affected = $db->delete($table, $where);?>
盡管你可以使用query()
方法直接對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,但是通常情況 下,仍然還是需要選擇數(shù)據(jù)行并返回結(jié)果。以fetch開(kāi)頭
的一系列的 方法可以實(shí)現(xiàn)這個(gè)要求。對(duì)于每一種fetch系列
的方法來(lái)說(shuō),你需 要傳送一個(gè)select的sql語(yǔ)句;假如你在操作語(yǔ)句中使用指定的占位符,你也可以 傳送一個(gè)綁定數(shù)據(jù)的數(shù)組對(duì)你的操作語(yǔ)句進(jìn)行處理和替換。Fetch系列
的方法包括:
fetchAll()
fetchAssoc()
fetchCol()
fetchOne()
fetchPairs()
fetchRow()
<?php// 創(chuàng)建一個(gè) $db對(duì)象, 然后...// 取回結(jié)果集中所有字段的值,作為連續(xù)數(shù)組返回$result = $db->fetchAll( "SELECT * FROM round_table WHERE noble_title = :title", array('title' => 'Sir'));// 取回結(jié)果集中所有字段的值,作為關(guān)聯(lián)數(shù)組返回// 第一個(gè)字段作為碼$result = $db->fetchAssoc( "SELECT * FROM round_table WHERE noble_title = :title", array('title' => 'Sir'));// 取回所有結(jié)果行的第一個(gè)字段名$result = $db->fetchCol( "SELECT first_name FROM round_table WHERE noble_title = :title", array('title' => 'Sir'));// 只取回第一個(gè)字段值$result = $db->fetchOne( "SELECT COUNT(*) FROM round_table WHERE noble_title = :title", array('title' => 'Sir'));// 取回一個(gè)相關(guān)數(shù)組,第一個(gè)字段值為碼// 第二個(gè)字段為值$result = $db->fetchPairs( "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title", array('title' => 'Sir'));// 只取回結(jié)果集的第一行$result = $db->fetchRow( "SELECT * FROM round_table WHERE first_name = :name", array('name' => 'Lancelot'));?>