數據庫MySql在python中的使用

  隨着須要存儲數據的結構不斷複雜化,使用數據庫來存儲數據是一個必須面臨的問題。那麼應該如何在python中使用數據庫?下面就在本篇博客中介紹一下在python中使用mysql。html

  首先,本博客已經假定閱讀者已經安裝了python和mysql,因此不會講解關於它們的安裝(若是未安裝,請查閱官方文檔進行下載安裝)。python

 

在python中使用pymysql操做mysql  

python的標準庫中,是沒有能夠直接鏈接操做mysql的模塊,首先咱們應安裝python的第三方模塊pymysql。mysql

使用pymysql操做mysql的步驟:程序員

  1)使用pymysql.connect鏈接並登陸mysqlweb

  2) 使用connection.cursor創建遊標sql

  3) 使用cursor.execute()或cursor.executemany()執行sql語句數據庫

 

例一(使用pymysql執行簡單的mysql操做):編程

  (1) 首先在mysql中創建一張用戶表api

CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(255) COLLATE utf8_bin NOT NULL, `password` varchar(255) COLLATE utf8_bin NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;

  (2) 使用pymysql鏈接數據庫並操做這張表session

 1 import pymysql  2 
 3 # Connect to the database
 4 # 鏈接mysql,host指定主機;port指定端口,若是mysql爲默認端口3306能夠不寫;
 5 # user,password分別指定登陸mysql的用戶名和密碼;
 6 # db指定數據庫;charset指定字符集;
 7 connection = pymysql.connect(host='localhost',  8                              user='root',  9                              password='', 10                              db='test', 11                              charset='utf8mb4', 12                               cursorclass=pymysql.cursors.DictCursor) 13 
14 try: 15  with connection.cursor() as cursor: 16         # Create a new record
17         # 構建sql語句
18         sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
19         # 至關於在mysql終端執行
20         # "INSERT INTO `users` (`email`, `password`) VALUES ('webmaster@python.org', 'very-secret')"
21         cursor.execute(sql, ('webmaster@python.org', 'very-secret')) 22 
23     # connection is not autocommit by default. So you must commit to save
24     # your changes.
25     # 向mysql提交更改,若是是查詢語句,無需執行connection.commit()
26     # 能夠經過設置connection.autocommit()來自動提交,傳入True便可
27  connection.commit() 28 
29  with connection.cursor() as cursor: 30         # Read a single record
31         # sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s"
32         # cursor.execute(sql, ('webmaster@python.org',))
33         sql = "SELECT * FROM `users`"
34         # 執行cursor.execute(sql),等於在mysql終端執行sql語句。
35  cursor.execute(sql) 36         # 獲取sql語句執行結果並打印
37         result = cursor.fetchall() 38         print(result) 39 finally: 40     # 關閉鏈接
41     connection.close()
pymysql_example.py

 

例二(向mysql中的表插入多條信息):

 1 import pymysql  2 
 3 connection = pymysql.Connect(host="localhost",  4                              user="root",  5                              password="",  6                              db="test",  7                              charset="utf8mb4",  8                              cursorclass=pymysql.cursors.DictCursor)  9 
10 try: 11     # # 執行屢次INSERT操做
12     # with connection.cursor() as cursor:
13     # users_info = [('xiaoming@123.com','simple'), ('xiaoqiang@123.com','simple'),
14     # ('xiaozhang@123.com','very-secret'), ('xiaoli@123.com', 'simple'),
15     # ('xiangwang@123.com','simple'), ('xiaohong@123.com','very-secret')]
16     # sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
17     # # 執行屢次相同操做使用cursor.executemany()
18     # cursor.executemany(sql, users_info)
19     # connection.commit()
20 
21     # 查詢全部用戶信息
22  with connection.cursor() as cursor: 23         sql = "SELECT * FROM `users`"
24  cursor.execute(sql) 25         result = cursor.fetchall() 26         print("-----all users-----") 27         for user_info in result: 28             print(user_info) 29 
30  with connection.cursor() as cursor: 31         sql = "SELECT * FROM `users` WHERE `password`=%s"
32         cursor.execute(sql, ('very-secret',)) 33         result = cursor.fetchall() 34         print("-----password is very-secret-----") 35         for user_info in result: 36             print(user_info) 37 finally: 38     connection.close()
test_pymysql.py

  注:在python程序中使用pymysql,最好只執行對錶的增刪該查便可(使用pymysql雖然能執行原生SQL語句,但不建議使用它進行建數據庫,表,修改數據庫,表屬性等操做(若是要進行這些操做不妨直接登陸mysql,直接在mysql終端執行這些操做)。

下面將介紹一些pymysql的一些經常使用API(在pymysq中只有兩個經常使用object):

(1)Connection Object:

  經常使用屬性:

host – mysql主機地址 user – 登陸用戶名 password – 登陸用戶密碼 port – mysql端口,默認3306 charset – 字符集 connect_timeout – 鏈接最大時間,超時自動斷開。(default: 10, min: 1, max: 31536000) autocommit – 是否自動提交更改。(default: False) db – 使用指定的數據庫 cursorclass – 指定cursor類

  注:以上參數應在鏈接數據庫時指定,只是經常使用參數(詳細請參見:http://pymysql.readthedocs.io/en/latest/modules/connections.html)。

  經常使用方法:

begin() - 開啓一個事件 與 在mysql終端執行BEGIN效果相同 close() - 關閉與mysql的鏈接 commit() - 提交對mysql中存儲數據的更改 cursor(cursor=None) - 建立一個cursor對象,cursor類在鏈接時未指明,能夠在此指明,使用默認cursor忽略參數便可 ping(reconnect=True) - 檢測鏈接是否存活,若是鏈接超過設置的connet_timeout會自動斷開,因此在進行對mysql操做前應使用此方法檢測 rollback() - 使用了begin()後,對mysql的操做未提交前,能夠只用此方法恢復到未操做以前 select_db(db) - 選擇數據庫,若是要操做的表不在鏈接時指定的數據庫,使用此方法切換。 show_warnings() - 顯示警告信息

(2)Cursor Objects:

  經常使用方法:

execute(query, args=None) - 執行一條sql語句 Parameters: query (str) – 要被執行的sql語句 args (tuple, list or dict) – sql語句中用到的參數 Returns: 多少行信息收到影響 Return type: int 若是args是以tuple的形式指定,則按位置依次傳入sql語句中;若是是以dict傳入,則以關鍵字傳入sql語句中。 executemany(query, args) - 屢次執行這條sql語句 參數與上相同,不過要使用[]將多個args括起來。 此方法可提升多行INSERT和REPLACE的性能。 不然,它等價於使用execute() 循環args。 fetchone() - 取結果中的一行 fetchall() - 取全部的結果 fetchmany(size=None) - 取結果中的size行 close() - 關閉當前cursor max_stmt_length = 1024000 - 指定 executemany() 執行最多max_stmt_length次sql語句

  注:只寫了經常使用方法,詳細請參見:http://pymysql.readthedocs.io/en/latest/modules/cursors.html

 

使用sqlalchemy操做數據庫(重點)

例三(使用sqlalchemy建立一張數據表並插入數據):

  使用pymysql當然能夠與mysql進行交互,但仍是在源代碼中使用了原生SQL語句,使代碼的重用行和擴展性大大下降,這不符合面向對象的編程的特性。那麼該如何像操做對象同樣操做數據庫呢?

  咱們使用一種叫作ORM(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping)的技術,是一種程序技術,用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換。在python中咱們使用一個名爲SQLAlchemy(基於ORM的開發組件)來進行對數據庫的操做,這樣就沒必要在源代碼中使用SQL語句,大大下降了程序員學習SQL的成本,因爲沒必要再拼接複雜的SQL語句,大大提升開發效率,而且使程序有更高的擴展性。

 1 import sqlalchemy  2 from sqlalchemy import create_engine  3 from sqlalchemy.ext.declarative import declarative_base  4 from sqlalchemy import Column, Integer, String  5 from sqlalchemy.orm import sessionmaker  6 
 7 # 檢查sqlalchemy的版本
 8 # print(sqlalchemy.__version__)
 9 
10 # 建立一個engine
11 # 傳入一個URL做爲第一個位置參數(格式爲:dialect[+driver]://user:password@host/dbname[?key=value..])
12 # dialect is a database name such as mysql, oracle, postgresql, ,
13 # and driver the name of a DBAPI, such as psycopg2, pyodbc, cx_oracle, pymysql.
14 # 打印操做數據庫的過程,則設置echo=True,不然默認便可
15 engine = create_engine('mysql+pymysql://root:123456@localhost/test') 16 
17 Base = declarative_base() 18 
19 # 將要建立的表結構
20 class User(Base): 21     # 表名
22     __tablename__ = 'users'
23 
24     # 字段名,字段屬性
25     id = Column(Integer, primary_key=True) 26     name = Column(String(32)) 27     fullname = Column(String(64)) 28     password = Column(String(64)) 29 
30     def __repr__(self): 31         return "<User(name='%s', fullname='%s', password='%s')>" % ( 32  self.name, self.fullname, self.password) 33 
34 # 能夠同時建立多個表,在前面以上面的形式寫好全部表結構,最後統一建立
35 Base.metadata.create_all(engine) 36 
37 # 建立一個Session類
38 # Session = sessionmaker()
39 # Session.configure(bind=engine)
40 # 等同於上面兩行
41 Session = sessionmaker(bind=engine) 42 # 生成一個session實例
43 session = Session() 44 
45 # 構造要插入表中的數據
46 ed_user = User(name='ed', fullname='Ed Jones', password='edspassword') 47 # 將數據放入session中,若是有多條數據使用session.add_all([data1,data2,...])
48 session.add(ed_user) 49 # session.add_all([User(name='wendy', fullname='Wendy Williams', password='foobar'),
50 # User(name='mary', fullname='Mary Contrary', password='xxg527'),
51 # User(name='fred', fullname='Fred Flinstone', password='blah')])
52 # 向數據庫提交
53 # session.commit()
54 
55 data = session.query(User).filter(User.id>2).all() 56 print(data)
sqlalchemy_test.py
# 使用上面的代碼生成的數據表結構 mysql> desc users; +----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     | NO   | PRI | NULL    | auto_increment |
| name     | varchar(32) | YES  |     | NULL    |                |
| fullname | varchar(64) | YES  |     | NULL    |                |
| password | varchar(64) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec) # 使用上面代碼插入表中的數據 mysql> select * from users; +----+------+----------+-------------+
| id | name | fullname | password    |
+----+------+----------+-------------+
|  1 | ed   | Ed Jones | edspassword |
+----+------+----------+-------------+
1 row in set (0.00 sec)

 

例四(使用sqlalchemy進行對數據的查,改,刪)

 1 # 查詢時在filter_by(或filter)中寫上條件便可,查詢到的結果多是多條,first()表明取第一條,all()表明取全部
 2 our_user = session.query(User).filter_by(name='ed').first()  3 # 若是有多個查詢條件,data = session.query(User).filter(User.id>2).filter(User.id<4).all(),這樣使用便可
 4 data = session.query(User).filter(User.id>2).all()  5 print("-------這是查詢數據的結果-------")  6 print(our_user)  7 print(data)  8 print('\n')  9 
10 # 直接修改查詢的結果,而後提交便可
11 our_user.password = 'f8s7ccs'
12 session.commit() 13 new_user = session.query(User).filter_by(name='ed').first() 14 print("-------這是修改數據的結果-------") 15 print(new_user) 16 print('\n') 17 
18 # 先查詢出要刪除的數據,而後使用session.delete()和session.delete()便可
19 data = session.query(User).filter(User.id==5).first() 20 # print(data)
21 session.delete(data) 22 session.commit()
使用sqlalchemy操做數據庫中的數據

 

例五(使用sqlalchemy實現數據表的外鍵關聯):

  做爲關係型數據庫,表與表之間的外鍵關聯是比不可少的,也是相當重要的,那麼改如何使用sqlalchemy在python對象中經過類的形式映射這種關係呢? 請看下面的代碼。

 1 import sqlalchemy  2 from sqlalchemy import create_engine  3 from sqlalchemy.ext.declarative import declarative_base  4 from sqlalchemy import Column, Integer, String, Enum, ForeignKey  5 from sqlalchemy.orm import sessionmaker, relationship  6 
 7 engine = create_engine('mysql+pymysql://root:123456@localhost/student')  8 
 9 Base = declarative_base() 10 
11 class Student(Base): 12     __tablename__ = 'student_info'
13 
14     # 設置id, 類型爲int, 不能爲空, id是這張表的主鍵
15     id = Column(Integer, nullable=False, primary_key=True) 16     # 設置stu_id, 類型爲int, 不能爲空, id在這張表中的值惟一
17     stu_id = Column(Integer, nullable=False, unique=True) 18     name = Column(String(32), nullable=False, ) 19     age = Column(Integer, nullable=False, ) 20     gender = Column(Enum('F', 'M'), nullable=False) 21 
22     # 查詢結果的顯示是此函數返回的格式
23     def __repr__(self): 24         return "<Student(stu_id='%s', name='%s', age='%s', gender='%s')>" % ( 25  self.stu_id, self.name, self.age, self.gender) 26 
27 class Study(Base): 28     __tablename__ = 'study_level'
29 
30     id = Column(Integer, nullable=False, primary_key=True) 31     # 設置stu_id爲study_level表的外鍵,與student_info表中的stu_id關聯
32     stu_id = Column(Integer, ForeignKey('student_info.stu_id')) 33     mathematics = Column(Integer) 34     physics = Column(Integer) 35     chemistry = Column(Integer) 36 
37     # 定義關係,能夠在本類中使用屬性student_info查詢表student_info中的數據(以一樣的條件)
38     # 也能夠在Student類中使用屬性study_level查詢表study_level中的數據
39     student_info = relationship('Student', backref='study_level') 40 
41     def __repr__(self): 42         return "<Study(name=%s, mathematics=%s, physics=%s, chemistry=%s)>" % ( 43  self.student_info.name, self.mathematics, self.physics, self.chemistry) 44 
45 # Base.metadata.create_all(engine)
46 
47 Session = sessionmaker(engine) 48 session = Session() 49 
50 # 插入4個學生信息
51 # session.add_all([Student(stu_id=10001, name='zhangsan', age=16, gender='F'),
52 # Student(stu_id=10002, name='lisi', age=17, gender='M'),
53 # Student(stu_id=10003, name='wangwu', age=16, gender='M'),
54 # Student(stu_id=10004, name='zhouliu', age=15, gender='F')])
55 # 56 # 插入考試成績,成績不到60分的科目需補考,再插入補考成績
57 # session.add_all([Study(stu_id=10001, mathematics=78, physics=70, chemistry=83),
58 # Study(stu_id=10002, mathematics=87, physics=85, chemistry=92),
59 # Study(stu_id=10003, mathematics=60, physics=54, chemistry=76),
60 # Study(stu_id=10004, mathematics=52, physics=46, chemistry=44),
61 # Study(stu_id=10003, physics=68),
62 # Study(stu_id=10004, mathematics=63, physics=61, chemistry=65)])
63 # session.commit()
64 
65 # 使用這種方法查詢多張表,表之間能夠沒有任何關係
66 data = session.query(Student, Study).filter(Student.stu_id==Study.stu_id).all() 67 print(data) 68 print('\n') 69 
70 
71 # 使用下面的方法經過一張表查詢其餘表,表之間必須有外鍵關聯
72 # 由於每一個學生的信息惟一,因此使用first()
73 student = session.query(Student).filter(Student.stu_id==10003).first() 74 print(student) 75 # print(student.study_level)至關於Student.stu_id==10003時,下面的兩行代碼
76 # data = session.query(Study).filter(session.query(Study).filter(Student.stu_id==Study.stu_id).all()).all()
77 # print(data)
78 print(student.study_level) 79 print('\n') 80 
81 # 由於一個學生可能會有屢次考試記錄,因此使用all()
82 score = session.query(Study).filter(Study.stu_id==10003).all() 83 print(score) 84 # print(score[0].student_info)至關於Study.stu_id==10003時
85 # 由於在student_info表中stu_id的值惟一,因此只有一條數據
86 # data = session.query(Student).filter(Study[0].stu_id==Student.stu_id).first()
87 # print(data)
88 print(score[0].student_info)
fk_sqlalchemy.py
mysql> select * from student_info; +----+--------+----------+-----+--------+
| id | stu_id | name     | age | gender |
+----+--------+----------+-----+--------+
|  1 |  10001 | zhangsan |  16 | F      |
|  2 |  10002 | lisi     |  17 | M      |
|  3 |  10003 | wangwu   |  16 | M      |
|  4 |  10004 | zhouliu  |  15 | F      |
+----+--------+----------+-----+--------+
4 rows in set (0.00 sec) mysql> select * from study_level; +----+--------+-------------+---------+-----------+
| id | stu_id | mathematics | physics | chemistry |
+----+--------+-------------+---------+-----------+
|  1 |  10001 |          78 |      70 |        83 |
|  2 |  10002 |          87 |      85 |        92 |
|  3 |  10003 |          60 |      54 |        76 |
|  4 |  10004 |          52 |      46 |        44 |
|  5 |  10003 |        NULL |      68 |      NULL | #學號爲10003的學生,只有一科成績小於60,只補考一科
|  6 |  10004 |          63 |      61 |        65 | #學號爲10004的學生,三科成績都小於60,需補考三科
+----+--------+-------------+---------+-----------+
6 rows in set (0.00 sec)

   注:對有外鍵關聯的數據表,進行數據的增刪該查,與上例中使用的方式同樣,不過受外鍵約束,約束條件同mysql中外鍵的約束相同。(詳細請參見:http://www.cnblogs.com/God-Li/p/8157312.html)

 

例六(使用sqlalchemy實現mysql中多對多的關係):

  多對多的數據關係是最多見的實際生產的數據關係,好比超市的商品與顧客之間的關係(一個顧客能夠買多種商品,一種商品能夠被多個顧客購買),好比電影與演員的關係(一名演員能夠參演多部電影,一部電影會有多個演員),這些數據是咱們常用的,好比咱們在視頻網站查找電影時,會有按演員查找,對於一部電影咱們也常常關注是哪些演員參演的。那麼改如何使用sqlalchemy在mysql中存儲這些關係呢?咱們就以超市商品與顧客之間的關係來作一個示例,請看下面的代碼。

  爲了便於理解,咱們先來看一下表結構(一共三張表)

# 商品表,存儲商品的名稱,價格,和生產日期(爲了簡單隻存這幾樣信息) mysql> select * from products; +----+-------------+-------+------------+
| id | name        | price | pro_date   |
+----+-------------+-------+------------+
|  1 | iPhone8     |  6988 | 2017-09-18 |
|  2 | Apple Watch |  2588 | 2017-06-20 |
|  3 | Airpods     |  1288 | 2017-01-11 |
|  4 | MacBook     | 10288 | 2017-05-13 |
+----+-------------+-------+------------+
4 rows in set (0.00 sec) # 顧客表,存儲顧客的姓名(這裏爲了簡單隻存了姓名,其實還應該用性別、年齡等具體信息) mysql> select * from customers; +----+-----------+
| id | name      |
+----+-----------+
|  1 | ZhangSang |
|  2 | WangWu    |
|  3 | XiaoMing  |
|  4 | LiSi      |
|  5 | ZhaoLiu   |
+----+-----------+
5 rows in set (0.00 sec) # 商品顧客關係表,存儲商品與用戶的關係,可經過用戶查購買了哪些商品,也可經過商品查有哪些用戶購買 mysql> select * from product_to_customer; +------------+-------------+
| product_id | customer_id |
+------------+-------------+
|          4 |           4 |
|          4 |           3 |
|          3 |           2 |
|          2 |           1 |
|          2 |           4 |
|          2 |           2 |
|          2 |           5 |
|          2 |           3 |
|          1 |           1 |
|          1 |           4 |
|          1 |           5 |
+------------+-------------+
11 rows in set (0.00 sec)

  接着咱們來看一下如何使用python來建立這些表,插入並查詢這些信息。

 1 import sqlalchemy  2 from sqlalchemy import Table, Column, Integer, String, DATE, ForeignKey  3 from sqlalchemy.orm import relationship  4 from sqlalchemy.ext.declarative import declarative_base  5 from sqlalchemy import create_engine  6 
 7 Base = declarative_base()  8 
 9 # 商品與顧客關係表結構
10 product_to_customer = Table('product_to_customer', Base.metadata, 11                             Column('product_id', Integer, ForeignKey('products.id')), 12                             Column('customer_id', Integer, ForeignKey('customers.id'))) 13 
14 # 用戶表結構
15 class Customer(Base): 16     __tablename__ = 'customers'
17 
18     id = Column(Integer, primary_key=True) 19     name = Column(String(32)) 20 
21     def __repr__(self): 22         return self.name 23 
24 # 商品表結構
25 class Product(Base): 26     __tablename__ = 'products'
27 
28     id = Column(Integer, primary_key=True) 29     name = Column(String(32)) 30     price = Column(Integer) 31     pro_date = Column(DATE) 32     customers = relationship(Customer, backref='products', secondary='product_to_customer') 33 
34     def __repr__(self): 35         return self.name 36 
37 
38 engine = create_engine('mysql+pymysql://root:123456@localhost/supermarket') 39 Base.metadata.create_all(engine)
table_struct.py
 1 import table_struct  2 from sqlalchemy.orm import sessionmaker  3 
 4 Session = sessionmaker(table_struct.engine)  5 session = Session()  6 
 7 # 構建商品信息
 8 # p1 = table_struct.Product(name='iPhone8', price='6988', pro_date='2017-9-18')
 9 # p2 = table_struct.Product(name='MacBook', price='10288', pro_date='2017-5-13')
10 # p3 = table_struct.Product(name='Airpods', price='1288', pro_date='2017-1-11')
11 # p4 = table_struct.Product(name='Apple Watch', price='2588', pro_date='2017-6-20')
12 # 
13 # 構建顧客信息
14 # c1 = table_struct.Customer(name="ZhangSang")
15 # c2 = table_struct.Customer(name="LiSi")
16 # c3 = table_struct.Customer(name="WangWu")
17 # c4 = table_struct.Customer(name="ZhaoLiu")
18 # c5 = table_struct.Customer(name="XiaoMing")
19 # 20 # 構建商品與顧客的關係
21 # p1.customers = [c1, c2, c4]
22 # p2.customers = [c2, c5]
23 # p3.customers = [c3]
24 # p4.customers = [c1, c2, c3, c4, c5]
25 # 26 # session.add_all([p1, p2, p3, p4, c1, c2, c3, c4, c5])
27 # session.commit()
28 
29 # 經過顧客查詢他購買了哪些商品
30 customer_obj = session.query(table_struct.Customer).filter(table_struct.Customer.name=='XiaoMing').first() 31 print(customer_obj.products) 32 
33 # 經過商品查詢有哪些顧客購買
34 product_obj = session.query(table_struct.Product).filter(table_struct.Product.name=="iPhone8").first() 35 print(product_obj.customers)
database_api.py
相關文章
相關標籤/搜索