ConnectionResolver.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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\Database\ConnectionInterface;
  13. use Hyperf\Database\ConnectionResolverInterface;
  14. use Hyperf\DbConnection\Pool\PoolFactory;
  15. use Hyperf\Utils\Context;
  16. use Hyperf\Utils\Coroutine;
  17. use Psr\Container\ContainerInterface;
  18. class ConnectionResolver implements ConnectionResolverInterface
  19. {
  20. /**
  21. * The default connection name.
  22. *
  23. * @var string
  24. */
  25. protected $default = 'default';
  26. /**
  27. * @var PoolFactory
  28. */
  29. protected $factory;
  30. /**
  31. * @var ContainerInterface
  32. */
  33. protected $container;
  34. public function __construct(ContainerInterface $container)
  35. {
  36. $this->container = $container;
  37. $this->factory = $container->get(PoolFactory::class);
  38. }
  39. /**
  40. * Get a database connection instance.
  41. *
  42. * @param string $name
  43. * @return ConnectionInterface
  44. */
  45. public function connection($name = null)
  46. {
  47. if (is_null($name)) {
  48. $name = $this->getDefaultConnection();
  49. }
  50. $connection = null;
  51. $id = $this->getContextKey($name);
  52. if (Context::has($id)) {
  53. $connection = Context::get($id);
  54. }
  55. if (! $connection instanceof ConnectionInterface) {
  56. $pool = $this->factory->getPool($name);
  57. $connection = $pool->get();
  58. try {
  59. // PDO is initialized as an anonymous function, so there is no IO exception,
  60. // but if other exceptions are thrown, the connection will not return to the connection pool properly.
  61. $connection = $connection->getConnection();
  62. Context::set($id, $connection);
  63. } finally {
  64. if (Coroutine::inCoroutine()) {
  65. defer(function () use ($connection, $id) {
  66. Context::set($id, null);
  67. $connection->release();
  68. });
  69. }
  70. }
  71. }
  72. return $connection;
  73. }
  74. /**
  75. * Get the default connection name.
  76. *
  77. * @return string
  78. */
  79. public function getDefaultConnection()
  80. {
  81. return $this->default;
  82. }
  83. /**
  84. * Set the default connection name.
  85. *
  86. * @param string $name
  87. */
  88. public function setDefaultConnection($name)
  89. {
  90. $this->default = $name;
  91. }
  92. /**
  93. * The key to identify the connection object in coroutine context.
  94. * @param mixed $name
  95. */
  96. private function getContextKey($name): string
  97. {
  98. return sprintf('database.connection.%s', $name);
  99. }
  100. }