20171121_Python學習六周二次課(11月21日)
任務:
12.5 遊標
12.6 mysql連接池
12.7 設計表結構
筆記:
a) 遊標操作
我們先來看一個例子:
接下來,我們通過python代碼增加一條數據到數據庫中,代碼如下:
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 = ‘‘‘ 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()
b) 數據庫連接池
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.關閉連接的時候,把連接放回連接池,而不是真正的關閉,所以可以減少頻繁地打開和關閉連接
1. 建表
數據庫鍵表,直接在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。
20171121_Python學習六周二次課(11月21日)