@@ -70,6 +70,55 @@ cur.execute('SET CHARACTER SET utf8;')
70
70
cur.execute(' SET character_set_connection=utf8;' )
71
71
```
72
72
73
+ 打开游标也可以使用 上下文管理器 ,这样可以自动执行关闭操作。
74
+
75
+ ```
76
+ # coding=utf-8
77
+
78
+ import MySQLdb
79
+
80
+ conn = MySQLdb.Connection(host='127.0.0.1', user='root', passwd='123456', db='test', port=3306, charset='utf8')
81
+
82
+ with conn as cur:
83
+
84
+ cur.execute('SELECT * FROM user')
85
+
86
+ print 'sum:', cur.rowcount
87
+
88
+ for row in cur.fetchall():
89
+ print row
90
+
91
+ ```
92
+
93
+ 使用 上下文管理器还有一个好处,就是在 with 语句中的所有 SQL 执行作为一个事务 ,只有全部执行成功才会 commit ,否则会自动 rollback
94
+
95
+ 一般的执行 SQL 语句是使用游标 cursor 操作的,我们也可以直接使用 connection 执行 SQL 语句。
96
+
97
+ ```
98
+ # coding=utf-8
99
+
100
+ import MySQLdb
101
+
102
+ try:
103
+ conn = MySQLdb.connect(host='127.0.0.1', user='root', passwd='123456', db='test', port=3306, charset='utf8')
104
+
105
+ # 数据库连接信息
106
+ print "Host Info :", conn.get_host_info()
107
+ print "Server Info:", conn.get_server_info()
108
+
109
+ conn.query('SELECT * FROM user')
110
+
111
+ # fetch_row 默认只取一条数据
112
+ for row in conn.use_result().fetch_row(10):
113
+ print row
114
+
115
+ except MySQLdb.Error,e:
116
+ print "MySQL Error %d: %s" % tuple(e)
117
+ else:
118
+ conn.close()
119
+
120
+ ```
121
+
73
122
再来看一个完整的增改删查的代码。
74
123
75
124
``` python
@@ -116,6 +165,58 @@ except MySQLdb.Error,e:
116
165
117
166
这里包含完整的数据库增改删查的操作。
118
167
168
+ #### 参数化 SQL 查询
169
+
170
+ 为了防止 SQL 注入,建议使用 参数化 查询,MySQLdb 自动进行转义过滤。
171
+
172
+ ```
173
+ # coding=utf-8
174
+
175
+ import MySQLdb
176
+
177
+ conn = MySQLdb.Connection(host='127.0.0.1', user='root', passwd='123456', db='test', port=3306, charset='utf8')
178
+
179
+ with conn as cur:
180
+
181
+ # secure
182
+ cur.execute('SELECT * FROM user WHERE id=%s AND name=%s', ["0 or 1=1; # -- ", 'windard'])
183
+
184
+ print 'sum:', cur.rowcount
185
+
186
+ for row in cur.fetchall():
187
+ print row
188
+
189
+ # insecure
190
+ cur.execute('SELECT * FROM user WHERE id=%s AND name=%s'%("0 or 1=1; # -- ", 'windard'))
191
+
192
+ print 'sum:', cur.rowcount
193
+
194
+ for row in cur.fetchall():
195
+ print row
196
+
197
+ ```
198
+
199
+ MySQLdb 的转义函数是 ` Connection.literal(o) ` ,参数可以是字符串或者是列表。
200
+
201
+ ```
202
+ # coding=utf-8
203
+
204
+ import MySQLdb
205
+
206
+ conn = MySQLdb.Connection(host='127.0.0.1', user='root', passwd='123456', db='test', port=3306, charset='utf8')
207
+
208
+ print conn.literal(["0 or 1=1; # -- ", 'windard'])
209
+
210
+ print conn.literal("0' or 1=1; # -- ")
211
+ ```
212
+
213
+ 转义结果为
214
+
215
+ ```
216
+ ("'0 or 1=1; # -- '", "'windard'")
217
+ '0\' or 1=1; # -- '
218
+ ```
219
+
119
220
#### 进阶操作
120
221
121
222
那我们试一下创建一个新的数据库和新的表单,插入大量的数据来试试。
@@ -217,146 +318,155 @@ except MySQLdb.Error,e:
217
318
```
218
319
#coding=utf-8
219
320
321
+ import chardet
220
322
import MySQLdb
221
323
222
324
class Database(object):
223
- """docstring for Database"""
224
- def __init__(self, host="127.0.0.1", user="root", password="", db="",port=3306, charset="utf8", use_unicode=True, debug=False):
325
+ """Database Control For Beginner"""
326
+ def __init__(self, host='127.0.0.1', user='root', password='', db='', port=3306, charset='utf8', \
327
+ use_unicode=True, debug=False):
225
328
self.host = host
226
329
self.user = user
227
330
self.password = password
228
331
self.port = port
229
332
self.charset = charset
230
333
self.db = db
231
- self.debug = debug
334
+ self._debug = debug
232
335
try:
233
- self.conn = MySQLdb.connect(host=self.host, user=self.user, passwd=self.password, db=self.db, port=self.port, charset=self.charset )
234
- self.conn.set_character_set('utf8')
235
- self.cur = self.conn.cursor()
236
- self.cur.execute('SET NAMES utf8;')
237
- self.cur.execute('SET CHARACTER SET utf8;')
238
- self.cur.execute('SET character_set_connection=utf8;')
239
- except Exception,e:
240
- print e
241
-
242
- def exec_(self, query):
336
+ self._conn = MySQLdb.Connection(host=self.host, user=self.user, passwd=self.password, \
337
+ db=self.db, port=self.port, charset=self.charset)
338
+ self._conn.set_character_set('utf8')
339
+ self._cur = self._conn.cursor()
340
+ self._cur.execute('SET NAMES utf8;')
341
+ self._cur.execute('SET CHARACTER SET utf8;')
342
+ self._cur.execute('SET character_set_connection=utf8;')
343
+ except Exception, e:
344
+ if self._debug:
345
+ print tuple(e)
346
+
347
+ def exec_(self, query, paras=''):
243
348
try:
244
- if self.debug :
349
+ if self._debug :
245
350
print query
246
- self.cur.execute(query)
247
- result = {"code":"00","content":[]}
248
- for x in self.cur.fetchall():
249
- if len(x)==1:
250
- result["content"].append(x[0])
251
- else:
252
- children = []
253
- for y in x:
254
- children.append(y)
255
- result["content"].append(children)
351
+ if paras:
352
+ self._cur.execute(query, paras)
353
+ else:
354
+ self._cur.execute(query)
355
+ result = {'code':1000}
356
+ result['content'] = self._cur.fetchall()
256
357
return result
257
358
except Exception,e:
258
- self.conn .rollback()
259
- result = {" code":"01"," content" :tuple(e)}
359
+ self._conn .rollback()
360
+ result = {' code':1001,' content' :tuple(e)}
260
361
return result
261
362
262
- def get(self, table, filed=["*" ], options={}):
363
+ def get(self, table, filed=['*' ], options={}):
263
364
try:
264
- if "*" in filed:
265
- filed = "*"
365
+ select, where, order, limit, paras, conds = '', '', '', '', [], []
366
+ if '*' in filed:
367
+ select = '*'
266
368
else:
267
- filed = ",".join(filed)
268
- conds = ""
269
- if options.get("where",""):
270
- where = []
271
- for key,value in options.get("where").items():
272
- where.append("%s='%s'"%(unicode(key),unicode(value)))
273
- conds += "WHERE "
274
- conds += " AND ".join(where)
275
- if options.get("order",""):
276
- order = ""
277
- order += " ORDER BY "+ options.get("order")[0]
278
- if len(options.get("order")) == 2:
279
- order += " "+options.get("order")[1]
280
- conds += order
281
- if options.get("limit",""):
282
- limit = ""
283
- if type(options.get("limit")) == unicode:
284
- limit = " LIMIT "+unicode(options.get("limit"))
285
- else:
286
- limit = " LIMIT " + ",".join(options.get("limit"))
287
- conds += limit
288
- return self.exec_("SELECT %s FROM %s %s"%(filed,table,conds))
369
+ select = ','.join(filed)
370
+ if options.get('where', None):
371
+ for key,value in options['where'].items():
372
+ if type(value) == str:
373
+ value = value.decode(chardet.detect(value)['encoding'])
374
+ conds.append("%s %%s"%key)
375
+ paras.append(value)
376
+ where = 'WHERE '
377
+ where += ' AND '.join(conds)
378
+ if options.get('order', None):
379
+ order = ' ORDER BY '+ options['order']
380
+ if options.get('limit', None):
381
+ limit = ' LIMIT ' + ','.join(map(str, options['limit']))
382
+ return self.exec_("SELECT %s FROM %s %s %s %s"%(select, table, where, order, limit), paras)
289
383
except Exception,e:
290
- return {" code":"02"," content" :tuple(e)}
384
+ return {' code':1002, ' content' :tuple(e)}
291
385
292
386
def set(self, table, values, options={}):
293
387
try:
294
- where = []
295
- for key,value in options.items():
296
- where.append("%s='%s'"%(unicode(key),unicode(value)))
297
- conds = []
298
- for key,value in values.items():
299
- conds.append("%s='%s'"%(unicode(key),unicode(value)))
300
- if len(where):
301
- return self.exec_("UPDATE %s SET %s WHERE %s"%(table," AND ".join(conds)," AND ".join(where)))
302
- else:
303
- return self.exec_("UPDATE %s SET %s "%(table," AND ".join(conds)))
388
+ conds, where, paras, stats = [], '', [], []
389
+ for key, value in values.items():
390
+ if type(value) == str:
391
+ value = value.decode(chardet.detect(value)['encoding'])
392
+ conds.append("%s %%s"%key)
393
+ paras.append(value)
394
+ if options:
395
+ for key, value in options.items():
396
+ if type(value) == str:
397
+ value = value.decode(chardet.detect(value)['encoding'])
398
+ stats.append("%s %%s"%key)
399
+ paras.append(value)
400
+ where = 'WHERE '
401
+ where += ' AND '.join(stats)
402
+ return self.exec_('UPDATE %s SET %s %s'%(table, ' AND '.join(conds), where), paras)
304
403
except Exception,e:
305
- return {" code":"03"," content" :tuple(e)}
404
+ return {' code':1003, ' content' :tuple(e)}
306
405
307
406
def new(self, table, values, options=[]):
308
407
try:
309
- conds = ""
310
- for i in values:
311
- if type(i ) == int :
312
- conds += " %d,"
313
- else:
314
- conds += " '%s',"
408
+ conds, paras, stats = [], [], ''
409
+ for value in values:
410
+ if type(value ) == str :
411
+ value = value.decode(chardet.detect(value)['encoding'])
412
+ conds.append("%s")
413
+ paras.append(value)
315
414
if options:
316
- return self.exec_("INSERT INTO %s(%s) VALUES(%s)"%(table," , ".join(options),conds[:-1]%(tuple(values))))
317
- else:
318
- return self.exec_("INSERT INTO %s VALUES(%s)"%(table,conds[:-1]%(tuple(values))))
415
+ stats += '(' + ','.join(options) + ')'
416
+ return self.exec_('INSERT INTO %s%s VALUES(%s)'%(table, stats, ','.join(conds)), paras)
319
417
except Exception,e:
320
- return {" code":"04"," content" :tuple(e)}
418
+ return {' code':1004,' content' :tuple(e)}
321
419
322
420
def del_(self, table, options={}):
323
421
try:
324
- where = []
325
- for key,value in options.items():
326
- where.append("%s='%s'"%(unicode(key),unicode(value)))
327
- if where:
328
- return self.exec_("DELETE FROM %s WHERE %s"%(table," AND ".join(where)))
329
- else:
330
- return self.exec_("DELETE FROM %s"%table)
422
+ where, paras, stats = '', [], []
423
+ if options:
424
+ for key, value in options.items():
425
+ if type(value) == str:
426
+ value = value.decode(chardet.detect(value)['encoding'])
427
+ stats.append("%s %%s"%key)
428
+ paras.append(value)
429
+ where = 'WHERE '
430
+ where += ' AND '.join(stats)
431
+ return self.exec_('DELETE FROM %s %s'%(table, where), paras)
331
432
except Exception,e:
332
- return {" code":"05"," content" :tuple(e)}
433
+ return {' code':1005,' content' :tuple(e)}
333
434
334
435
def __del__(self):
335
436
try:
336
- self.conn.commit()
337
- self.cur.close()
338
- self.conn.close()
339
- except Exception,e:
340
- print e
437
+ try:
438
+ self._conn.commit()
439
+ except Exception,e:
440
+ if self._debug:
441
+ print tuple(e)
442
+ self._conn.rollback()
443
+ self._cur.close()
444
+ self._conn.close()
445
+ except Exception, e:
446
+ if self._debug:
447
+ print tuple(e)
341
448
342
449
"""
343
450
344
451
import databasescontrol
345
452
346
- a = databasescontrol.Database(password="XXXXXX")
347
-
348
- print a.exec_("show databases")
349
-
350
- print a.exec_("use test")
453
+ conn = databasescontrol.Database(password="XXXXXX")
351
454
352
- # print a.get("user",options={"where":{"password":"haha"},"limit":["2","2"],"order":["id","DESC"]} )
353
- # print a.set(" user",{"username":"wocao"} )
455
+ print conn.exec_('use test;' )
456
+ # print conn.get(' user' )
354
457
355
- print a.new("user",["name","password"],["username","password"])
458
+ print conn.get("user", options={'where':{'id >':1, 'name like':'%m%'}, "limit":[1], "order":'id desc'})
459
+ # print conn.get("user", options={'where':{'id >':1, 'name =':'mary'}, "limit":[1, 2], "order":'id desc'})
460
+ # print conn.get("user", filed=['id', 'name', 'passwd'], options={'where':{'id >':1, 'name =':'姓名'}})
461
+ # print conn.get('user', options={'where': {'id in':(1,2)}})
462
+ # print conn.set("user", {"name =":"mary"}, {'id >':2, 'name=':'wocao'})
463
+ # print conn.new("user", ["name","password", 6], ["name","passwd", 'id'])
464
+ # print conn.new('user', [7, 'hello', 'world', 'nihao', 9.0])
465
+ # print conn.new('user', [8, '中文', 'world', '测试', 9.0])
356
466
357
- # print a .del_(" user" )
467
+ # print conn .del_(' user', {'name=':'姓名'} )
358
468
359
- print a .get(" user" )
469
+ print conn .get(' user' )
360
470
361
471
"""
362
472
```
0 commit comments