如何使用Zend_Db_Adapter每次调用“查询”运行多个SQL查询?

时间:2011-09-12 23:05:33

标签: php sql zend-framework

这是我写的Zend_Application_Resource,用于在部署中进行更改时自动更新架构。

<?php

/**
 * Makes sure the current schema version matches what we're expecting for this
 * particular version of the application.
 * 
 * The version of the database is compared against the value configured in
 * application.ini. SQL scripts corresponding to versions between the database
 * version's and the current local SQL scripts are run against the database to
 * get things up to date.
 *
 * @copyright 2011 Case Western Reserve University, College of Arts and Sciences
 * @author Billy O'Neal III (bro4@case.edu)
 */
class Cas_Application_Resource_Schema extends Zend_Application_Resource_ResourceAbstract
{
    /**
     * Creates an array of filepaths corresponding to the scripts that need
     * to run.
     * 
     * @param int $from
     * @param int $to
     * @return array
     */
    private function GetScriptsToRun($from, $to)
    {
        $application = APPLICATION_PATH . '/configs/sql/';
        $result = array();
        for($cur = $from + 1; $cur <= $to; $cur++)
        {
            $result[] = "{$application}{$cur}.sql";
        }
        return $result;
    }

    /**
     * Returns the version the application is locally configured to expect.
     * 
     * @return int
     */
    private function GetLocalVersion()
    {
        $options = $this->getOptions();
        $version = (int)$options['version'];
        return $version;
    }

    /**
     * Returns the version the database thinks it is.
     * 
     * @return int
     */
    private function GetDbVersion()
    {
        $adapter = Zend_Db_Table::getDefaultAdapter();
        $metadataTable = new Cas_Model_Table_Metadata;
        $verQuery = $metadataTable->select()->from($metadataTable, array('Value'));
        $verQuery->where("{$adapter->quoteIdentifier('Key')} = ?", 'Version');
        $dbVersion = $adapter->fetchOne($verQuery);
        return (int)$dbVersion;
    }

    /**
     * Runs the specified filepath's file contents as a SQL script.
     * 
     * @param string $scriptPath
     */
    private function RunSqlScript($scriptPath)
    {
        $adapter = Zend_Db_Table::getDefaultAdapter();
        $contents = file_get_contents($scriptPath);
        $adapter->query($contents);
    }

    /**
     * Updates the version number in the database to match the version
     * specified in the local configuration file.
     */
    private function UpdateVersion()
    {
        $metadataTable = new Cas_Model_Table_Metadata;
        $metadataTable->delete(array("{$metadataTable->getAdapter()->quoteIdentifier('Key')} = ?" => 'Version'));
        $metadataTable->insert(array('Version' => $this->GetLocalVersion()));
    }

    /**
     * Performs the actual schema checks.
     */
    public function init()
    {
        //We depend on the database being connected.
        $this->getBootstrap()->bootstrap('db');
        $local = $this->GetLocalVersion();
        $remote = $this->GetDbVersion();
        if ($local < $remote)
        {
            throw new Exception('Database version is newer than local version.');
        }
        else if ($remote < $local)
        {
            $scripts = self::GetScriptsToRun($remote, $local);
            foreach($scripts as $script)
            {
                $this->RunSqlScript($script);
            }
            $this->UpdateVersion();
        }
    }
}

这会失败,因为有问题的脚本(例如configs / sql / 1.sql,configs / sql / 2.sql等)包含多个SQL语句,用; s分隔,并带有如下消息:

  

Zend_Db_Statement_Mysqli_Exception:Mysqli准备错误:您的SQL语法中有错误;检查与MySQL服务器版本对应的手册,以便在';'

附近使用正确的语法

1 个答案:

答案 0 :(得分:4)

Zend_Db_Adapter不支持multi_query()

您可以选择解决方法:

  • 调用$adapter->getConnection(),它将返回基础 mysqli 资源的实例。您可以调用此资源的multi_query()方法。

  • 将文件内容拆分为单个SQL语句的数组,并为每个语句调用$adapter->query()Be careful about edge cases.

  • 使用shell_exec()调用mysql命令行工具的子进程来处理SQL脚本。