THINKPHP支援ORACLE資料庫的最佳化方法

來源:互聯網
上載者:User

 

Thinkphp對Oracle的支援簡直弱爆,只做到了基本的操作,就連事務都不支援。今天來手動改一改DbOracle.class.php,讓它稍微好用一些吧。


首先是insert。原來的insert應該沒有什麼問題,但實際項目中更多的是需要在插入的時候遇到已存在的記錄則進行更新。於是,利用Oracle中的MERGE INTO來實現這一點。

public function insert($data, $options = array(), $replace = false)
{
if (!$replace) {
return parent::insert($data, $options, $replace);
}
 
$values = $fields = array();
$this->model = $options['model'];
 
$sql_merge = 'MERGE INTO ' . $this->parseTable($options['table']) .
' using (select 1 from dual) ' .
' ON (' . $this->parseValue($data[$options['marge_key']]) . ' is not null and ' . $this->parseValue($data[$options['marge_key']]) . ' = ' . $options['marge_key'] . ')';
 
//insert
foreach ($data as $key => $val) {
//主索引值為空白時,不插入主鍵
if ($this->parseKey($key) == $this->parseKey($options['marge_key'])
&& $val == null
) {
 
} elseif (is_array($val) && 'exp' == $val[0]) {
$fields[] = $this->parseKey($key);
$values[] = $val[1];
} elseif (is_scalar($val) || is_null(($val))) { // 過濾非標量資料
$fields[] = $this->parseKey($key);
if (C('DB_BIND_PARAM') && 0 !== strpos($val, ':')) {
$name = md5($key);
$values[] = ':' . $name;
$this->bindParam($name, $val);
} else {
$values[] = $this->parseValue($val);
}
}
}
$sql_insert = 'INSERT (' . implode(',', $fields) . ') VALUES (' . implode(',', $values) . ')';
 
//update
if (isset($data[$this->parseKey($options['marge_key'])])
|| $data[$this->parseKey($options['marge_key'])] == null
) {
unset($data[$this->parseKey($options['marge_key'])]);
}
$sql_update = 'UPDATE '
. $this->parseSet($data)
. $this->parseWhere(!empty($options['where']) ? $options['where'] : '')
. $this->parseOrder(!empty($options['order']) ? $options['order'] : '')
. $this->parseLimit(!empty($options['limit']) ? $options['limit'] : '');
 
$sql = $sql_merge . ' WHEN MATCHED THEN ' . $sql_update . ' WHEN NOT MATCHED THEN ' . $sql_insert;
return $this->execute($sql, $this->parseBind(!empty($options['bind']) ? $options['bind'] : array()));
}
不支援事務是Thinkphp串連Oracle時的另一個問題,架構作者似乎已經做過適配,但是應該是沒有測試,留下一堆bug。DbOracle.class.php中已經有了startTrans,commit,rollback等,稍作修改即可。

Thinkphp對資料庫的所有操作最終都是彙集到query或execute上來執行,但這兩個函數裡放了一句$this->mode = OCI_COMMIT_ON_SUCCESS;活生生的把事務扼殺了,所以,這裡先把兩個函數裡的這句注釋掉。

然後,驚人得發現execute()中調用oci_execute時根本沒有傳入mode!前面辛辛苦苦改mode又是何苦,果斷加上oci_execute($stmt, $this->mode)。

接下來才是讓事務生效的重頭戲。在事務的幾個開關函數中加入對mode的修改,在startTrans()中,將mode設為 OCI_DEFAULT,commit和rollback中將將mode設為改回OCI_COMMIT_ON_SUCCESS。這三個函數大概就是這樣子 的:

/**
    * 啟動事務
    * @access public
    * @return void
    */
    public function startTrans() {
    $this->initConnect(true);
    if ( !$this->_linkID ) return false;
    //資料rollback 支援
    if ($this->transTimes == 0) {
    $this->mode = OCI_DEFAULT;
    }
    $this->transTimes++;
    return ;
    }
    
    /**
    * 用於非自動認可狀態下面的查詢提交
    * @access public
    * @return boolen
    */
    public function commit(){
    if ($this->transTimes > 0) {
    $result = oci_commit($this->_linkID);
    if(!$result){
    $this->error();
    return false;
    }
    $this->mode = OCI_COMMIT_ON_SUCCESS;//陳宣亦 2014.11.09 14:07
    $this->transTimes = 0;
    }
    return true;
    }
    
    /**
    * 交易回復
    * @access public
    * @return boolen
    */
    public function rollback(){
    if ($this->transTimes > 0) {
    $result = oci_rollback($this->_linkID);
    if(!$result){
    $this->error();
    return false;
    }
    $this->mode = OCI_COMMIT_ON_SUCCESS;//陳宣亦 2014.11.09 14:07
    $this->transTimes = 0;
    }
    return true;
    }

還有一個頭疼的問題就是日期類型轉換,我還在尋找一種便捷的方法來解決這個問題。以後再補充上來吧。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.