Python與資料庫的新人手冊 -- MySQL
Python支援的資料庫有很多, MySQL
作為主流資料庫之一,我們不妨瞭解下它們之間的 小故事
Python操作MySQL的庫有三個, python-MySQL(MySQLdb)
, PyMySQL
跟 SQLAlchemy
。
python-MySQL(MySQLdb) PyMySQL SQLAlchemy
本文將主要拿 SQLAlchemy
來進行了解學習。
安裝工具
首先安裝基本的資料庫驅動 pymysql
pip3 install pymysql 複製程式碼
然後安裝ORM框架 SQLAlchemy
pip3 install sqlalchemy 複製程式碼
日常工作中,如果不想每次通過命令列來檢視資料的話。推薦安裝 Navicat for MySQL
,通過這個圖形化工具能夠方便快捷地操作資料庫,實時查詢資料。

初始化資料庫
安裝好必要工具後,我們開始嘗試建立個使用者資料 user
表來。 首先,使用 SQLAlchemy
連線資料庫並定義表結構初始化DBSession。
# 匯入SQLAlchemy from sqlalchemy import Column, BIGINT, String, create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base # 建立基類 Base = declarative_base() # 初始化資料庫連線: # '資料庫型別+資料庫驅動名稱://使用者名稱:密碼@資料庫地址:埠號/資料庫名' engine = create_engine('mysql+pymysql://root:123123@mysql:3306/test') # 建立DBSession型別: DBSession = sessionmaker(bind=engine) # 建立session物件: session = DBSession() # 資料庫操作方法 # 初始化資料庫 def init_db(): Base.metadata.create_all(engine) # 刪除資料庫 def drop_db(): Base.metadata.drop_all(engine) 複製程式碼
建立 user
資料表模型:
# 定義user類 class User(Base): # 表名 __tablename__ = "user" # 表的結構 # 設定id為主鍵 並自增長 id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) gender = Column(String(2)) # 正式初始化資料庫,如果沒有user表的話,這裡將自動建立 init_db() 複製程式碼
這裡有個需要注意的地方就是在初始化資料庫之前需要先定義 user
資料表模型,否則的話無法正常建立 user
資料表。 session
(會話),可以看成一個管理資料庫持久連線的物件,後面的操作都將基於 session
物件進行。
如果使用INT自增型別,那麼當一張表的記錄數超過2147483647(約21億)時,會達到上限而出錯。使用BIGINT自增型別則可以最多約922億億條記錄。
增刪改查操作
增
初始化ORM物件後,我們插入一條記錄試試。
# 建立新User物件: new_user = User(name='mrlizi', gender='man') # 新增到session: session.add(new_user) # 批量新增 session.add_all([ User(name='子非魚', gender='M'), User(name='虞姬', gender='F'), User(name='花木蘭', gender='F') ]) # 提交即儲存到資料庫: session.commit() 複製程式碼
結果:

查
Session
的 query
函式會返回一個Query物件。query函式可以接受多種引數型別。
# query: 輸出所有的使用者名稱 result = session.query(User.name) # order: 按倒序輸出所有使用者 result = session.query(User).order_by(User.id.desc()) result = session.query(User).order_by(-User.id) # label: 自定義欄位名,查詢結果可通過item.my_name來獲取使用者名稱 for item in session.query(User.name.label('my_name')).all() # filter和filter_by: 篩選使用者名稱為'mrlizi'的使用者 result = session.query(User).filter(User.name=='mrlizi').one() result = session.query(User).filter_by(name='mrlizi').one() # offset和limit:組合起來可做分頁查詢(通過python的切片其實也一樣),下面的兩種語句的查詢結果是相同的 result = session.query(User).offset(2).limit(1).all() result = session.query(User)[1:3] # AND: 與查詢 result = session.query(User).filter(and_(User.name=='mrlizi', User.gender=='M')).all() result = session.query(User).filter(User.name=='mrlizi', User.gender=='M') result = session.query(User).filter(User.name=='mrlizi').filter(User.gender=='M').all() # OR: 或查詢 result = session.query(User).filter(or_(User.name == '子非魚', User.name == '花木蘭')) # 模糊查詢 result = session.query(User).filter(User.name.like('子%')).all() 複製程式碼
基本日常用到的查詢方法就是這些,面向物件操作的用法都比較靈活多變,大家可以根據不同才場景自由組合。
改
相比去查詢來講,修改就顯得簡單很多,找到命中的記錄,然後通過 update
方法來進行修改。 update
方法的 synchronize_session
引數用於在更新資料後是否對當前的session進行更新, synchronize_session
= False 不同步更新當前session synchronize_session
= 'fetch'
更新之前從資料庫中拉取實時資料,更新到session物件 synchronize_session
= 'evaluate'
更新之前先記錄符合的物件,更新完後對記錄的物件進行刪除。(意思是不與資料庫進行同步更新,僅更新當前的session記錄)
# 方法一 session.query(User).filter(User.name == 'mrlizi').update({'name': '李白'}) # 方法二 user = session.query(User).filter(User.name == '李白').first() user.name = '鎧' # 操作方式 result = session.query(User).filter(User.name == '虞姬').update({User.name: '孫尚香'}, synchronize_session='fetch') # 提交 session.commit() 複製程式碼
刪
刪除的話,無非就是 查詢
到目標記錄,然後進行刪除。
# 使用查詢語句,filter是where條件,最後呼叫delete()進行刪除記錄: session.query(User).filter_by(name="鎧").delete() session.commit() 複製程式碼
關聯表查詢
MySQL
作為關係型資料庫,可以通過設定外來鍵來進行多個表互相關聯查詢。相應的, SQLAlchemy
也提供了物件之間的一對一、一對多、多對多關聯功能。
一對多
在 SQLAlchemy
的一對多關係中,使用 ForeignKey()
來表示表的外來鍵, relationship()
表示表與表之間關聯的屬性。
def one_to_many(): # 定義user類 class User(Base): # 表名 __tablename__ = "user" # 表的結構 # 設定id為主鍵 並自增長 id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) # 定義使用者關注的公眾號屬性,指明兩者的關係 account = relationship('Account', back_populates="user") class Account(Base): __tablename__ = 'account' id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) # 設定外來鍵關聯到user表的: user_id = Column(BIGINT, ForeignKey('user.id')) # 定義 Account 的 user 屬性,指明兩者關係 user = relationship("User", back_populates="account") # 清空資料庫並重新初始化 drop_db() init_db() mrlizi = User(name='mrlizi') mrlizi.account = [ Account(name='攻城獅峽谷'), Account(name='zone7') ] session.add(mrlizi) result = session.query(User).filter(User.name == 'mrlizi').one() for item in result.account: print(item.name) result = session.query(Account).filter(Account.name == '攻城獅峽谷').one() print(result.user.name) session.commit() one_to_many() 複製程式碼
上面程式碼的實現過程:
user user account
一對一
一對一其實就是兩個表互相關聯,我們只需要在 一對多 關係基礎上的父表中使用 uselist
引數來表示。實現程式碼如下:
def one_to_one(): # 定義user類 class User(Base): __tablename__ = "user" id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) account = relationship('Account', uselist=False, back_populates="user") # 公眾號類 class Account(Base): __tablename__ = 'account' id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) # 設定外來鍵關聯到user表的: user_id = Column(BIGINT, ForeignKey('user.id')) # 定義 Account 的 user 屬性,指明兩者關係 user = relationship("User", back_populates="account") # 清空資料庫並重新初始化 drop_db() init_db() # 新增記錄 user = User(name='子非魚') user.account = Account(name='攻城獅峽谷') session.add(user) session.commit() # 查詢 result = session.query(User).filter(User.name == '子非魚').one() print(result.account.name) # 輸出: # 攻城獅峽谷 one_to_one() 複製程式碼
多對多
多對多是通過兩個表之間增加一個關聯的表來實現,這個關聯表使用 MetaData
物件來與兩個表關聯,並用 ForeignKey
引數指定連結來定位到兩個不同的表,兩個不同的表則在 relationship()
方法中通過 secondary
引數來指定關聯表。
def many_to_many(): # 關聯表 association_table = Table('association', Base.metadata, Column('user_id', BIGINT, ForeignKey('user.id')), Column('account_id', BIGINT, ForeignKey('account.id')) ) class User(Base): __tablename__ = "user" id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) accounts = relationship('Account', secondary=association_table, back_populates="users") class Account(Base): __tablename__ = 'account' id = Column(BIGINT, primary_key=True, autoincrement=True) name = Column(String(20)) users = relationship("User", secondary=association_table, back_populates="accounts") # 清空資料庫並重新初始化 drop_db() init_db() # 建立記錄 user1 = User(name='子非魚') user2 = User(name='zone') user3 = User(name='mrlizi') account1 = Account(name='攻城獅峽谷') account2 = Account(name='zone7') # 關聯記錄 user1.accounts = [account1] user2.accounts = [account1, account2] user3.accounts = [account2] # 新增並儲存 session.add(user1) session.add(user2) session.add(user3) session.commit() # 雙向查詢 result1 = session.query(User).filter(User.name == 'zone').one() for item in result1.accounts: print(item.name) result2 = session.query(Account).filter(Account.name == '攻城獅峽谷').one() for item in result2.users: print(item.name) many_to_many() 複製程式碼
總結
MySQL作為主流的資料庫之一,我們不一定說要多深入去研究它的使用,但起碼的瞭解還是要有的。而且python中使用MySQL還是挺簡單的,程式碼敲著敲著就會了。