Python與資料庫的新人手冊 — MySQL

Mr李子發表於2019-01-23

Python支援的資料庫有很多,MySQL作為主流資料庫之一,我們不妨瞭解下它們之間的操作互動。

Python操作MySQL的庫有三個,python-MySQL(MySQLdb)PyMySQLSQLAlchemy

  • 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,通過這個圖形化工具能夠方便快捷地運算元據庫,實時查詢資料。

Python與資料庫的新人手冊 — MySQL

初始化資料庫

安裝好必要工具後,我們開始嘗試建立個使用者資料user表來。首先,使用SQLAlchemy連線資料庫並定義表結構初始化DBSession。

# 匯入SQLAlchemyfrom sqlalchemy import Column, BIGINT, String, create_enginefrom sqlalchemy.orm import sessionmakerfrom 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()複製程式碼

結果:

Python與資料庫的新人手冊 — MySQL

Sessionquery函式會返回一個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還是挺簡單的,程式碼敲著敲著就會了。

來源:https://juejin.im/post/5c47445fe51d4552122cdda1#comment

相關文章