Connection.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\DbConnection;
  12. use Hyperf\Contract\ConnectionInterface;
  13. use Hyperf\Contract\StdoutLoggerInterface;
  14. use Hyperf\Database\ConnectionInterface as DbConnectionInterface;
  15. use Hyperf\Database\Connectors\ConnectionFactory;
  16. use Hyperf\DbConnection\Pool\DbPool;
  17. use Hyperf\DbConnection\Traits\DbConnection;
  18. use Hyperf\Pool\Connection as BaseConnection;
  19. use Hyperf\Pool\Exception\ConnectionException;
  20. use Psr\Container\ContainerInterface;
  21. use Psr\EventDispatcher\EventDispatcherInterface;
  22. use Psr\Log\LoggerInterface;
  23. use Throwable;
  24. class Connection extends BaseConnection implements ConnectionInterface, DbConnectionInterface
  25. {
  26. use DbConnection;
  27. protected ?DbConnectionInterface $connection = null;
  28. protected ConnectionFactory $factory;
  29. protected LoggerInterface $logger;
  30. public function __construct(ContainerInterface $container, DbPool $pool, protected array $config)
  31. {
  32. parent::__construct($container, $pool);
  33. $this->factory = $container->get(ConnectionFactory::class);
  34. $this->logger = $container->get(StdoutLoggerInterface::class);
  35. $this->reconnect();
  36. }
  37. public function __call($name, $arguments)
  38. {
  39. return $this->connection->{$name}(...$arguments);
  40. }
  41. public function getActiveConnection(): DbConnectionInterface
  42. {
  43. if ($this->check()) {
  44. return $this;
  45. }
  46. if (! $this->reconnect()) {
  47. throw new ConnectionException('Connection reconnect failed.');
  48. }
  49. return $this;
  50. }
  51. public function reconnect(): bool
  52. {
  53. $this->close();
  54. $this->connection = $this->factory->make($this->config);
  55. if ($this->connection instanceof \Hyperf\Database\Connection) {
  56. // Reset event dispatcher after db reconnect.
  57. if ($this->container->has(EventDispatcherInterface::class)) {
  58. $dispatcher = $this->container->get(EventDispatcherInterface::class);
  59. $this->connection->setEventDispatcher($dispatcher);
  60. }
  61. // Reset reconnector after db reconnect.
  62. $this->connection->setReconnector(function ($connection) {
  63. $this->logger->warning('Database connection refreshing.');
  64. if ($connection instanceof \Hyperf\Database\Connection) {
  65. $this->refresh($connection);
  66. }
  67. });
  68. }
  69. $this->lastUseTime = microtime(true);
  70. return true;
  71. }
  72. public function close(): bool
  73. {
  74. if ($this->connection instanceof \Hyperf\Database\Connection) {
  75. $this->connection->disconnect();
  76. }
  77. unset($this->connection);
  78. return true;
  79. }
  80. public function isTransaction(): bool
  81. {
  82. return $this->transactionLevel() > 0;
  83. }
  84. public function release(): void
  85. {
  86. try {
  87. if ($this->connection instanceof \Hyperf\Database\Connection) {
  88. // Reset $recordsModified property of connection to false before the connection release into the pool.
  89. $this->connection->resetRecordsModified();
  90. if ($this->connection->getErrorCount() > 100) {
  91. // If the error count of connection is more than 100, we think it is a bad connection,
  92. // So we'll reset it at the next time
  93. $this->lastUseTime = 0.0;
  94. }
  95. }
  96. if ($this->transactionLevel() > 0) {
  97. $this->rollBack(0);
  98. $this->logger->error('Maybe you\'ve forgotten to commit or rollback the MySQL transaction.');
  99. }
  100. } catch (Throwable $exception) {
  101. $this->logger->error('Rollback connection failed, caused by ' . $exception);
  102. // Ensure that the connection must be reset the next time after broken.
  103. $this->lastUseTime = 0.0;
  104. }
  105. parent::release();
  106. }
  107. /**
  108. * Refresh pdo and readPdo for current connection.
  109. */
  110. protected function refresh(\Hyperf\Database\Connection $connection)
  111. {
  112. $refresh = $this->factory->make($this->config);
  113. if ($refresh instanceof \Hyperf\Database\Connection) {
  114. $connection->disconnect();
  115. $connection->setPdo($refresh->getPdo());
  116. $connection->setReadPdo($refresh->getReadPdo());
  117. }
  118. $this->logger->warning('Database connection refreshed.');
  119. }
  120. }