111
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

257 行
7.6 KiB

  1. <?php
  2. /**
  3. * @copyright (C)2016-2099 Hnaoyun Inc.
  4. * @author XingMeng
  5. * @email hnxsh@foxmail.com
  6. * @date 2016年11月6日
  7. * 数据库mysqli驱动
  8. */
  9. namespace core\database;
  10. use core\basic\Config;
  11. class Mysqli implements Builder
  12. {
  13. protected static $mysqli;
  14. protected $master;
  15. protected $slave;
  16. protected $begin = false;
  17. private function __construct()
  18. {}
  19. public function __destruct()
  20. {
  21. if ($this->begin) { // 存在待提交的事务时自动进行提交
  22. $this->commit();
  23. }
  24. }
  25. // 获取单一实例,使用单一实例数据库连接类
  26. public static function getInstance()
  27. {
  28. if (! self::$mysqli) {
  29. self::$mysqli = new self();
  30. }
  31. return self::$mysqli;
  32. }
  33. // 连接数据库,接受数据库连接参数,返回数据库连接对象
  34. public function conn($cfg)
  35. {
  36. if (! extension_loaded('mysqli')) {
  37. die('未检测到您服务器环境的mysqli数据库扩展,请检查php.ini中是否已经开启该扩展!');
  38. }
  39. // 优化>php5.3版本 在win2008以上服务器连接
  40. if ($cfg['host'] == 'localhost') {
  41. $cfg['host'] = '127.0.0.1';
  42. }
  43. $conn = @new \Mysqli($cfg['host'], $cfg['user'], $cfg['passwd'], $cfg['dbname'], $cfg['port']);
  44. if (mysqli_connect_errno()) {
  45. error("连接数据库服务器失败:" . iconv('gbk', 'utf-8', mysqli_connect_error()));
  46. }
  47. $charset = Config::get('database.charset') ?: 'utf8';
  48. $conn->set_charset($charset); // 设置编码
  49. return $conn;
  50. }
  51. // 关闭自动提交,开启事务模式
  52. public function begin()
  53. {
  54. $this->master->autocommit(false);
  55. $this->begin = true;
  56. }
  57. // 提交事务
  58. public function commit()
  59. {
  60. $this->master->commit(); // 提交事务
  61. $this->master->autocommit(true); // 提交后恢复自动提交
  62. $this->begin = false; // 关闭事务模式
  63. }
  64. // 执行SQL语句,接受完整SQL语句,返回结果集对象
  65. public function query($sql, $type = 'master')
  66. {
  67. $time_s = microtime(true);
  68. switch ($type) {
  69. case 'master':
  70. if (! $this->master) {
  71. $cfg = Config::get('database');
  72. $this->master = $this->conn($cfg);
  73. $this->master->query("SET sql_mode='NO_ENGINE_SUBSTITUTION'"); // 写入规避严格模式
  74. }
  75. if (Config::get('database.transaction') && ! $this->begin) { // 根据配置开启mysql事务,注意需要是InnoDB引擎
  76. $this->begin();
  77. }
  78. $result = $this->master->query($sql) or $this->error($sql, 'master');
  79. break;
  80. case 'slave':
  81. if (! $this->slave) {
  82. // 未设置从服务器时直接读取主数据库配置
  83. if (! $cfg = Config::get('database.slave')) {
  84. $cfg = Config::get('database');
  85. } else {
  86. // 随机选择从数据库
  87. if (is_multi_array($cfg)) {
  88. $count = count($cfg);
  89. $cfg = $cfg['slave' . mt_rand(1, $count)];
  90. }
  91. }
  92. $this->slave = $this->conn($cfg);
  93. }
  94. $result = $this->slave->query($sql) or $this->error($sql, 'slave');
  95. break;
  96. }
  97. return $result;
  98. }
  99. // 数据是否存在模型,接受完整SQL语句,返回boolean数据
  100. public function isExist($sql)
  101. {
  102. $result = $this->query($sql, 'slave');
  103. if ($result->num_rows) {
  104. $result->free();
  105. return true;
  106. } else {
  107. return false;
  108. }
  109. }
  110. // 获取记录总量模型,接受数据库表名,返回int数据
  111. public function rows($table)
  112. {
  113. $sql = "SELECT count(*) FROM $table";
  114. $result = $this->query($sql, 'slave');
  115. if (! ! $row = $result->fetch_array(2)) {
  116. $result->free();
  117. return $row[0];
  118. } else {
  119. return 0;
  120. }
  121. }
  122. // 读取字段数量模型,接受数据库表名,返回int数据
  123. public function fields($table)
  124. {
  125. $sql = "SELECT * FROM $table LIMIT 1";
  126. $result = $this->query($sql, 'slave');
  127. if ($result) {
  128. return $result->field_count;
  129. } else {
  130. return 0;
  131. }
  132. }
  133. /**
  134. * 获取表信息,接受数据库表名,返回表字段信息数组
  135. *
  136. * @param $table 表名
  137. */
  138. public function tableFields($table)
  139. {
  140. $sql = "describe $table";
  141. $result = $this->query($sql, 'slave');
  142. $rows = array();
  143. if ($this->slave->affected_rows) {
  144. while (! ! $row = $result->fetch_object()) {
  145. $rows[] = $row->Field;
  146. }
  147. $result->free();
  148. }
  149. return $rows;
  150. }
  151. /**
  152. * 查询一条数据模型,接受完整SQL语句,有数据返回对象数组,否则空数组
  153. *
  154. * @$type 可以是MYSQLI_ASSOC ,MYSQLI_NUM ,MYSQLI_BOTH,不设置则返回对象数组
  155. */
  156. public function one($sql, $type = null)
  157. {
  158. $result = $this->query($sql, 'slave');
  159. $row = array();
  160. if ($this->slave->affected_rows) {
  161. if ($type) {
  162. $row = $result->fetch_array($type);
  163. } else {
  164. $row = $result->fetch_object();
  165. }
  166. $result->free();
  167. }
  168. return $row;
  169. }
  170. /**
  171. * 查询多条数据模型,接受完整SQL语句,有数据返回二维对象数组,否则空数组
  172. * @$type 可以是MYSQLI_ASSOC ,MYSQLI_NUM ,MYSQLI_BOTH,不设置则返回对象模式
  173. */
  174. public function all($sql, $type = null)
  175. {
  176. $result = $this->query($sql, 'slave');
  177. $rows = array();
  178. if ($this->slave->affected_rows) {
  179. if ($type) {
  180. while (! ! $array = $result->fetch_array($type)) { // 关联数组或数字数组或同时
  181. $rows[] = $array;
  182. }
  183. } else {
  184. while (! ! $objects = $result->fetch_object()) {
  185. $rows[] = $objects;
  186. }
  187. }
  188. $result->free();
  189. }
  190. return $rows;
  191. }
  192. // 数据增、删、改模型,接受完整SQL语句,返回影响的行数的int数据
  193. public function amd($sql)
  194. {
  195. $result = $this->query($sql, 'master');
  196. $num = $this->master->affected_rows;
  197. if ($num > 0) {
  198. return $num;
  199. } else {
  200. return 0;
  201. }
  202. }
  203. // 最近一次插入数据的自增字段值,返回int数据
  204. public function insertId()
  205. {
  206. return $this->master->insert_id;
  207. }
  208. // 执行多条SQL模型,成功返回true,否则false
  209. public function multi($sql)
  210. {
  211. $result = $this->master->multi_query($sql) or $this->error($sql);
  212. if ($result) {
  213. $result->free();
  214. return true;
  215. } else {
  216. return false;
  217. }
  218. }
  219. // 显示执行错误
  220. protected function error($sql, $conn)
  221. {
  222. $err = '错误:' . mysqli_error($this->$conn) . ',';
  223. if (preg_match('/XPATH/i', $err)) {
  224. $err = '';
  225. }
  226. if ($this->begin) { // 如果是事务模式,发生错误,则回滚
  227. $this->$conn->rollback();
  228. $this->begin = false;
  229. }
  230. error('执行SQL发生错误!' . $err . '语句:' . $sql);
  231. }
  232. }