任務:python
12.5 遊標
12.6 mysql鏈接池
12.7 設計表結構mysql
筆記:sql
咱們先來看一個例子:數據庫
接下來,咱們經過python代碼增長一條數據到數據庫中,代碼以下:編程
import MySQLdb安全
def connect_mysql():app
db_config = {dom
'host': '192.168.48.128',函數
'port': 3306,性能
'user': 'xiang',
'passwd': '123456',
'db': 'python',
'charset': 'utf8'
}
cnx = MySQLdb.connect(**db_config)
return cnx
if __name__ == '__main__':
cnx = connect_mysql()
cus = cnx.cursor()
sql = ''' create table test(id int not null);insert into test(id) values (100);'''
try:
cus.execute(sql)
cus.close()
cnx.commit()
except Exception as e:
cnx.rollback()
print('Error')
# raise e
finally:
cnx.close()
結果:
Error
查看數據庫中的數據:select * from employees;並無發生變化
解釋:
在咱們插入數據僱傭時間字段:hire_date的時候,故意把時間寫錯,致使異常發生,捕獲到異常以後,打印Error,最後關閉mysql鏈接。cus = cnx.cursor()是建立一個遊標對象,具體咱們在後面進行介紹。
1,建立遊標對象
Import MySQLdb
db_config = {
'host': '192.168.48.128',
'port': 3306,
'user': 'xiang',
'passwd': '123456',
'db': 'python',
'charset': 'utf8'
}
cnx = MySQLdb.connect(**db_config)
cus = cnx.cursor()
這樣就是建立一個遊標對象,之後咱們對mysql的各類操做都是基於遊標進行操做,後面咱們將詳細介紹。
在瞭解該方法以前,咱們先來了解什麼叫作遊標,
遊標(cursor)
遊標是系統爲用戶開設的一個數據緩衝區,存放SQL語句的執行結果
用戶能夠用SQL語句逐一從遊標中獲取記錄,並賦給主變量,交由python進一步處理,一組主變量一次只能存放一條記錄
僅使用主變量並不能徹底知足SQL語句嚮應用程序輸出數據的要求
1.遊標和遊標的優勢
在數據庫中,遊標是一個十分重要的概念。遊標提供了一種對從表中檢索出的數據進行操做的靈活手段,就本質而言,遊標其實是一種能從包括多條數據記錄的結果集中每次提取一條記錄的機制。遊標老是與一條SQL 選擇語句相關聯由於遊標由結果集(能夠是零條、一條或由相關的選擇語句檢索出的多條記錄)和結果集中指向特定記錄的遊標位置組成。當決定對結果集進行處理時,必須聲明一個指向該結果集的遊標。
經常使用方法:
cursor():建立遊標對象
close():關閉此遊標對象
fetchone():獲得結果集的下一行
fetchmany([size = cursor.arraysize]):獲得結果集的下幾行
fetchall():獲得結果集中剩下的全部行
excute(sql[, args]):執行一個數據庫查詢或命令
executemany (sql, args):執行多個數據庫查詢或命令
下面咱們來看一個例子:
import MySQLdb
def connect_mysql():
db_config = {
'host': '192.168.48.128',
'port': 3306,
'user': 'xiang',
'passwd': '123456',
'db': 'python',
'charset': 'utf8'
}
cnx = MySQLdb.connect(**db_config)
return cnx
if __name__ == '__main__':
cnx = connect_mysql()
cus = cnx.cursor()
sql = '''select * from employees;'''
try:
cus.execute(sql)
result1 = cus.fetchone()
print('result1:')
print(result1)
result2 = cus.fetchmany(1)
print('result2:')
print(result2)
result3 = cus.fetchall()
print('result3:')
print(result3) cus.close()
cnx.commit()
except Exception as e:
cnx.rollback()
print('error')
raise e
finally:
cnx.close()
結果:
result1:
(1001L, u'lingjiang', u'M', datetime.date(2015, 4, 1))
result2:
((1002L, u'xiang', u'M', datetime.date(2015, 4, 1)),)
result3:
((1003L, u'shang', u'M', datetime.date(2015, 4, 1)),)
解釋:
1,先經過MySQLdb.connect(**db_config)創建mysql鏈接對象
2,在經過 = cnx.cursor()建立遊標
3,fetchone():在最終搜索的數據中去一條數據
4,fetchmany(1)在接下來的數據中在去1行的數據,這個數字能夠自定義,定義多少就是在結果集中取多少條數據。
5,fetchall()是在全部的結果中搞出來全部的數據。
對於excute()和excutemany()的方法,咱們會在以一節詳細分析他們的區別。
執行多條語句的sql時要注意:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2017/9/18 22:17
# @Author : lingxiangxiang
# @File : domon3.py
from demon2 import connect_mysql
import MySQLdb
def connect_mysql():
db_config = {
"host": "192.168.48.128",
"port": 3306,
"user": "xiang",
"passwd": "123456",
"db": "python",
"charset": "utf8"
}
try:
cnx = MySQLdb.connect(**db_config)
except Exception as e:
raise e
return cnx
if __name__ == "__main__":
sql = "select * from tmp;"
sql1 = "insert into tmp(id) value (%s);"
param = []
for i in xrange(100, 130):
param.append([str(i)])
print(param)
cnx = connect_mysql()
cus = cnx.cursor()
print(dir(cus))
try:
cus.execute(sql)
cus.executemany(sql1, param)
# help(cus.executemany)
result1 = cus.fetchone()
print("result1")
print(result1)
result2 = cus.fetchmany(3)
print("result2")
print(result2)
result3 = cus.fetchall()
print("result3")
print(result3)
cus.close()
cnx.commit()
except Exception as e:
cnx.rollback()
raise e
finally:
cnx.close()
python編程中可使用MySQLdb進行數據庫的鏈接及諸如查詢/插入/更新等操做,可是每次鏈接mysql數據庫請求時,都是獨立的去請求訪問,至關浪費資源,並且訪問數量達到必定數量時,對mysql的性能會產生較大的影響。所以,實際使用中,一般會使用數據庫的鏈接池技術,來訪問數據庫達到資源複用的目的。
python的數據庫鏈接池包 DBUtils:
DBUtils是一套Python數據庫鏈接池包,並容許對非線程安全的數據庫接口進行線程安全包裝。DBUtils來自Webware for Python。
DBUtils提供兩種外部接口:
* PersistentDB :提供線程專用的數據庫鏈接,並自動管理鏈接。
* PooledDB :提供線程間可共享的數據庫鏈接,並自動管理鏈接。
下載地址:https://pypi.python.org/pypi/DBUtils/ 下載解壓後,使用python setup.py install 命令進行安裝
或者使用
Pip install DBUtils
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2017/9/18 22:46
# @Author : lingxiangxiang
# @File : demon4.py
import MySQLdb
from DBUtils.PooledDB import PooledDB
db_config = {
"host": "192.168.48.128",
"port": 3306,
"user": "xiang",
"passwd": "123456",
"db": "python",
"charset": "utf8"
}
pool = PooledDB(MySQLdb, 5, **db_config) # 5爲鏈接池裏的最少鏈接數
conn = pool.connection() # 之後每次須要數據庫鏈接就是用connection()函數獲取鏈接就行了
cur = conn.cursor()
SQL = "select * from tmp;"
r = cur.execute(SQL)
r = cur.fetchall()
print(r)
cur.close()
conn.close()
PooledDB的參數:
1. mincached,最少的空閒鏈接數,若是空閒鏈接數小於這個數,pool會建立一個新的鏈接
2. maxcached,最大的空閒鏈接數,若是空閒鏈接數大於這個數,pool會關閉空閒鏈接
3. maxconnections,最大的鏈接數,
4. blocking,當鏈接數達到最大的鏈接數時,在請求鏈接的時候,若是這個值是True,請求鏈接的程序會一直等待,直到當前鏈接數小於最大鏈接數,若是這個值是False,會報錯,
5. maxshared 當鏈接數達到這個數,新請求的鏈接會分享已經分配出去的鏈接
在uwsgi中,每一個http請求都會分發給一個進程,鏈接池中配置的鏈接數都是一個進程爲單位的(即上面的最大鏈接數,都是在一個進程中的鏈接數),而若是業務中,一個http請求中須要的sql鏈接數不是不少的話(其實大多數都只須要建立一個鏈接),配置的鏈接數配置都不須要太大。
鏈接池對性能的提高表如今:
1.在程序建立鏈接的時候,能夠從一個空閒的鏈接中獲取,不須要從新初始化鏈接,提高獲取鏈接的速度
2.關閉鏈接的時候,把鏈接放回鏈接池,而不是真正的關閉,因此能夠減小頻繁地打開和關閉鏈接
數據庫鍵表,直接在python代碼中執行,
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2017/5/5 13:56
# @Author : lingxiangxiang
# @File : aa.py
import MySQLdb
def connect_mysql():
db_config = {
'host': '192.168.48.128',
'port': 3306,
'user': 'xiang',
'passwd': '123456',
'db': 'python',
'charset': 'utf8'
}
cnx = MySQLdb.connect(**db_config)
return cnx
if __name__ == '__main__':
cnx = connect_mysql()
cus = cnx.cursor()
# sql = '''insert into student(id, name, age, gender, score) values ('1001', 'ling', 29, 'M', 88), ('1002', 'ajing', 29, 'M', 90), ('1003', 'xiang', 33, 'M', 87);'''
student = '''create table Student(
StdID int not null,
StdName varchar(100) not null,
Gender enum('M', 'F'),
Age tinyint
)'''
course = '''create table Course(
CouID int not null,
CName varchar(50) not null,
TID int not null
)'''
score = '''create table Score(
SID int not null,
StdID int not null,
CID int not null,
Grade int not null
)'''
teacher = '''create table Teacher(
TID int not null,
TName varchar(100) not null
)'''
tmp = '''set @i := 0;
create table tmp as select (@i := @i + 1) as id from information_schema.tables limit 10;
'''
try:
cus.execute(student)
cus.execute(course)
cus.execute(score)
cus.execute(thearch)
cus.execute(tmp)
cus.close()
cnx.commit()
except Exception as e:
cnx.rollback()
print('error')
raise e
finally:
cnx.close()
結果:
mysql> show tables;
+------------------+
| Tables_in_python |
+------------------+
| Course |
| Score |
| Student |
| Teacher |
| tmp |
+------------------+
1 rows in set (0.00 sec)
沒有任何異常,在數據庫中查看錶,出現這五個表。說明這五個表已經建立成功。
既然咱們要搞,就儘量的接近實戰,咱們來把數據搞大一點,語句設計的複雜一點,這樣對咱們之後接觸到簡單的sql語句時,就有很大的幫助。
首先咱們先來了解一下information_schema這個庫,這個在mysql安裝時就有了,提供了訪問數據庫元數據的方式。那什麼是元數據庫呢?元數據是關於數據的數據,如數據庫名或表名,列的數據類型,或訪問權限等。有些時候用於表述該信息的其餘術語包括「數據詞典」和「系統目錄」。
information_schema數據庫表說明:
SCHEMATA表:提供了當前mysql實例中全部數據庫的信息。是show databases的結果取之此表。
TABLES表:提供了關於數據庫中的表的信息(包括視圖)。詳細表述了某個表屬於哪一個schema,表類型,表引擎,建立時間等信息。是show tables from schemaname的結果取之此表。
COLUMNS表:提供了表中的列信息。詳細表述了某張表的全部列以及每一個列的信息。是show columns from schemaname.tablename的結果取之此表。
STATISTICS表:提供了關於表索引的信息。是show index from schemaname.tablename的結果取之此表。
USER_PRIVILEGES(用戶權限)表:給出了關於全程權限的信息。該信息源自mysql.user受權表。是非標準表。
SCHEMA_PRIVILEGES(方案權限)表:給出了關於方案(數據庫)權限的信息。該信息來自mysql.db受權表。是非標準表。
TABLE_PRIVILEGES(表權限)表:給出了關於表權限的信息。該信息源自mysql.tables_priv受權表。是非標準表。
COLUMN_PRIVILEGES(列權限)表:給出了關於列權限的信息。該信息源自mysql.columns_priv受權表。是非標準表。
CHARACTER_SETS(字符集)表:提供了mysql實例可用字符集的信息。是SHOW CHARACTER SET結果集取之此表。
COLLATIONS表:提供了關於各字符集的對照信息。
COLLATION_CHARACTER_SET_APPLICABILITY表:指明瞭可用於校對的字符集。這些列等效於SHOW COLLATION的前兩個顯示字段。
TABLE_CONSTRAINTS表:描述了存在約束的表。以及表的約束類型。
KEY_COLUMN_USAGE表:描述了具備約束的鍵列。
ROUTINES表:提供了關於存儲子程序(存儲程序和函數)的信息。此時,ROUTINES表不包含自定義函數(UDF)。名爲「mysql.proc name」的列指明瞭對應於INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
VIEWS表:給出了關於數據庫中的視圖的信息。須要有show views權限,不然沒法查看視圖信息。
TRIGGERS表:提供了關於觸發程序的信息。必須有super權限才能查看該表
而TABLES在安裝好mysql的時候,必定是有數據的,由於在初始化mysql的時候,就須要建立系統表,該表必定有數據。
set @i := 0;
create table tmp as select (@i := @i + 1) as id from information_schema.tables limit 10;
mysql中變量不用事前申明,在用的時候直接用「@變量名」使用就能夠了。set這個是mysql中設置變量的特殊用法,當@i須要在select中使用的時候,必須加:,這樣就建立好了一個表tmp,查看tmp的數據:
mysql> select * from tmp;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+------+
10 rows in set (0.00 sec)
咱們只是從information_schema.tables表中取10條數據,任何表有10條數據也是能夠的,而後把變量@i做爲id列的值,分10次不斷輸出,依據最後select的結果,建立表tmp。