├── README.md ├── composer.json └── src └── Connection.php /README.md: -------------------------------------------------------------------------------- 1 | # Workerman\Mysql\Connection 2 | 3 | Long-living MySQL connection for daemon. 4 | 5 | # Install 6 | ```composer require workerman/mysql``` 7 | 8 | # Usage 9 | ```php 10 | $db = new Workerman\MySQL\Connection($mysql_host, $mysql_port, $user, $password, $db_bname); 11 | 12 | // Get all rows. 13 | $db1->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->query(); 14 | // Equivalent to. 15 | $db1->select('ID,Sex')->from('Persons')->where("sex='F'")->query(); 16 | // Equivalent to. 17 | $db->query("SELECT ID,Sex FROM `Persons` WHERE sex='M'"); 18 | 19 | 20 | // Get one row. 21 | $db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->row(); 22 | // Equivalent to. 23 | $db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->row(); 24 | // Equivalent to. 25 | $db->row("SELECT ID,Sex FROM `Persons` WHERE sex='M'"); 26 | 27 | 28 | // Get a column. 29 | $db->select('ID')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->column(); 30 | // Equivalent to. 31 | $db->select('ID')->from('Persons')->where("sex= 'F' ")->column(); 32 | // Equivalent to. 33 | $db->column("SELECT `ID` FROM `Persons` WHERE sex='M'"); 34 | 35 | // Get single. 36 | $db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->single(); 37 | // Equivalent to. 38 | $db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->single(); 39 | // Equivalent to. 40 | $db->single("SELECT ID,Sex FROM `Persons` WHERE sex='M'"); 41 | 42 | // Complex query. 43 | $db->select('*')->from('table1')->innerJoin('table2','table1.uid = table2.uid')->where('age > :age') 44 | ->groupBy(array('aid'))->having('foo="foo"')->orderByASC/*orderByDESC*/(array('did')) 45 | ->limit(10)->offset(20)->bindValues(array('age' => 13)); 46 | // Equivalent to. 47 | $db->query(SELECT * FROM `table1` INNER JOIN `table2` ON `table1`.`uid` = `table2`.`uid` WHERE age > 13 48 | GROUP BY aid HAVING foo="foo" ORDER BY did LIMIT 10 OFFSET 20“); 49 | 50 | // Insert. 51 | $insert_id = $db->insert('Persons')->cols(array( 52 | 'Firstname'=>'abc', 53 | 'Lastname'=>'efg', 54 | 'Sex'=>'M', 55 | 'Age'=>13))->query(); 56 | // Equivalent to. 57 | $insert_id = $db->query("INSERT INTO `Persons` ( `Firstname`,`Lastname`,`Sex`,`Age`) 58 | VALUES ( 'abc', 'efg', 'M', 13)"); 59 | 60 | // Update. 61 | $row_count = $db->update('Persons')->cols(array('sex'))->where('ID=1') 62 | ->bindValue('sex', 'F')->query(); 63 | // Equivalent to. 64 | $row_count = $db->update('Persons')->cols(array('sex'=>'F'))->where('ID=1')->query(); 65 | // Equivalent to. 66 | $row_count = $db->query("UPDATE `Persons` SET `sex` = 'F' WHERE ID=1"); 67 | 68 | // Delete. 69 | $row_count = $db->delete('Persons')->where('ID=9')->query(); 70 | // Equivalent to. 71 | $row_count = $db->query("DELETE FROM `Persons` WHERE ID=9"); 72 | 73 | // Transaction. 74 | $db1->beginTrans(); 75 | .... 76 | $db1->commitTrans(); // or $db1->rollBackTrans(); 77 | 78 | ``` 79 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "workerman/mysql", 3 | "type" : "library", 4 | "keywords": ["mysql", "pdo", "pdo_mysql"], 5 | "homepage": "http://www.workerman.net", 6 | "license" : "MIT", 7 | "description": "Long-living MySQL connection for daemon.", 8 | "require": { 9 | "php": ">=5.3", 10 | "ext-pdo": "*", 11 | "ext-pdo_mysql": "*" 12 | }, 13 | "autoload": { 14 | "psr-4": {"Workerman\\MySQL\\": "./src"} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Connection.php: -------------------------------------------------------------------------------- 1 | type = 'SELECT'; 220 | if (!is_array($cols)) { 221 | $cols = explode(',', $cols); 222 | } 223 | $this->cols($cols); 224 | return $this; 225 | } 226 | 227 | /** 228 | * 从哪个表删除 229 | * 230 | * @param string $table 231 | * @return self 232 | */ 233 | public function delete($table) 234 | { 235 | $this->type = 'DELETE'; 236 | $this->table = $this->quoteName($table); 237 | $this->fromRaw($this->quoteName($table)); 238 | return $this; 239 | } 240 | 241 | /** 242 | * 更新哪个表 243 | * 244 | * @param string $table 245 | * @return self 246 | */ 247 | public function update($table) 248 | { 249 | $this->type = 'UPDATE'; 250 | $this->table = $this->quoteName($table); 251 | return $this; 252 | } 253 | 254 | /** 255 | * 向哪个表插入 256 | * 257 | * @param string $table 258 | * @return self 259 | */ 260 | public function insert($table) 261 | { 262 | $this->type = 'INSERT'; 263 | $this->table = $this->quoteName($table); 264 | return $this; 265 | } 266 | 267 | /** 268 | * 269 | * 设置 SQL_CALC_FOUND_ROWS 标记. 270 | * 271 | * @param bool $enable 272 | * @return self 273 | */ 274 | public function calcFoundRows($enable = true) 275 | { 276 | $this->setFlag('SQL_CALC_FOUND_ROWS', $enable); 277 | return $this; 278 | } 279 | 280 | /** 281 | * 设置 SQL_CACHE 标记 282 | * 283 | * @param bool $enable 284 | * @return self 285 | */ 286 | public function cache($enable = true) 287 | { 288 | $this->setFlag('SQL_CACHE', $enable); 289 | return $this; 290 | } 291 | 292 | /** 293 | * 设置 SQL_NO_CACHE 标记 294 | * 295 | * @param bool $enable 296 | * @return self 297 | */ 298 | public function noCache($enable = true) 299 | { 300 | $this->setFlag('SQL_NO_CACHE', $enable); 301 | return $this; 302 | } 303 | 304 | /** 305 | * 设置 STRAIGHT_JOIN 标记. 306 | * 307 | * @param bool $enable 308 | * @return self 309 | */ 310 | public function straightJoin($enable = true) 311 | { 312 | $this->setFlag('STRAIGHT_JOIN', $enable); 313 | return $this; 314 | } 315 | 316 | /** 317 | * 设置 HIGH_PRIORITY 标记 318 | * 319 | * @param bool $enable 320 | * @return self 321 | */ 322 | public function highPriority($enable = true) 323 | { 324 | $this->setFlag('HIGH_PRIORITY', $enable); 325 | return $this; 326 | } 327 | 328 | /** 329 | * 设置 SQL_SMALL_RESULT 标记 330 | * 331 | * @param bool $enable 332 | * @return self 333 | */ 334 | public function smallResult($enable = true) 335 | { 336 | $this->setFlag('SQL_SMALL_RESULT', $enable); 337 | return $this; 338 | } 339 | 340 | /** 341 | * 设置 SQL_BIG_RESULT 标记 342 | * 343 | * @param bool $enable 344 | * @return self 345 | */ 346 | public function bigResult($enable = true) 347 | { 348 | $this->setFlag('SQL_BIG_RESULT', $enable); 349 | return $this; 350 | } 351 | 352 | /** 353 | * 设置 SQL_BUFFER_RESULT 标记 354 | * 355 | * @param bool $enable 356 | * @return self 357 | */ 358 | public function bufferResult($enable = true) 359 | { 360 | $this->setFlag('SQL_BUFFER_RESULT', $enable); 361 | return $this; 362 | } 363 | 364 | /** 365 | * 设置 FOR UPDATE 标记 366 | * 367 | * @param bool $enable 368 | * @return self 369 | */ 370 | public function forUpdate($enable = true) 371 | { 372 | $this->for_update = (bool)$enable; 373 | return $this; 374 | } 375 | 376 | /** 377 | * 设置 DISTINCT 标记 378 | * 379 | * @param bool $enable 380 | * @return self 381 | */ 382 | public function distinct($enable = true) 383 | { 384 | $this->setFlag('DISTINCT', $enable); 385 | return $this; 386 | } 387 | 388 | /** 389 | * 设置 LOW_PRIORITY 标记 390 | * 391 | * @param bool $enable 392 | * @return self 393 | */ 394 | public function lowPriority($enable = true) 395 | { 396 | $this->setFlag('LOW_PRIORITY', $enable); 397 | return $this; 398 | } 399 | 400 | /** 401 | * 设置 IGNORE 标记 402 | * 403 | * @param bool $enable 404 | * @return self 405 | */ 406 | public function ignore($enable = true) 407 | { 408 | $this->setFlag('IGNORE', $enable); 409 | return $this; 410 | } 411 | 412 | /** 413 | * 设置 QUICK 标记 414 | * 415 | * @param bool $enable 416 | * @return self 417 | */ 418 | public function quick($enable = true) 419 | { 420 | $this->setFlag('QUICK', $enable); 421 | return $this; 422 | } 423 | 424 | /** 425 | * 设置 DELAYED 标记 426 | * 427 | * @param bool $enable 428 | * @return self 429 | */ 430 | public function delayed($enable = true) 431 | { 432 | $this->setFlag('DELAYED', $enable); 433 | return $this; 434 | } 435 | 436 | /** 437 | * 序列化 438 | * 439 | * @return string 440 | */ 441 | public function __toString() 442 | { 443 | $union = ''; 444 | if ($this->union) { 445 | $union = implode(' ', $this->union) . ' '; 446 | } 447 | return $union . $this->build(); 448 | } 449 | 450 | /** 451 | * 设置每页多少条记录 452 | * 453 | * @param int $paging 454 | * @return self 455 | */ 456 | public function setPaging($paging) 457 | { 458 | $this->paging = (int)$paging; 459 | return $this; 460 | } 461 | 462 | /** 463 | * 获取每页多少条记录 464 | * 465 | * @return int 466 | */ 467 | public function getPaging() 468 | { 469 | return $this->paging; 470 | } 471 | 472 | /** 473 | * 获取绑定在占位符上的值 474 | */ 475 | public function getBindValues() 476 | { 477 | switch ($this->type) { 478 | case 'SELECT': 479 | return $this->getBindValuesSELECT(); 480 | case 'DELETE': 481 | case 'UPDATE': 482 | case 'INSERT': 483 | return $this->getBindValuesCOMMON(); 484 | default : 485 | throw new Exception("type err"); 486 | } 487 | } 488 | 489 | /** 490 | * 获取绑定在占位符上的值 491 | * 492 | * @return array 493 | */ 494 | public function getBindValuesSELECT() 495 | { 496 | $bind_values = $this->bind_values; 497 | $i = 1; 498 | foreach ($this->bind_where as $val) { 499 | $bind_values[$i] = $val; 500 | $i++; 501 | } 502 | foreach ($this->bind_having as $val) { 503 | $bind_values[$i] = $val; 504 | $i++; 505 | } 506 | return $bind_values; 507 | } 508 | 509 | /** 510 | * 511 | * SELECT选择哪些列 512 | * 513 | * @param mixed $key 514 | * @param string $val 515 | * @return void 516 | */ 517 | protected function addColSELECT($key, $val) 518 | { 519 | if (is_string($key)) { 520 | $this->cols[$val] = $key; 521 | } else { 522 | $this->addColWithAlias($val); 523 | } 524 | } 525 | 526 | /** 527 | * SELECT 增加选择的列 528 | * 529 | * @param string $spec 530 | */ 531 | protected function addColWithAlias($spec) 532 | { 533 | $parts = explode(' ', $spec); 534 | $count = count($parts); 535 | if ($count == 2 && trim($parts[0]) != '' && trim($parts[1]) != '') { 536 | $this->cols[$parts[1]] = $parts[0]; 537 | } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') { 538 | $this->cols[$parts[2]] = $parts[0]; 539 | } else { 540 | $this->cols[] = trim($spec); 541 | } 542 | } 543 | 544 | /** 545 | * from 哪个表 546 | * 547 | * @param string $table 548 | * @return self 549 | */ 550 | public function from($table) 551 | { 552 | return $this->fromRaw($this->quoteName($table)); 553 | } 554 | 555 | /** 556 | * from的表 557 | * 558 | * @param string $table 559 | * @return self 560 | */ 561 | public function fromRaw($table) 562 | { 563 | $this->from[] = array($table); 564 | $this->from_key++; 565 | return $this; 566 | } 567 | 568 | /** 569 | * 570 | * 子查询 571 | * 572 | * @param string $table 573 | * @param string $name The alias name for the sub-select. 574 | * @return self 575 | */ 576 | public function fromSubSelect($table, $name) 577 | { 578 | $this->from[] = array("($table) AS " . $this->quoteName($name)); 579 | $this->from_key++; 580 | return $this; 581 | } 582 | 583 | /** 584 | * 增加 join 语句 585 | * 586 | * @param string $table 587 | * @param string $cond 588 | * @param string $type 589 | * @return self 590 | * @throws Exception 591 | */ 592 | public function join($table, $cond = null, $type = '') 593 | { 594 | return $this->joinInternal($type, $table, $cond); 595 | } 596 | 597 | /** 598 | * 增加 join 语句 599 | * 600 | * @param string $join inner, left, natural 601 | * @param string $table 602 | * @param string $cond 603 | * @return self 604 | * @throws Exception 605 | */ 606 | protected function joinInternal($join, $table, $cond = null) 607 | { 608 | if (!$this->from) { 609 | throw new Exception('Cannot join() without from()'); 610 | } 611 | 612 | $join = strtoupper(ltrim("$join JOIN")); 613 | $table = $this->quoteName($table); 614 | $cond = $this->fixJoinCondition($cond); 615 | $this->from[$this->from_key][] = rtrim("$join $table $cond"); 616 | return $this; 617 | } 618 | 619 | /** 620 | * quote 621 | * 622 | * @param string $cond 623 | * @return string 624 | * 625 | */ 626 | protected function fixJoinCondition($cond) 627 | { 628 | if (!$cond) { 629 | return ''; 630 | } 631 | 632 | $cond = $this->quoteNamesIn($cond); 633 | 634 | if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') { 635 | return $cond; 636 | } 637 | 638 | if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') { 639 | return $cond; 640 | } 641 | 642 | return 'ON ' . $cond; 643 | } 644 | 645 | /** 646 | * inner join 647 | * 648 | * @param string $table 649 | * @param string $cond 650 | * @return self 651 | * @throws Exception 652 | */ 653 | public function innerJoin($table, $cond = null) 654 | { 655 | return $this->joinInternal('INNER', $table, $cond); 656 | } 657 | 658 | /** 659 | * left join 660 | * 661 | * @param string $table 662 | * @param string $cond 663 | * @return self 664 | * @throws Exception 665 | */ 666 | public function leftJoin($table, $cond = null) 667 | { 668 | return $this->joinInternal('LEFT', $table, $cond); 669 | } 670 | 671 | /** 672 | * right join 673 | * 674 | * @param string $table 675 | * @param string $cond 676 | * @return self 677 | * @throws Exception 678 | */ 679 | public function rightJoin($table, $cond = null) 680 | { 681 | return $this->joinInternal('RIGHT', $table, $cond); 682 | } 683 | 684 | /** 685 | * joinSubSelect 686 | * 687 | * @param string $join inner, left, natural 688 | * @param string $spec 689 | * @param string $name sub-select 的别名 690 | * @param string $cond 691 | * @return self 692 | * @throws Exception 693 | */ 694 | public function joinSubSelect($join, $spec, $name, $cond = null) 695 | { 696 | if (!$this->from) { 697 | throw new \Exception('Cannot join() without from() first.'); 698 | } 699 | 700 | $join = strtoupper(ltrim("$join JOIN")); 701 | $name = $this->quoteName($name); 702 | $cond = $this->fixJoinCondition($cond); 703 | $this->from[$this->from_key][] = rtrim("$join ($spec) AS $name $cond"); 704 | return $this; 705 | } 706 | 707 | /** 708 | * group by 语句 709 | * 710 | * @param array $cols 711 | * @return self 712 | */ 713 | public function groupBy(array $cols) 714 | { 715 | foreach ($cols as $col) { 716 | $this->group_by[] = $this->quoteNamesIn($col); 717 | } 718 | return $this; 719 | } 720 | 721 | /** 722 | * having 语句 723 | * 724 | * @param string $cond 725 | * @return self 726 | */ 727 | public function having($cond) 728 | { 729 | $this->addClauseCondWithBind('having', 'AND', func_get_args()); 730 | return $this; 731 | } 732 | 733 | /** 734 | * or having 语句 735 | * 736 | * @param string $cond The HAVING condition. 737 | * @return self 738 | */ 739 | public function orHaving($cond) 740 | { 741 | $this->addClauseCondWithBind('having', 'OR', func_get_args()); 742 | return $this; 743 | } 744 | 745 | /** 746 | * 设置每页的记录数量 747 | * 748 | * @param int $page 749 | * @return self 750 | */ 751 | public function page($page) 752 | { 753 | $this->limit = 0; 754 | $this->offset = 0; 755 | 756 | $page = (int)$page; 757 | if ($page > 0) { 758 | $this->limit = $this->paging; 759 | $this->offset = $this->paging * ($page - 1); 760 | } 761 | return $this; 762 | } 763 | 764 | /** 765 | * union 766 | * 767 | * @return self 768 | */ 769 | public function union() 770 | { 771 | $this->union[] = $this->build() . ' UNION'; 772 | $this->reset(); 773 | return $this; 774 | } 775 | 776 | /** 777 | * unionAll 778 | * 779 | * @return self 780 | */ 781 | public function unionAll() 782 | { 783 | $this->union[] = $this->build() . ' UNION ALL'; 784 | $this->reset(); 785 | return $this; 786 | } 787 | 788 | /** 789 | * 重置 790 | */ 791 | protected function reset() 792 | { 793 | $this->resetFlags(); 794 | $this->cols = array(); 795 | $this->from = array(); 796 | $this->from_key = -1; 797 | $this->where = array(); 798 | $this->group_by = array(); 799 | $this->having = array(); 800 | $this->order_by = array(); 801 | $this->limit = 0; 802 | $this->offset = 0; 803 | $this->for_update = false; 804 | } 805 | 806 | /** 807 | * 清除所有数据 808 | */ 809 | protected function resetAll() 810 | { 811 | $this->union = array(); 812 | $this->for_update = false; 813 | $this->cols = array(); 814 | $this->from = array(); 815 | $this->from_key = -1; 816 | $this->group_by = array(); 817 | $this->having = array(); 818 | $this->bind_having = array(); 819 | $this->paging = 10; 820 | $this->bind_values = array(); 821 | $this->where = array(); 822 | $this->bind_where = array(); 823 | $this->order_by = array(); 824 | $this->limit = 0; 825 | $this->offset = 0; 826 | $this->flags = array(); 827 | $this->table = ''; 828 | $this->last_insert_id_names = array(); 829 | $this->col_values = array(); 830 | $this->returning = array(); 831 | $this->parameters = array(); 832 | } 833 | 834 | /** 835 | * 创建 SELECT SQL 836 | * 837 | * @return string 838 | */ 839 | protected function buildSELECT() 840 | { 841 | return 'SELECT' 842 | . $this->buildFlags() 843 | . $this->buildCols() 844 | . $this->buildFrom() 845 | . $this->buildWhere() 846 | . $this->buildGroupBy() 847 | . $this->buildHaving() 848 | . $this->buildOrderBy() 849 | . $this->buildLimit() 850 | . $this->buildForUpdate(); 851 | } 852 | 853 | /** 854 | * 创建 DELETE SQL 855 | */ 856 | protected function buildDELETE() 857 | { 858 | return 'DELETE' 859 | . $this->buildFlags() 860 | . $this->buildFrom() 861 | . $this->buildWhere() 862 | . $this->buildOrderBy() 863 | . $this->buildLimit() 864 | . $this->buildReturning(); 865 | } 866 | 867 | /** 868 | * 生成 SELECT 列语句 869 | * 870 | * @return string 871 | * @throws Exception 872 | */ 873 | protected function buildCols() 874 | { 875 | if (!$this->cols) { 876 | throw new Exception('No columns in the SELECT.'); 877 | } 878 | 879 | $cols = array(); 880 | foreach ($this->cols as $key => $val) { 881 | if (is_int($key)) { 882 | $cols[] = $this->quoteNamesIn($val); 883 | } else { 884 | $cols[] = $this->quoteNamesIn("$val AS $key"); 885 | } 886 | } 887 | 888 | return $this->indentCsv($cols); 889 | } 890 | 891 | /** 892 | * 生成 FROM 语句. 893 | * 894 | * @return string 895 | */ 896 | protected function buildFrom() 897 | { 898 | if (!$this->from) { 899 | return ''; 900 | } 901 | 902 | $refs = array(); 903 | foreach ($this->from as $from) { 904 | $refs[] = implode(' ', $from); 905 | } 906 | return ' FROM' . $this->indentCsv($refs); 907 | } 908 | 909 | /** 910 | * 生成 GROUP BY 语句. 911 | * 912 | * @return string 913 | */ 914 | protected function buildGroupBy() 915 | { 916 | if (!$this->group_by) { 917 | return ''; 918 | } 919 | return ' GROUP BY' . $this->indentCsv($this->group_by); 920 | } 921 | 922 | /** 923 | * 生成 HAVING 语句. 924 | * 925 | * @return string 926 | */ 927 | protected function buildHaving() 928 | { 929 | if (!$this->having) { 930 | return ''; 931 | } 932 | return ' HAVING' . $this->indent($this->having); 933 | } 934 | 935 | /** 936 | * 生成 FOR UPDATE 语句 937 | * 938 | * @return string 939 | */ 940 | protected function buildForUpdate() 941 | { 942 | if (!$this->for_update) { 943 | return ''; 944 | } 945 | return ' FOR UPDATE'; 946 | } 947 | 948 | /** 949 | * where 950 | * 951 | * @param string|array $cond 952 | * @return self 953 | */ 954 | public function where($cond) 955 | { 956 | if (is_array($cond)) { 957 | foreach ($cond as $key => $val) { 958 | if (is_string($key)) { 959 | $this->addWhere('AND', array($key, $val)); 960 | } else { 961 | $this->addWhere('AND', array($val)); 962 | } 963 | } 964 | } else { 965 | $this->addWhere('AND', func_get_args()); 966 | } 967 | return $this; 968 | } 969 | 970 | /** 971 | * or where 972 | * 973 | * @param string|array $cond 974 | * @return self 975 | */ 976 | public function orWhere($cond) 977 | { 978 | if (is_array($cond)) { 979 | foreach ($cond as $key => $val) { 980 | if (is_string($key)) { 981 | $this->addWhere('OR', array($key, $val)); 982 | } else { 983 | $this->addWhere('OR', array($val)); 984 | } 985 | } 986 | } else { 987 | $this->addWhere('OR', func_get_args()); 988 | } 989 | return $this; 990 | } 991 | 992 | /** 993 | * limit 994 | * 995 | * @param int $limit 996 | * @return self 997 | */ 998 | public function limit($limit) 999 | { 1000 | $this->limit = (int)$limit; 1001 | return $this; 1002 | } 1003 | 1004 | /** 1005 | * limit offset 1006 | * 1007 | * @param int $offset 1008 | * @return self 1009 | */ 1010 | public function offset($offset) 1011 | { 1012 | $this->offset = (int)$offset; 1013 | return $this; 1014 | } 1015 | 1016 | /** 1017 | * orderby. 1018 | * 1019 | * @param array $cols 1020 | * @return self 1021 | */ 1022 | public function orderBy(array $cols) 1023 | { 1024 | $this->order_asc = null; 1025 | return $this->addOrderBy($cols); 1026 | } 1027 | 1028 | /** 1029 | * order by ASC OR DESC 1030 | * 1031 | * @param array $cols 1032 | * @param bool $order_asc 1033 | * @return self 1034 | */ 1035 | public function orderByASC(array $cols, $order_asc = true) 1036 | { 1037 | $this->order_asc = $order_asc; 1038 | return $this->addOrderBy($cols); 1039 | } 1040 | 1041 | /** 1042 | * order by DESC 1043 | * 1044 | * @param array $cols 1045 | * @return self 1046 | */ 1047 | public function orderByDESC(array $cols) 1048 | { 1049 | $this->order_asc = false; 1050 | return $this->addOrderBy($cols); 1051 | } 1052 | 1053 | // -------------abstractquery---------- 1054 | 1055 | /** 1056 | * 返回逗号分隔的字符串 1057 | * 1058 | * @param array $list 1059 | * @return string 1060 | */ 1061 | protected function indentCsv(array $list) 1062 | { 1063 | return ' ' . implode(',', $list); 1064 | } 1065 | 1066 | /** 1067 | * 返回空格分隔的字符串 1068 | * 1069 | * @param array $list 1070 | * @return string 1071 | */ 1072 | protected function indent(array $list) 1073 | { 1074 | return ' ' . implode(' ', $list); 1075 | } 1076 | 1077 | /** 1078 | * 批量为占位符绑定值 1079 | * 1080 | * @param array $bind_values 1081 | * @return self 1082 | * 1083 | */ 1084 | public function bindValues(array $bind_values) 1085 | { 1086 | foreach ($bind_values as $key => $val) { 1087 | $this->bindValue($key, $val); 1088 | } 1089 | return $this; 1090 | } 1091 | 1092 | /** 1093 | * 单个为占位符绑定值 1094 | * 1095 | * @param string $name 1096 | * @param mixed $value 1097 | * @return self 1098 | */ 1099 | public function bindValue($name, $value) 1100 | { 1101 | $this->bind_values[$name] = $value; 1102 | return $this; 1103 | } 1104 | 1105 | /** 1106 | * 生成 flag 1107 | * 1108 | * @return string 1109 | */ 1110 | protected function buildFlags() 1111 | { 1112 | if (!$this->flags) { 1113 | return ''; 1114 | } 1115 | return ' ' . implode(' ', array_keys($this->flags)); 1116 | } 1117 | 1118 | /** 1119 | * 设置 flag. 1120 | * 1121 | * @param string $flag 1122 | * @param bool $enable 1123 | */ 1124 | protected function setFlag($flag, $enable = true) 1125 | { 1126 | if ($enable) { 1127 | $this->flags[$flag] = true; 1128 | } else { 1129 | unset($this->flags[$flag]); 1130 | } 1131 | } 1132 | 1133 | /** 1134 | * 重置 flag 1135 | */ 1136 | protected function resetFlags() 1137 | { 1138 | $this->flags = array(); 1139 | } 1140 | 1141 | /** 1142 | * 1143 | * 添加 where 语句 1144 | * 1145 | * @param string $andor 'AND' or 'OR 1146 | * @param array $conditions 1147 | * @return self 1148 | * 1149 | */ 1150 | protected function addWhere($andor, $conditions) 1151 | { 1152 | $this->addClauseCondWithBind('where', $andor, $conditions); 1153 | return $this; 1154 | } 1155 | 1156 | /** 1157 | * 添加条件和绑定值 1158 | * 1159 | * @param string $clause where 、having等 1160 | * @param string $andor AND、OR等 1161 | * @param array $conditions 1162 | */ 1163 | protected function addClauseCondWithBind($clause, $andor, $conditions) 1164 | { 1165 | $cond = array_shift($conditions); 1166 | $cond = $this->quoteNamesIn($cond); 1167 | 1168 | $bind =& $this->{"bind_{$clause}"}; 1169 | foreach ($conditions as $value) { 1170 | $bind[] = $value; 1171 | } 1172 | 1173 | $clause =& $this->$clause; 1174 | if ($clause) { 1175 | $clause[] = "$andor $cond"; 1176 | } else { 1177 | $clause[] = $cond; 1178 | } 1179 | } 1180 | 1181 | /** 1182 | * 生成 where 语句 1183 | * 1184 | * @return string 1185 | */ 1186 | protected function buildWhere() 1187 | { 1188 | if (!$this->where) { 1189 | return ''; 1190 | } 1191 | return ' WHERE' . $this->indent($this->where); 1192 | } 1193 | 1194 | /** 1195 | * 增加 order by 1196 | * 1197 | * @param array $spec The columns and direction to order by. 1198 | * @return self 1199 | */ 1200 | protected function addOrderBy(array $spec) 1201 | { 1202 | foreach ($spec as $col) { 1203 | $this->order_by[] = $this->quoteNamesIn($col); 1204 | } 1205 | return $this; 1206 | } 1207 | 1208 | /** 1209 | * 生成 order by 语句 1210 | * 1211 | * @return string 1212 | */ 1213 | protected function buildOrderBy() 1214 | { 1215 | if (!$this->order_by) { 1216 | return ''; 1217 | } 1218 | 1219 | $r = ' ORDER BY' . $this->indentCsv($this->order_by); 1220 | if (isset($this->order_asc)) { 1221 | $r .= ($this->order_asc) ? ' ASC' : ' DESC'; 1222 | } else { 1223 | // depend on devloper if $this->order_asc is not set. 1224 | // devloper can call function orderBy() to set $this->order_by. 1225 | } 1226 | return $r; 1227 | } 1228 | 1229 | /** 1230 | * 生成 limit 语句 1231 | * 1232 | * @return string 1233 | */ 1234 | protected function buildLimit() 1235 | { 1236 | $has_limit = $this->type == 'DELETE' || $this->type == 'UPDATE'; 1237 | $has_offset = $this->type == 'SELECT'; 1238 | 1239 | if ($has_offset && $this->limit) { 1240 | $clause = " LIMIT {$this->limit}"; 1241 | if ($this->offset) { 1242 | $clause .= " OFFSET {$this->offset}"; 1243 | } 1244 | return $clause; 1245 | } elseif ($has_limit && $this->limit) { 1246 | return " LIMIT {$this->limit}"; 1247 | } 1248 | return ''; 1249 | } 1250 | 1251 | /** 1252 | * Quotes 1253 | * 1254 | * @param string $spec 1255 | * @return string|array 1256 | */ 1257 | public function quoteName($spec) 1258 | { 1259 | $spec = trim($spec); 1260 | $seps = array(' AS ', ' ', '.'); 1261 | foreach ($seps as $sep) { 1262 | $pos = strripos($spec, $sep); 1263 | if ($pos) { 1264 | return $this->quoteNameWithSeparator($spec, $sep, $pos); 1265 | } 1266 | } 1267 | return $this->replaceName($spec); 1268 | } 1269 | 1270 | /** 1271 | * 指定分隔符的 Quotes 1272 | * 1273 | * @param string $spec 1274 | * @param string $sep 1275 | * @param int $pos 1276 | * @return string 1277 | */ 1278 | protected function quoteNameWithSeparator($spec, $sep, $pos) 1279 | { 1280 | $len = strlen($sep); 1281 | $part1 = $this->quoteName(substr($spec, 0, $pos)); 1282 | $part2 = $this->replaceName(substr($spec, $pos + $len)); 1283 | return "{$part1}{$sep}{$part2}"; 1284 | } 1285 | 1286 | /** 1287 | * Quotes "table.col" 格式的字符串 1288 | * 1289 | * @param string $text 1290 | * @return string|array 1291 | */ 1292 | public function quoteNamesIn($text) 1293 | { 1294 | $list = $this->getListForQuoteNamesIn($text); 1295 | $last = count($list) - 1; 1296 | $text = null; 1297 | foreach ($list as $key => $val) { 1298 | if (($key + 1) % 3) { 1299 | $text .= $this->quoteNamesInLoop($val, $key == $last); 1300 | } 1301 | } 1302 | return $text; 1303 | } 1304 | 1305 | /** 1306 | * 返回 quote 元素列表 1307 | * 1308 | * @param string $text 1309 | * @return array 1310 | */ 1311 | protected function getListForQuoteNamesIn($text) 1312 | { 1313 | $apos = "'"; 1314 | $quot = '"'; 1315 | return preg_split( 1316 | "/(($apos+|$quot+|\\$apos+|\\$quot+).*?\\2)/", 1317 | $text, 1318 | -1, 1319 | PREG_SPLIT_DELIM_CAPTURE 1320 | ); 1321 | } 1322 | 1323 | /** 1324 | * 循环 quote 1325 | * 1326 | * @param string $val 1327 | * @param bool $is_last 1328 | * @return string 1329 | */ 1330 | protected function quoteNamesInLoop($val, $is_last) 1331 | { 1332 | if ($is_last) { 1333 | return $this->replaceNamesAndAliasIn($val); 1334 | } 1335 | return $this->replaceNamesIn($val); 1336 | } 1337 | 1338 | /** 1339 | * 替换成别名 1340 | * 1341 | * @param string $val 1342 | * @return string 1343 | */ 1344 | protected function replaceNamesAndAliasIn($val) 1345 | { 1346 | $quoted = $this->replaceNamesIn($val); 1347 | $pos = strripos($quoted, ' AS '); 1348 | if ($pos !== false) { 1349 | $bracket = strripos($quoted, ')'); 1350 | if ($bracket === false) { 1351 | $alias = $this->replaceName(substr($quoted, $pos + 4)); 1352 | $quoted = substr($quoted, 0, $pos) . " AS $alias"; 1353 | } 1354 | } 1355 | return $quoted; 1356 | } 1357 | 1358 | /** 1359 | * Quotes name 1360 | * 1361 | * @param string $name 1362 | * @return string 1363 | */ 1364 | protected function replaceName($name) 1365 | { 1366 | $name = trim($name); 1367 | if ($name == '*') { 1368 | return $name; 1369 | } 1370 | return '`' . $name . '`'; 1371 | } 1372 | 1373 | /** 1374 | * Quotes 1375 | * 1376 | * @param string $text 1377 | * @return string|array 1378 | */ 1379 | protected function replaceNamesIn($text) 1380 | { 1381 | $is_string_literal = strpos($text, "'") !== false 1382 | || strpos($text, '"') !== false; 1383 | if ($is_string_literal) { 1384 | return $text; 1385 | } 1386 | 1387 | $word = '[a-z_][a-z0-9_]*'; 1388 | 1389 | $find = "/(\\b)($word)\\.($word)(\\b)/i"; 1390 | 1391 | $repl = '$1`$2`.`$3`$4'; 1392 | 1393 | $text = preg_replace($find, $repl, $text); 1394 | 1395 | return $text; 1396 | } 1397 | 1398 | // ---------- insert -------------- 1399 | 1400 | /** 1401 | * 设置 `table.column` 与 last-insert-id 的映射 1402 | * 1403 | * @param array $last_insert_id_names 1404 | */ 1405 | public function setLastInsertIdNames(array $last_insert_id_names) 1406 | { 1407 | $this->last_insert_id_names = $last_insert_id_names; 1408 | } 1409 | 1410 | /** 1411 | * insert into. 1412 | * 1413 | * @param string $table 1414 | * @return self 1415 | */ 1416 | public function into($table) 1417 | { 1418 | $this->table = $this->quoteName($table); 1419 | return $this; 1420 | } 1421 | 1422 | /** 1423 | * 生成 INSERT 语句 1424 | * 1425 | * @return string 1426 | */ 1427 | protected function buildINSERT() 1428 | { 1429 | return 'INSERT' 1430 | . $this->buildFlags() 1431 | . $this->buildInto() 1432 | . $this->buildValuesForInsert() 1433 | . $this->buildReturning(); 1434 | } 1435 | 1436 | /** 1437 | * 生成 INTO 语句 1438 | * 1439 | * @return string 1440 | */ 1441 | protected function buildInto() 1442 | { 1443 | return " INTO " . $this->table; 1444 | } 1445 | 1446 | /** 1447 | * PDO::lastInsertId() 1448 | * 1449 | * @param string $col 1450 | * @return mixed 1451 | */ 1452 | public function getLastInsertIdName($col) 1453 | { 1454 | $key = str_replace('`', '', $this->table) . '.' . $col; 1455 | if (isset($this->last_insert_id_names[$key])) { 1456 | return $this->last_insert_id_names[$key]; 1457 | } 1458 | 1459 | return null; 1460 | } 1461 | 1462 | /** 1463 | * 设置一列,如果有第二各参数,则把第二个参数绑定在占位符上 1464 | * 1465 | * @param string $col 1466 | * @return self 1467 | */ 1468 | public function col($col) 1469 | { 1470 | return call_user_func_array(array($this, 'addCol'), func_get_args()); 1471 | } 1472 | 1473 | /** 1474 | * 设置多列 1475 | * 1476 | * @param array $cols 1477 | * @return self 1478 | */ 1479 | public function cols(array $cols) 1480 | { 1481 | if ($this->type == 'SELECT') { 1482 | foreach ($cols as $key => $val) { 1483 | $this->addColSELECT($key, $val); 1484 | } 1485 | return $this; 1486 | } 1487 | return $this->addCols($cols); 1488 | } 1489 | 1490 | /** 1491 | * 直接设置列的值 1492 | * 1493 | * @param string $col 1494 | * @param string $value 1495 | * @return self 1496 | */ 1497 | public function set($col, $value) 1498 | { 1499 | return $this->setCol($col, $value); 1500 | } 1501 | 1502 | /** 1503 | * 为 INSERT 语句绑定值 1504 | * 1505 | * @return string 1506 | */ 1507 | protected function buildValuesForInsert() 1508 | { 1509 | return ' (' . $this->indentCsv(array_keys($this->col_values)) . ') VALUES (' . 1510 | $this->indentCsv(array_values($this->col_values)) . ')'; 1511 | } 1512 | 1513 | // ------update------- 1514 | 1515 | /** 1516 | * 更新哪个表 1517 | * 1518 | * @param string $table 1519 | * @return self 1520 | */ 1521 | public function table($table) 1522 | { 1523 | $this->table = $this->quoteName($table); 1524 | return $this; 1525 | } 1526 | 1527 | /** 1528 | * 生成完整 SQL 语句 1529 | * 1530 | * @return string 1531 | * @throws Exception 1532 | */ 1533 | protected function build() 1534 | { 1535 | switch ($this->type) { 1536 | case 'DELETE': 1537 | return $this->buildDELETE(); 1538 | case 'INSERT': 1539 | return $this->buildINSERT(); 1540 | case 'UPDATE': 1541 | return $this->buildUPDATE(); 1542 | case 'SELECT': 1543 | return $this->buildSELECT(); 1544 | } 1545 | throw new Exception("type empty"); 1546 | } 1547 | 1548 | /** 1549 | * 生成更新的 SQL 语句 1550 | */ 1551 | protected function buildUPDATE() 1552 | { 1553 | return 'UPDATE' 1554 | . $this->buildFlags() 1555 | . $this->buildTable() 1556 | . $this->buildValuesForUpdate() 1557 | . $this->buildWhere() 1558 | . $this->buildOrderBy() 1559 | . $this->buildLimit() 1560 | . $this->buildReturning(); 1561 | } 1562 | 1563 | /** 1564 | * 哪个表 1565 | * 1566 | * @return string 1567 | */ 1568 | protected function buildTable() 1569 | { 1570 | return " {$this->table}"; 1571 | } 1572 | 1573 | /** 1574 | * 为更新语句绑定值 1575 | * 1576 | * @return string 1577 | */ 1578 | protected function buildValuesForUpdate() 1579 | { 1580 | $values = array(); 1581 | foreach ($this->col_values as $col => $value) { 1582 | $values[] = "{$col} = {$value}"; 1583 | } 1584 | return ' SET' . $this->indentCsv($values); 1585 | } 1586 | 1587 | // ----------Dml--------------- 1588 | 1589 | /** 1590 | * 获取绑定的值 1591 | * 1592 | * @return array 1593 | */ 1594 | public function getBindValuesCOMMON() 1595 | { 1596 | $bind_values = $this->bind_values; 1597 | $i = 1; 1598 | foreach ($this->bind_where as $val) { 1599 | $bind_values[$i] = $val; 1600 | $i++; 1601 | } 1602 | return $bind_values; 1603 | } 1604 | 1605 | /** 1606 | * 设置列 1607 | * 1608 | * @param string $col 1609 | * @return self 1610 | */ 1611 | protected function addCol($col) 1612 | { 1613 | $key = $this->quoteName($col); 1614 | $this->col_values[$key] = ":$col"; 1615 | $args = func_get_args(); 1616 | if (count($args) > 1) { 1617 | $this->bindValue($col, $args[1]); 1618 | } 1619 | return $this; 1620 | } 1621 | 1622 | /** 1623 | * 设置多个列 1624 | * 1625 | * @param array $cols 1626 | * @return self 1627 | */ 1628 | protected function addCols(array $cols) 1629 | { 1630 | foreach ($cols as $key => $val) { 1631 | if (is_int($key)) { 1632 | $this->addCol($val); 1633 | } else { 1634 | $this->addCol($key, $val); 1635 | } 1636 | } 1637 | return $this; 1638 | } 1639 | 1640 | /** 1641 | * 设置单列的值 1642 | * 1643 | * @param string $col . 1644 | * @param string $value 1645 | * @return self 1646 | */ 1647 | protected function setCol($col, $value) 1648 | { 1649 | if ($value === null) { 1650 | $value = 'NULL'; 1651 | } 1652 | 1653 | $key = $this->quoteName($col); 1654 | $value = $this->quoteNamesIn($value); 1655 | $this->col_values[$key] = $value; 1656 | return $this; 1657 | } 1658 | 1659 | /** 1660 | * 增加返回的列 1661 | * 1662 | * @param array $cols 1663 | * @return self 1664 | * 1665 | */ 1666 | protected function addReturning(array $cols) 1667 | { 1668 | foreach ($cols as $col) { 1669 | $this->returning[] = $this->quoteNamesIn($col); 1670 | } 1671 | return $this; 1672 | } 1673 | 1674 | /** 1675 | * 生成 RETURNING 语句 1676 | * 1677 | * @return string 1678 | */ 1679 | protected function buildReturning() 1680 | { 1681 | if (!$this->returning) { 1682 | return ''; 1683 | } 1684 | return ' RETURNING' . $this->indentCsv($this->returning); 1685 | } 1686 | 1687 | /** 1688 | * 构造函数 1689 | * 1690 | * @param string $host 1691 | * @param int $port 1692 | * @param string $user 1693 | * @param string $password 1694 | * @param string $db_name 1695 | * @param string $charset 1696 | */ 1697 | public function __construct($host, $port, $user, $password, $db_name, $charset = 'utf8') 1698 | { 1699 | $this->settings = array( 1700 | 'host' => $host, 1701 | 'port' => $port, 1702 | 'user' => $user, 1703 | 'password' => $password, 1704 | 'dbname' => $db_name, 1705 | 'charset' => $charset, 1706 | ); 1707 | $this->connect(); 1708 | } 1709 | 1710 | /** 1711 | * 创建 PDO 实例 1712 | */ 1713 | protected function connect() 1714 | { 1715 | $dsn = 'mysql:dbname=' . $this->settings["dbname"] . ';host=' . 1716 | $this->settings["host"] . ';port=' . $this->settings['port']; 1717 | $this->pdo = new PDO($dsn, $this->settings["user"], $this->settings["password"], 1718 | array( 1719 | PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . (!empty($this->settings['charset']) ? 1720 | $this->settings['charset'] : 'utf8') 1721 | )); 1722 | $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 1723 | $this->pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); 1724 | $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 1725 | } 1726 | 1727 | /** 1728 | * 关闭连接 1729 | */ 1730 | public function closeConnection() 1731 | { 1732 | $this->pdo = null; 1733 | } 1734 | 1735 | /** 1736 | * 执行 1737 | * 1738 | * @param string $query 1739 | * @param string $parameters 1740 | * @throws PDOException 1741 | */ 1742 | protected function execute($query, $parameters = "") 1743 | { 1744 | try { 1745 | if (is_null($this->pdo)) { 1746 | $this->connect(); 1747 | } 1748 | $this->clearSQuery(); 1749 | $this->sQuery = @$this->pdo->prepare($query); 1750 | $this->bindMore($parameters); 1751 | if (!empty($this->parameters)) { 1752 | foreach ($this->parameters as $param) { 1753 | $this->sQuery->bindParam($param[0], $param[1]); 1754 | } 1755 | } 1756 | $this->success = $this->sQuery->execute(); 1757 | } catch (PDOException $e) { 1758 | // 服务端断开时重连一次 1759 | if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) { 1760 | $this->closeConnection(); 1761 | $this->connect(); 1762 | 1763 | try { 1764 | $this->clearSQuery(); 1765 | $this->sQuery = $this->pdo->prepare($query); 1766 | $this->bindMore($parameters); 1767 | if (!empty($this->parameters)) { 1768 | foreach ($this->parameters as $param) { 1769 | $this->sQuery->bindParam($param[0], $param[1]); 1770 | } 1771 | } 1772 | $this->success = $this->sQuery->execute(); 1773 | } catch (PDOException $ex) { 1774 | $this->rollBackTrans(); 1775 | throw $ex; 1776 | } 1777 | } else { 1778 | $this->rollBackTrans(); 1779 | $msg = $e->getMessage(); 1780 | $err_msg = "SQL:" . $this->lastSQL() . " " . $msg; 1781 | $exception = new \PDOException($err_msg, (int)$e->getCode()); 1782 | throw $exception; 1783 | } 1784 | } 1785 | $this->parameters = array(); 1786 | } 1787 | 1788 | private function clearSQuery() 1789 | { 1790 | if (isset($this->sQuery)) { 1791 | $this->sQuery = null; 1792 | } 1793 | } 1794 | 1795 | /** 1796 | * 绑定 1797 | * 1798 | * @param string $para 1799 | * @param string $value 1800 | */ 1801 | public function bind($para, $value) 1802 | { 1803 | if (is_string($para)) { 1804 | $this->parameters[sizeof($this->parameters)] = array(":" . $para, $value); 1805 | } else { 1806 | $this->parameters[sizeof($this->parameters)] = array($para, $value); 1807 | } 1808 | } 1809 | 1810 | /** 1811 | * 绑定多个 1812 | * 1813 | * @param array $parray 1814 | */ 1815 | public function bindMore($parray) 1816 | { 1817 | if (empty($this->parameters) && is_array($parray)) { 1818 | $columns = array_keys($parray); 1819 | foreach ($columns as $i => &$column) { 1820 | $this->bind($column, $parray[$column]); 1821 | } 1822 | } 1823 | } 1824 | 1825 | /** 1826 | * 执行 SQL 1827 | * 1828 | * @param string $query 1829 | * @param array $params 1830 | * @param int $fetchmode 1831 | * @return mixed 1832 | */ 1833 | public function query($query = '', $params = null, $fetchmode = PDO::FETCH_ASSOC) 1834 | { 1835 | $query = trim($query); 1836 | if (empty($query)) { 1837 | $union = ''; 1838 | if (!empty($this->union)) { 1839 | $union = implode(PHP_EOL, $this->union) . PHP_EOL; 1840 | } 1841 | 1842 | $query = $union . $this->build(); 1843 | 1844 | if (!$params) { 1845 | $params = $this->getBindValues(); 1846 | } 1847 | } 1848 | 1849 | $this->resetAll(); 1850 | $this->lastSql = $query; 1851 | 1852 | $this->execute($query, $params); 1853 | 1854 | $rawStatement = explode(" ", $query); 1855 | 1856 | $statement = strtolower(trim($rawStatement[0])); 1857 | if ($statement === 'select' || $statement === 'show') { 1858 | return $this->sQuery->fetchAll($fetchmode); 1859 | } elseif ($statement === 'update' || $statement === 'delete' || $statement === 'replace') { 1860 | return $this->sQuery->rowCount(); 1861 | } elseif ($statement === 'insert') { 1862 | if ($this->sQuery->rowCount() > 0) { 1863 | return $this->lastInsertId(); 1864 | } 1865 | } else { 1866 | return null; 1867 | } 1868 | 1869 | return null; 1870 | } 1871 | 1872 | /** 1873 | * 返回一列 1874 | * 1875 | * @param string $query 1876 | * @param array $params 1877 | * @return array 1878 | */ 1879 | public function column($query = '', $params = null) 1880 | { 1881 | $query = trim($query); 1882 | if (empty($query)) { 1883 | $union = ''; 1884 | if (!empty($this->union)) { 1885 | $union = implode(PHP_EOL, $this->union) . PHP_EOL; 1886 | } 1887 | 1888 | $query = $union . $this->build(); 1889 | 1890 | if (!$params) { 1891 | $params = $this->getBindValues(); 1892 | } 1893 | } 1894 | 1895 | $this->resetAll(); 1896 | $this->lastSql = $query; 1897 | 1898 | $this->execute($query, $params); 1899 | $columns = $this->sQuery->fetchAll(PDO::FETCH_NUM); 1900 | $column = null; 1901 | foreach ($columns as $cells) { 1902 | $column[] = $cells[0]; 1903 | } 1904 | return $column; 1905 | } 1906 | 1907 | /** 1908 | * 返回一行 1909 | * 1910 | * @param string $query 1911 | * @param array $params 1912 | * @param int $fetchmode 1913 | * @return array 1914 | */ 1915 | public function row($query = '', $params = null, $fetchmode = PDO::FETCH_ASSOC) 1916 | { 1917 | $query = trim($query); 1918 | if (empty($query)) { 1919 | $union = ''; 1920 | if (!empty($this->union)) { 1921 | $union = implode(PHP_EOL, $this->union) . PHP_EOL; 1922 | } 1923 | 1924 | $query = $union . $this->build(); 1925 | 1926 | if (!$params) { 1927 | $params = $this->getBindValues(); 1928 | } 1929 | } 1930 | 1931 | $this->resetAll(); 1932 | $this->lastSql = $query; 1933 | 1934 | $this->execute($query, $params); 1935 | return $this->sQuery->fetch($fetchmode); 1936 | } 1937 | 1938 | /** 1939 | * 返回单个值 1940 | * 1941 | * @param string $query 1942 | * @param array $params 1943 | * @return string 1944 | */ 1945 | public function single($query = '', $params = null) 1946 | { 1947 | $query = trim($query); 1948 | if (empty($query)) { 1949 | $union = ''; 1950 | if (!empty($this->union)) { 1951 | $union = implode(PHP_EOL, $this->union) . PHP_EOL; 1952 | } 1953 | 1954 | $query = $union . $this->build(); 1955 | 1956 | if (!$params) { 1957 | $params = $this->getBindValues(); 1958 | } 1959 | } 1960 | 1961 | $this->resetAll(); 1962 | $this->lastSql = $query; 1963 | 1964 | $this->execute($query, $params); 1965 | return $this->sQuery->fetchColumn(); 1966 | } 1967 | 1968 | /** 1969 | * 返回 lastInsertId 1970 | * 1971 | * @return string 1972 | */ 1973 | public function lastInsertId() 1974 | { 1975 | return $this->pdo->lastInsertId(); 1976 | } 1977 | 1978 | /** 1979 | * 返回最后一条执行的 sql 1980 | * 1981 | * @return string 1982 | */ 1983 | public function lastSQL() 1984 | { 1985 | return $this->lastSql; 1986 | } 1987 | 1988 | /** 1989 | * 开始事务 1990 | */ 1991 | public function beginTrans() 1992 | { 1993 | try { 1994 | if (is_null($this->pdo)) { 1995 | $this->connect(); 1996 | } 1997 | return $this->pdo->beginTransaction(); 1998 | } catch (PDOException $e) { 1999 | // 服务端断开时重连一次 2000 | if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) { 2001 | $this->closeConnection(); 2002 | $this->connect(); 2003 | return $this->pdo->beginTransaction(); 2004 | } else { 2005 | throw $e; 2006 | } 2007 | } 2008 | } 2009 | 2010 | /** 2011 | * 提交事务 2012 | */ 2013 | public function commitTrans() 2014 | { 2015 | return $this->pdo->commit(); 2016 | } 2017 | 2018 | /** 2019 | * 事务回滚 2020 | */ 2021 | public function rollBackTrans() 2022 | { 2023 | if ($this->pdo->inTransaction()) { 2024 | return $this->pdo->rollBack(); 2025 | } 2026 | return true; 2027 | } 2028 | } 2029 | --------------------------------------------------------------------------------