2828class Mysqli extends Driver implements CRUDAbleInterface, CRUDQueryableInterface
2929{
3030 public const string ID = "mysqli " ;
31+
32+ /** @var int[] */
33+ protected const array CONNECTION_ERROR_CODES = [2006 , 2013 ];
34+
3135 protected string $ id = self ::ID ;
3236
3337 /**
@@ -77,8 +81,6 @@ class Mysqli extends Driver implements CRUDAbleInterface, CRUDQueryableInterface
7781 */
7882 protected ?\mysqli $ connection = null ;
7983
80- protected int $ connectionRetries = 1 ;
81-
8284 /**
8385 * Mysqli constructor.
8486 *
@@ -123,6 +125,17 @@ protected function reconnect(): void
123125 $ this ->connect ();
124126 }
125127
128+ /**
129+ * @return RetryCollection
130+ */
131+ protected function getRetryCollection (): RetryCollection
132+ {
133+ return new RetryCollection ([
134+ new RetryGroup (static ::CONNECTION_ERROR_CODES , 1 ), // connection
135+ new RetryGroup ([1213 ], 3 ) // deadlock
136+ ]);
137+ }
138+
126139 /**
127140 * Execute a mysql query
128141 *
@@ -134,24 +147,19 @@ protected function reconnect(): void
134147 protected function rawQuery (string $ query ): mysqli_result |true
135148 {
136149 $ this ->connect ();
137- $ retries = $ this ->connectionRetries ;
150+ $ retries = $ this ->getRetryCollection () ;
138151 while (true ) {
139152 try {
140153 return $ this ->connection ->query ($ query );
141154 } catch (mysqli_sql_exception $ e ) {
142- // no more retries left
143- if ($ retries <= 0 ) {
144- throw MysqliException::fromException ($ e );
145- }
146-
147- // connection error, try to reconnect and retry
148- if ($ e ->getCode () === 2006 || $ e ->getCode () === 2013 ) {
149- $ this ->reconnect ();
150- $ retries --;
155+ if ($ retries ->canRetry ($ e ->getCode ())) {
156+ if (in_array ($ e ->getCode (), static ::CONNECTION_ERROR_CODES , true )) {
157+ $ this ->reconnect ();
158+ }
159+ $ this ->handleRetriedException ($ e );
151160 continue ;
152161 }
153162
154- // other error, throw exception
155163 throw MysqliException::fromException ($ e );
156164 }
157165 }
@@ -166,29 +174,33 @@ protected function rawQuery(string $query): mysqli_result|true
166174 protected function escape (string $ data ): string
167175 {
168176 $ this ->connect ();
169- $ retries = $ this ->connectionRetries ;
177+ $ retries = $ this ->getRetryCollection () ;
170178 while (true ) {
171179 try {
172180 return $ this ->connection ->real_escape_string ($ data );
173181 } catch (mysqli_sql_exception $ e ) {
174- // no more retries left
175- if ($ retries <= 0 ) {
176- throw MysqliException::fromException ($ e );
177- }
178-
179- // connection error, try to reconnect and retry
180- if ($ e ->getCode () === 2006 || $ e ->getCode () === 2013 ) {
181- $ this ->reconnect ();
182- $ retries --;
182+ if ($ retries ->canRetry ($ e ->getCode ())) {
183+ if (in_array ($ e ->getCode (), static ::CONNECTION_ERROR_CODES , true )) {
184+ $ this ->reconnect ();
185+ }
186+ $ this ->handleRetriedException ($ e );
183187 continue ;
184188 }
185189
186- // other error, throw exception
187190 throw MysqliException::fromException ($ e );
188191 }
189192 }
190193 }
191194
195+ /**
196+ * @param mysqli_sql_exception $exception
197+ * @return void
198+ */
199+ protected function handleRetriedException (mysqli_sql_exception $ exception ): void
200+ {
201+ // can be used to log retried exceptions
202+ }
203+
192204 /**
193205 * Save the model
194206 *
@@ -383,14 +395,4 @@ public function setDatabase(string $database): Mysqli
383395 $ this ->database = $ database ;
384396 return $ this ;
385397 }
386-
387- /**
388- * @param int $connectionRetries
389- * @return $this
390- */
391- public function setConnectionRetries (int $ connectionRetries ): static
392- {
393- $ this ->connectionRetries = $ connectionRetries ;
394- return $ this ;
395- }
396398}
0 commit comments