Python支持的數據庫有很多,MySQL
作爲主流數據庫之一,我們不妨瞭解下它們之間的小故事
Python操作MySQL的庫有三個,python-MySQL(MySQLdb)
,PyMySQL
跟SQLAlchemy
。
- python2中一般使用
python-MySQL(MySQLdb)
,核心由C語言打造,性能最好,缺點是安裝複雜,已停止更新,不支持python3。 -
PyMySQL
爲代替它而生,純python打造,安裝方便,支持python3。 -
SQLAlchemy
是一個ORM框架,ORM框架的作用就是把數據庫表的一行記錄與一個對象互相做自動轉換,它本身無法操作數據庫,而是要依賴於MySQLdb、PyMySQL等第三方庫來完成,目前SQLAlchemy在Web編程領域應用廣泛。
本文將主要拿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 不同步更新當前sessionsynchronize_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,並添加關注的公衆號account
- 增加name爲mrlizi的
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還是挺簡單的,代碼敲着敲着就會了。