thinkphp 簡單的跨數據庫鏈接,不支持多表操做。

前幾天正在開發的某個項目忽然告知他們想把先後臺的數據庫分離,客戶的會員量在50W左右。他們的需求是一個數據庫只能存在一個數據服務器上,因此不能用mysql主從複製。數據庫是局域網連通的。php

當時考慮了他們的數據結構,由於客戶的功能需求特別簡單,只是註冊會員買東西算獎金。因此不多涉及到一對多關聯。mysql

因此當時採用了經過修改數據庫鏈接的方式對其它數據庫的數據進行操做。具體代碼以下:sql

\thinkphp\library\think\db\Query.php 裏的__construct  方法thinkphp

/**
* 構造函數
* @access public
* @param Connection $connection 數據庫對象實例
* @param Model $model 模型對象
*/
public function __construct(Connection $connection = null, $model = null)
{
$this->connection = $connection ?: Db::connect([], true);
//會員數據庫鏈接 生成新的鏈接
$this->userconnection= Db::connect(Config('usercon'));
$this->prefix = $this->connection->getConfig('prefix');
$this->model = $model;
// 設置當前鏈接的Builder對象
$this->setBuilder();
}數據庫

經過操做的表來判斷查詢和執行語句的數據庫鏈接緩存

public function query($sql, $bind = [], $master = false, $class = false)
{
$options = $this->parseExpress();
//判斷數據庫鏈接 
  if(in_array($options['table'],Config('usertable'))){
   return $this->userconnection->query($sql, $bind, $master, $class);
  }else{
   return $this->connection->query($sql, $bind, $master, $class);
  }
}服務器

/**
* 執行語句
* @access public
* @param string $sql sql指令
* @param array $bind 參數綁定
* @return int
* @throws BindParamException
* @throws PDOException
*/
public function execute($sql, $bind = [])
{
$options = $this->parseExpress();
//判斷數據庫鏈接 
  if(in_array($options['table'],Config('usertable'))){
   return $this->userconnection->execute($sql, $bind, $this);
  }else{
   return $this->connection->execute($sql, $bind, $this);
  }
}數據結構

/**函數

* 獲取最近插入的ID
* @access public
* @param string $sequence 自增序列名
* @return string
*/
fetch

public function getLastInsID($sequence = null)

{
  $options = $this->parseExpress();
  //判斷數據庫鏈接 
  if(in_array($options['table'],Config('usertable'))){
   return $this->userconnection->getLastInsID($sequence);
  }else{
   return $this->connection->getLastInsID($sequence);
  } 
}

/**
* 獲取最近一次查詢的sql語句
* @access public
* @return string
*/
public function getLastSql()
{
  $options = $this->parseExpress();
// //判斷數據庫鏈接 
  if(in_array($options['table'],Config('usertable'))){
   return $this->userconnection->getLastSql();
  }else{
   return $this->connection->getLastSql();
  }
}

/**
* 執行數據庫事務
* @access public
* @param callable $callback 數據操做方法回調
* @return mixed
*/
public function transaction($callback)
{

return $this->connection->transaction($callback);
}

/**
* 啓動事務
* @access public
* @return void
*/
public function startTrans()
{
$this->userconnection->startTrans();
$this->connection->startTrans();
}

/**
* 用於非自動提交狀態下面的查詢提交
* @access public
* @return void
* @throws PDOException
*/
public function commit()
{
$this->connection->commit();
$this->userconnection->commit();
}

/**
* 事務回滾
* @access public
* @return void
* @throws PDOException
*/
public function rollback()
{
$this->connection->rollback();
$this->userconnection->rollback();
}

/**
* 獲取數據表信息    
* @access public
* @param mixed $tableName 數據表名 留空自動獲取
* @param string $fetch 獲取信息類型 包括 fields type bind pk
* @return mixed
*/
public function getTableInfo($tableName = '', $fetch = '')
{

if (!$tableName) {
$tableName = $this->getTable();
}
if (is_array($tableName)) {
$tableName = key($tableName) ?: current($tableName);
}

if (strpos($tableName, ',')) {
// 多表不獲取字段信息
return false;
} else {
$tableName = $this->parseSqlTable($tableName);
}

// 修正子查詢做爲表名的問題
if (strpos($tableName, ')')) {
return [];
}

list($guid) = explode(' ', $tableName);
$db = $this->getConfig('database');
if (!isset(self::$info[$db . '.' . $guid])) {
if (!strpos($guid, '.')) {
$schema = $db . '.' . $guid;
} else {
$schema = $guid;
}
// 讀取緩存
if (!App::$debug && is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) {
$info = include RUNTIME_PATH . 'schema/' . $schema . '.php';
} else {
//判斷數據庫鏈接 
    if(in_array($tableName,Config('usertable'))){
      $info = $this->userconnection->getFields($guid);
    }else{
      $info = $this->connection->getFields($guid);
    }
$info = $this->connection->getFields($guid);
}
$fields = array_keys($info);
$bind = $type = [];
foreach ($info as $key => $val) {
// 記錄字段類型
$type[$key] = $val['type'];
$bind[$key] = $this->getFieldBindType($val['type']);
if (!empty($val['primary'])) {
$pk[] = $key;
}
}
if (isset($pk)) {
// 設置主鍵
$pk = count($pk) > 1 ? $pk : $pk[0];
} else {
$pk = null;
}
self::$info[$db . '.' . $guid] = ['fields' => $fields, 'type' => $type, 'bind' => $bind, 'pk' => $pk];
}
return $fetch ? self::$info[$db . '.' . $guid][$fetch] : self::$info[$db . '.' . $guid];
}

 

 

這樣在進行數據操做的時候,tp會自動判斷當前的sql語句要在那個數據庫上執行。

親測有效。。。寫的很差,請多多指教。。。

相關文章
相關標籤/搜索