11
11
*
12
12
* A PHP MySQL PDO class similar to the the Python MySQLdb.
13
13
*/
14
- require (dirname (__FILE__ ) . "/PDO.Log.class.php " );
14
+ require (__DIR__ . '/PDO.Log.class.php ' );
15
+ require (__DIR__ . '/PDO.Iterator.class.php ' );
16
+ /** Class DB
17
+ * @property PDO pdo PDO object
18
+ * @property PDOStatement sQuery PDOStatement
19
+ * @property PDOLog PDOLog logObject
20
+ */
15
21
class DB
16
22
{
17
23
private $ Host ;
24
+ private $ DBPort ;
18
25
private $ DBName ;
19
26
private $ DBUser ;
20
27
private $ DBPassword ;
21
- private $ DBPort ;
22
28
private $ pdo ;
23
29
private $ sQuery ;
24
- private $ bConnected = false ;
25
- private $ log ;
30
+ private $ connectionStatus = false ;
31
+ private $ logObject ;
26
32
private $ parameters ;
27
33
public $ rowCount = 0 ;
28
34
public $ columnCount = 0 ;
29
35
public $ querycount = 0 ;
30
-
31
-
32
- public function __construct ($ Host , $ DBName , $ DBUser , $ DBPassword , $ DBPort = 3306 )
36
+
37
+
38
+ private $ retryAttempt = 0 ; // 失败重试次数
39
+ const AUTO_RECONNECT = true ;
40
+ const RETRY_ATTEMPTS = 3 ; // 最大失败重试次数
41
+
42
+ /**
43
+ * DB constructor.
44
+ * @param $Host
45
+ * @param $DBPort
46
+ * @param $DBName
47
+ * @param $DBUser
48
+ * @param $DBPassword
49
+ */
50
+ public function __construct ($ Host , $ DBPort , $ DBName , $ DBUser , $ DBPassword )
33
51
{
34
- $ this ->log = new Log ();
52
+ $ this ->logObject = new PDOLog ();
35
53
$ this ->Host = $ Host ;
54
+ $ this ->DBPort = $ DBPort ;
36
55
$ this ->DBName = $ DBName ;
37
56
$ this ->DBUser = $ DBUser ;
38
57
$ this ->DBPassword = $ DBPassword ;
39
- $ this ->DBPort = $ DBPort ;
40
- $ this ->Connect ();
41
58
$ this ->parameters = array ();
59
+ $ this ->Connect ();
42
60
}
43
61
44
62
45
63
private function Connect ()
46
64
{
47
65
try {
48
- $ this ->pdo = new PDO ('mysql:dbname= ' . $ this ->DBName . ';host= ' . $ this ->Host . ';port= ' . $ this ->DBPort . ';charset=utf8 ' ,
66
+ $ dsn = 'mysql: ' ;
67
+ $ dsn .= 'host= ' . $ this ->Host . '; ' ;
68
+ $ dsn .= 'port= ' . $ this ->DBPort . '; ' ;
69
+ if (!empty ($ this ->DBName )) {
70
+ $ dsn .= 'dbname= ' . $ this ->DBName . '; ' ;
71
+ }
72
+ $ dsn .= 'charset=utf8; ' ;
73
+ $ this ->pdo = new PDO ($ dsn ,
49
74
$ this ->DBUser ,
50
75
$ this ->DBPassword ,
51
76
array (
@@ -68,30 +93,36 @@ private function Connect()
68
93
//$this->pdo->setAttribute(PDO::ATTR_PERSISTENT, true);//长连接
69
94
$this->pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
70
95
*/
71
- $ this ->bConnected = true ;
96
+ $ this ->connectionStatus = true ;
72
97
73
98
}
74
99
catch (PDOException $ e ) {
75
- echo $ this ->ExceptionLog ($ e ->getMessage ());
76
- die ();
100
+ $ this ->ExceptionLog ($ e , '' , 'Connect ' );
77
101
}
78
102
}
79
-
80
-
81
- public function CloseConnection ()
103
+
104
+ private function SetFailureFlag ()
82
105
{
83
106
$ this ->pdo = null ;
107
+ $ this ->connectionStatus = false ;
84
108
}
85
-
86
-
87
- private function Init ($ query , $ parameters = "" )
109
+
110
+ /**
111
+ * close pdo connection
112
+ */
113
+ public function closeConnection ()
114
+ {
115
+ $ this ->pdo = null ;
116
+ }
117
+
118
+ private function Init ($ query , $ parameters = null , $ driverOptions = array ())
88
119
{
89
- if (!$ this ->bConnected ) {
120
+ if (!$ this ->connectionStatus ) {
90
121
$ this ->Connect ();
91
122
}
92
123
try {
93
124
$ this ->parameters = $ parameters ;
94
- $ this ->sQuery = $ this ->pdo ->prepare ($ this ->BuildParams ($ query , $ this ->parameters ));
125
+ $ this ->sQuery = $ this ->pdo ->prepare ($ this ->BuildParams ($ query , $ this ->parameters ), $ driverOptions );
95
126
96
127
if (!empty ($ this ->parameters )) {
97
128
if (array_key_exists (0 , $ parameters )) {
@@ -105,19 +136,22 @@ private function Init($query, $parameters = "")
105
136
$ this ->sQuery ->bindParam ($ parametersType ? intval ($ column ) : ": " . $ column , $ this ->parameters [$ column ]); //It would be query after loop end(before 'sQuery->execute()').It is wrong to use $value.
106
137
}
107
138
}
108
-
109
- $ this ->succes = $ this ->sQuery ->execute ();
139
+
140
+ if (!isset ($ driverOptions [PDO ::ATTR_CURSOR ])) {
141
+ $ this ->sQuery ->execute ();
142
+ }
110
143
$ this ->querycount ++;
111
144
}
112
145
catch (PDOException $ e ) {
113
- echo $ this ->ExceptionLog ($ e-> getMessage () , $ this ->BuildParams ($ query ));
114
- die ();
146
+ $ this ->ExceptionLog ($ e , $ this ->BuildParams ($ query), ' Init ' , array ( ' query ' => $ query , ' parameters ' => $ parameters ));
147
+
115
148
}
116
149
117
150
$ this ->parameters = array ();
118
151
}
119
152
120
- private function BuildParams ($ query , $ params = array ()){
153
+ private function BuildParams ($ query , $ params = null )
154
+ {
121
155
if (!empty ($ params )) {
122
156
$ array_parameter_found = false ;
123
157
foreach ($ params as $ parameter_key => $ parameter ) {
@@ -143,30 +177,116 @@ private function BuildParams($query, $params = array()){
143
177
}
144
178
return $ query ;
145
179
}
146
-
147
-
148
- public function query ($ query , $ params = null , $ fetchmode = PDO ::FETCH_ASSOC )
180
+
181
+ /**
182
+ * @return bool
183
+ */
184
+ public function beginTransaction ()
185
+ {
186
+ return $ this ->pdo ->beginTransaction ();
187
+ }
188
+
189
+ /**
190
+ * @return bool
191
+ */
192
+ public function commit ()
193
+ {
194
+ return $ this ->pdo ->commit ();
195
+ }
196
+
197
+ /**
198
+ * @return bool
199
+ */
200
+ public function rollBack ()
201
+ {
202
+ return $ this ->pdo ->rollBack ();
203
+ }
204
+
205
+ /**
206
+ * @return bool
207
+ */
208
+ public function inTransaction ()
209
+ {
210
+ return $ this ->pdo ->inTransaction ();
211
+ }
212
+
213
+ /**
214
+ * execute a sql query, returns an result array in the select operation, and returns the number of rows affected in other operations
215
+ * @param string $query
216
+ * @param null $params
217
+ * @param int $fetchMode
218
+ * @return array|int|null
219
+ */
220
+ public function query ($ query , $ params = null , $ fetchMode = PDO ::FETCH_ASSOC )
149
221
{
150
222
$ query = trim ($ query );
151
223
$ rawStatement = explode (" " , $ query );
152
224
$ this ->Init ($ query , $ params );
153
225
$ statement = strtolower ($ rawStatement [0 ]);
154
226
if ($ statement === 'select ' || $ statement === 'show ' ) {
155
- return $ this ->sQuery ->fetchAll ($ fetchmode );
227
+ return $ this ->sQuery ->fetchAll ($ fetchMode );
156
228
} elseif ($ statement === 'insert ' || $ statement === 'update ' || $ statement === 'delete ' ) {
157
229
return $ this ->sQuery ->rowCount ();
158
230
} else {
159
231
return NULL ;
160
232
}
161
233
}
162
-
163
-
234
+
235
+ /**
236
+ * execute a sql query, returns an iterator in the select operation, and returns the number of rows affected in other operations
237
+ * @param string $query
238
+ * @param null $params
239
+ * @param int $fetchMode
240
+ * @return int|null|PDOIterator
241
+ */
242
+ public function iterator ($ query , $ params = null , $ fetchMode = PDO ::FETCH_ASSOC )
243
+ {
244
+ $ query = trim ($ query );
245
+ $ rawStatement = explode (" " , $ query );
246
+ $ this ->Init ($ query , $ params , array (PDO ::ATTR_CURSOR => PDO ::CURSOR_SCROLL ));
247
+ $ statement = strtolower ($ rawStatement [0 ]);
248
+ if ($ statement === 'select ' || $ statement === 'show ' ) {
249
+ return new PDOIterator ($ this ->sQuery , $ fetchMode );
250
+ } elseif ($ statement === 'insert ' || $ statement === 'update ' || $ statement === 'delete ' ) {
251
+ return $ this ->sQuery ->rowCount ();
252
+ } else {
253
+ return NULL ;
254
+ }
255
+ }
256
+
257
+ /**
258
+ * @param $tableName
259
+ * @param null $params
260
+ * @return bool|string
261
+ */
262
+ public function insert ($ tableName , $ params = null )
263
+ {
264
+ $ keys = array_keys ($ params );
265
+ $ rowCount = $ this ->query (
266
+ 'INSERT INTO ` ' . $ tableName . '` (` ' . implode ('`,` ' , $ keys ) . '`)
267
+ VALUES (: ' . implode (',: ' , $ keys ) . ') ' ,
268
+ $ params
269
+ );
270
+ if ($ rowCount === 0 ) {
271
+ return false ;
272
+ }
273
+ return $ this ->lastInsertId ();
274
+ }
275
+
276
+ /**
277
+ * @return string
278
+ */
164
279
public function lastInsertId ()
165
280
{
166
281
return $ this ->pdo ->lastInsertId ();
167
282
}
168
-
169
-
283
+
284
+
285
+ /**
286
+ * @param $query
287
+ * @param null $params
288
+ * @return array
289
+ */
170
290
public function column ($ query , $ params = null )
171
291
{
172
292
$ this ->Init ($ query , $ params );
@@ -177,7 +297,12 @@ public function column($query, $params = null)
177
297
return $ resultColumn ;
178
298
}
179
299
180
-
300
+ /**
301
+ * @param $query
302
+ * @param null $params
303
+ * @param int $fetchmode
304
+ * @return mixed
305
+ */
181
306
public function row ($ query , $ params = null , $ fetchmode = PDO ::FETCH_ASSOC )
182
307
{
183
308
$ this ->Init ($ query , $ params );
@@ -187,28 +312,56 @@ public function row($query, $params = null, $fetchmode = PDO::FETCH_ASSOC)
187
312
$ this ->sQuery ->closeCursor ();
188
313
return $ resultRow ;
189
314
}
190
-
191
-
315
+
316
+ /**
317
+ * @param $query
318
+ * @param null $params
319
+ * @return mixed
320
+ */
192
321
public function single ($ query , $ params = null )
193
322
{
194
323
$ this ->Init ($ query , $ params );
195
324
return $ this ->sQuery ->fetchColumn ();
196
325
}
197
-
198
-
199
- private function ExceptionLog ($ message , $ sql = "" )
326
+
327
+ /**
328
+ * @param PDOException $e
329
+ * @param string $sql
330
+ * @param string $method
331
+ * @param array $parameters
332
+ */
333
+ private function ExceptionLog (PDOException $ e , $ sql = "" , $ method = '' , $ parameters = array ())
200
334
{
335
+ $ message = $ e ->getMessage ();
201
336
$ exception = 'Unhandled Exception. <br /> ' ;
202
337
$ exception .= $ message ;
203
338
$ exception .= "<br /> You can find the error back in the log. " ;
204
339
205
340
if (!empty ($ sql )) {
206
341
$ message .= "\r\nRaw SQL : " . $ sql ;
207
342
}
208
- $ this ->log ->write ($ message , $ this ->DBName . md5 ($ this ->DBPassword ));
209
- //Prevent search engines to crawl
210
- header ("HTTP/1.1 500 Internal Server Error " );
211
- header ("Status: 500 Internal Server Error " );
212
- return $ exception ;
343
+ $ this ->logObject ->write ($ message , $ this ->DBName . md5 ($ this ->DBPassword ));
344
+ if (
345
+ self ::AUTO_RECONNECT
346
+ && $ this ->retryAttempt < self ::RETRY_ATTEMPTS
347
+ && stripos ($ message , 'server has gone away ' ) !== false
348
+ && !empty ($ method )
349
+ && !$ this ->inTransaction ()
350
+ ) {
351
+ $ this ->SetFailureFlag ();
352
+ $ this ->retryAttempt ++;
353
+ $ this ->logObject ->write ('Retry ' . $ this ->retryAttempt . ' times ' , $ this ->DBName . md5 ($ this ->DBPassword ));
354
+ call_user_func_array (array ($ this , $ method ), $ parameters );
355
+ } else {
356
+ if (($ this ->pdo === null || !$ this ->inTransaction ()) && php_sapi_name () !== "cli " ) {
357
+ //Prevent search engines to crawl
358
+ header ("HTTP/1.1 500 Internal Server Error " );
359
+ header ("Status: 500 Internal Server Error " );
360
+ echo $ exception ;
361
+ exit ();
362
+ } else {
363
+ throw $ e ;
364
+ }
365
+ }
213
366
}
214
367
}
0 commit comments