Python與數據庫的新人手冊 -- MySQL

Python支持的數據庫有不少,MySQL做爲主流數據庫之一,咱們不妨瞭解下它們之間的操做交互。python

Python操做MySQL的庫有三個,python-MySQL(MySQLdb)PyMySQLSQLAlchemymysql

  • python2中通常使用python-MySQL(MySQLdb),核心由C語言打造,性能最好,缺點是安裝複雜,已中止更新,不支持python3。
  • PyMySQL爲代替它而生,純python打造,安裝方便,支持python3。
  • SQLAlchemy是一個ORM框架,ORM框架的做用就是把數據庫表的一行記錄與一個對象互相作自動轉換,它自己沒法操做數據庫,而是要依賴於MySQLdb、PyMySQL等第三方庫來完成,目前SQLAlchemy在Web編程領域應用普遍。

本文將主要拿SQLAlchemy來進行了解學習。sql

安裝工具

首先安裝基本的數據庫驅動pymysql數據庫

pip3 install pymysql
複製代碼

而後安裝ORM框架SQLAlchemy編程

pip3 install sqlalchemy
複製代碼

平常工做中,若是不想每次經過命令行來查看數據的話。推薦安裝Navicat for MySQL,經過這個圖形化工具可以方便快捷地操做數據庫,實時查詢數據。session

初始化數據庫

安裝好必要工具後,咱們開始嘗試建立個用戶數據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()
複製代碼

結果:

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 不一樣步更新當前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也提供了對象之間的一對1、一對多、多對多關聯功能。

一對多

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仍是挺簡單的,代碼敲着敲着就會了。

相關文章
相關標籤/搜索