Zend Framework DB Load Balancing (Master/Slave Database)

網路上找來找去……
沒看到有人寫相關的解法….
加上不想用mysql-proxy來解這部份…

所以打算從code 的部份下手
看到最後只能動Zend Framework 的code 了(還沒想到可以不動ZF 的code 而做到DB LB的方法)

我是先從function save 下手去找..

Zend/Table/Row/Abstract.php:    public function save()

public function save()
    {
        /**
         * If the _cleanData array is empty,
         * this is an INSERT of a new row.
         * Otherwise it is an UPDATE.
         */
        if (empty($this->_cleanData)) {
            return $this->_doInsert();
        } else {
            return $this->_doUpdate();
        }
    }

ZF會自已做update or insert 的區分

再看

/**
     * @return mixed The primary key value(s), as an associative array if the
     *     key is compound, or a scalar if the key is single-column.
     */
    protected function _doInsert()
    {
        /**
         * A read-only row cannot be saved.
         */
        if ($this->_readOnly === true) {
            require_once 'Zend/Db/Table/Row/Exception.php';
            throw new Zend_Db_Table_Row_Exception('This row has been marked read-only');
        }

        /**
         * Run pre-INSERT logic
         */
        $this->_insert();

        /**
         * Execute the INSERT (this may throw an exception)
         */
        $data = array_intersect_key($this->_data, $this->_modifiedFields);
        $primaryKey = $this->_getTable()->insert($data);

        /**
         * Normalize the result to an array indexed by primary key column(s).
         * The table insert() method may return a scalar.
         */
        if (is_array($primaryKey)) {
            $newPrimaryKey = $primaryKey;
        } else {
            $newPrimaryKey = array(current((array) $this->_primary) => $primaryKey);
        }

        /**
         * Save the new primary key value in _data.  The primary key may have
         * been generated by a sequence or auto-increment mechanism, and this
         * merge should be done before the _postInsert() method is run, so the
         * new values are available for logging, etc.
         */
        $this->_data = array_merge($this->_data, $newPrimaryKey);

        /**
         * Run post-INSERT logic
         */
        $this->_postInsert();

        /**
         * Update the _cleanData to reflect that the data has been inserted.
         */
        $this->_refresh();

        return $primaryKey;
    }

$primaryKey = $this->_getTable()->insert($data);

程式在
Zend/Adapter/Abstract.php
這邊有
function update()
function insert()

來看

public function insert($table, array $bind)
    {
        // extract and quote col names from the array keys
        $cols = array();
        $vals = array();
        foreach ($bind as $col => $val) {
            $cols[] = $this->quoteIdentifier($col, true);
            if ($val instanceof Zend_Db_Expr) {
                $vals[] = $val->__toString();
                unset($bind[$col]);
            } else {
                $vals[] = '?';
            }
        }

        // build the statement
        $sql = "INSERT INTO "
             . $this->quoteIdentifier($table, true)
             . ' (' . implode(', ', $cols) . ') '
             . 'VALUES (' . implode(', ', $vals) . ')';

        // execute the statement and return the number of affected rows
        $stmt = $this->query($sql, array_values($bind));
        $result = $stmt->rowCount();
        return $result;
    }

不管insert or update
都是透過query 這個method 去執行sql

所以就在這邊下手吧

public function query($sql, $bind = array())
    {
        // connect to the database if needed
        if ($sql instanceof Zend_Db_Select) {
            if (preg_match('/UPDATE|INSERT|REPLACE/i',$sql->__toString())) {
                $this->closeConnection();
                $this->_config['dbname'] = 'DB_WRITE';
            }
        } else {
            if (preg_match('/UPDATE|INSERT|REPLACE/i',$sql)) {
                $this->closeConnection();
                $this->_config['dbname'] = 'DB_WRITE';
            }
        }
        $this->_connect();

        // is the $sql a Zend_Db_Select object?
        if ($sql instanceof Zend_Db_Select) {
            $sql = $sql->assemble();
        }

        // make sure $bind to an array;
        // don't use (array) typecasting because
        // because $bind may be a Zend_Db_Expr object
        if (!is_array($bind)) {
            $bind = array($bind);
        }

        // prepare and execute the statement with profiling
        $stmt = $this->prepare($sql);
        $stmt->execute($bind);
        // return the results embedded in the prepared statement object
        $stmt->setFetchMode($this->_fetchMode);

        if ($sql instanceof Zend_Db_Select) {
            if (preg_match('/UPDATE|INSERT|REPLACE/i',$sql->__toString())) {
                $this->closeConnection();
                $this->_config['dbname'] = 'DB_READ';
                $this->_connect();
            }
        } else {
            if (preg_match('/UPDATE|INSERT|REPLACE/i',$sql)) {
                $this->closeConnection();
                $this->_config['dbname'] = 'DB_READ';
                $this->_connect();
            }
        }
        return $stmt;
    }

就是很簡單的去parse $sql 是否有UPDATE,INSERT,REPLACE 之類的寫入語法
若有的話就改config

基本上就是這樣…

如果有人有更好的做法…
拜拖 指教一下小第………..
實在是不想弄到ZF 裡面的code 來達到DB LB的功能..

About johnpupu

..........
This entry was posted in MySQL, program and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word