Python Flask SQLALchemy基础知识

一、介绍

SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
快速安装
pip3 install sqlalchemy

  

组成部分:
  • Engine,框架的引擎
  • Connection Pooling ,数据库连接池
  • Dialect,选择连接数据库的DB API种类
  • Schema/Types,架构和类型
  • SQL Exprression Language,SQL表达式语言
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
MySQL-Python
    mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>

pymysql
    mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]

MySQL-Connector
    mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>

cx_Oracle
    oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]

更多:http://docs.sqlalchemy.org/en/latest/dialects/index.html

二、使用 

1. 执行原生SQL语句
import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine

engine = create_engine(
    "mysql+pymysql://root:123@127.0.0.1:3306/t1?charset=utf8",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)—— -1 永不回收
)


def task(arg):
    conn = engine.raw_connection()
    cursor = conn.cursor()
    cursor.execute(
        "select * from t1"
    )
    result = cursor.fetchall()
    cursor.close()
    conn.close()


for i in range(20):
    t = threading.Thread(target=task, args=(i,))
    t.start()
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine

engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=0, pool_size=5)


def task(arg):
    conn = engine.contextual_connect()
    with conn:
        cur = conn.execute(
            "select * from t1"
        )
        result = cur.fetchall()
        print(result)


for i in range(20):
    t = threading.Thread(target=task, args=(i,))
    t.start()
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine
from sqlalchemy.engine.result import ResultProxy
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=0, pool_size=5)


def task(arg):
    cur = engine.execute("select * from t1")
    result = cur.fetchall()
    cur.close()
    print(result)


for i in range(20):
    t = threading.Thread(target=task, args=(i,))
    t.start()
注意: 查看连接 show status like 'Threads%';
2. ORM
a. 创建数据库表
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:supery
 4 
 5 import datetime
 6 from sqlalchemy import create_engine
 7 from sqlalchemy.ext.declarative import declarative_base
 8 from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
 9 
10 Base = declarative_base()
11 
12 
13 class Users(Base):
14     __tablename__ = 'users'
15 
16     id = Column(Integer, primary_key=True)          # 主键
17     name = Column(String(32), index=True, nullable=False)   # 添加索引,不能为空
18     email = Column(String(32), unique=True)
19     ctime = Column(DateTime, default=datetime.datetime.now)
20     # datetime.datetime.now不能加括号,加括号默认值就是第一次插入时间
21     # extra = Column(Text, nullable=True)
22 
23     __table_args__ = (
24         UniqueConstraint('id', 'name', name='uix_id_name'),    # 联合唯一索引
25         Index('ix_id_name', 'name', 'email'),                   # 普通索引
26     )
27     _table_arhs__ = {
28         'mysql_engine': 'InnoDb',                   # 设置表引擎
29         'mysql_charset': 'utf8'                     # 设置表字符集
30     }
31 
32 
33 def init_db():
34     """
35     根据类创建数据库表
36     :return:
37     """
38     engine = create_engine(
39         "mysql+pymysql://root:123.com@10.0.0.10:3306/day123?charset=utf8",
40         max_overflow=0,  # 超过连接池大小外最多创建的连接
41         pool_size=5,  # 连接池大小
42         pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
43         pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)——永不回收-1
44     )
45 
46     Base.metadata.create_all(engine)
47 
48 
49 def drop_db():
50     """
51     根据类删除数据库表
52     :return:
53     """
54     engine = create_engine(
55         "mysql+pymysql://root:123.com@10.0.0.10:3306/day123?charset=utf8",
56         max_overflow=0,  # 超过连接池大小外最多创建的连接
57         pool_size=5,  # 连接池大小
58         pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
59         pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)——永不回收-1
60     )
61 
62     Base.metadata.drop_all(engine)
63 
64 
65 if __name__ == '__main__':
66     # 初始化数据库,先删除再创建
67     drop_db()
68     init_db()
创建单表 
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 import datetime
  4 from sqlalchemy import create_engine
  5 from sqlalchemy.ext.declarative import declarative_base
  6 from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
  7 from sqlalchemy.orm import relationship
  8 
  9 Base = declarative_base()
 10 
 11 
 12 # ##################### 单表示例 #########################
 13 class Users(Base):
 14     __tablename__ = 'users'
 15 
 16     id = Column(Integer, primary_key=True)
 17     name = Column(String(32), index=True)
 18     age = Column(Integer, default=18)
 19     email = Column(String(32), unique=True)
 20     ctime = Column(DateTime, default=datetime.datetime.now)
 21     extra = Column(Text, nullable=True)
 22 
 23     __table_args__ = (
 24         # UniqueConstraint('id', 'name', name='uix_id_name'),
 25         # Index('ix_id_name', 'name', 'extra'),
 26     )
 27 
 28 
 29 class Hosts(Base):
 30     __tablename__ = 'hosts'
 31 
 32     id = Column(Integer, primary_key=True)
 33     name = Column(String(32), index=True)
 34     ctime = Column(DateTime, default=datetime.datetime.now)
 35 
 36 
 37 # ##################### 一对多示例 #########################
 38 class Hobby(Base):
 39     __tablename__ = 'hobby'
 40     id = Column(Integer, primary_key=True)
 41     caption = Column(String(50), default='篮球')
 42 
 43 
 44 class Person(Base):
 45     __tablename__ = 'person'
 46     nid = Column(Integer, primary_key=True)
 47     name = Column(String(32), index=True, nullable=True)
 48     hobby_id = Column(Integer, ForeignKey("hobby.id"))
 49 
 50     # 与生成表结构无关,仅用于查询方便
 51     hobby = relationship("Hobby", backref='pers')
 52 
 53 
 54 # ##################### 多对多示例 #########################
 55 
 56 class Server2Group(Base):
 57     __tablename__ = 'server2group'
 58     id = Column(Integer, primary_key=True, autoincrement=True)
 59     server_id = Column(Integer, ForeignKey('server.id'))
 60     group_id = Column(Integer, ForeignKey('group.id'))
 61 
 62 
 63 class Group(Base):
 64     __tablename__ = 'group'
 65     id = Column(Integer, primary_key=True)
 66     name = Column(String(64), unique=True, nullable=False)
 67 
 68     # 与生成表结构无关,仅用于查询方便
 69     servers = relationship('Server', secondary='server2group', backref='groups')
 70 
 71 
 72 class Server(Base):
 73     __tablename__ = 'server'
 74 
 75     id = Column(Integer, primary_key=True, autoincrement=True)
 76     hostname = Column(String(64), unique=True, nullable=False)
 77 
 78 
 79 def init_db():
 80     """
 81     根据类创建数据库表
 82     :return:
 83     """
 84     engine = create_engine(
 85         "mysql+pymysql://root:123@127.0.0.1:3306/s6?charset=utf8",
 86         max_overflow=0,  # 超过连接池大小外最多创建的连接
 87         pool_size=5,  # 连接池大小
 88         pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
 89         pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
 90     )
 91 
 92     Base.metadata.create_all(engine)
 93 
 94 
 95 def drop_db():
 96     """
 97     根据类删除数据库表
 98     :return:
 99     """
100     engine = create_engine(
101         "mysql+pymysql://root:123@127.0.0.1:3306/s6?charset=utf8",
102         max_overflow=0,  # 超过连接池大小外最多创建的连接
103         pool_size=5,  # 连接池大小
104         pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
105         pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
106     )
107 
108     Base.metadata.drop_all(engine)
109 
110 
111 if __name__ == '__main__':
112     drop_db()
113     init_db()
创建多个表(包含FK,M2M关系)
b. 操作数据库表
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from sqlalchemy.orm import sessionmaker
 4 from sqlalchemy import create_engine
 5 from models import Users
 6 
 7 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6", max_overflow=0, pool_size=5)
 8 Session = sessionmaker(bind=engine)
 9 
10 # 每次执行数据库操作时,都需要创建一个session
11 session = Session()
12 
13 # ############# 执行ORM操作 #############
14 obj1 = Users(name="alex1")
15 session.add(obj1)
16 
17 # 提交事务
18 session.commit()
19 # 关闭session
20 session.close()
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 import threading
 5 
 6 from sqlalchemy.ext.declarative import declarative_base
 7 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
 8 from sqlalchemy.orm import sessionmaker, relationship
 9 from sqlalchemy import create_engine
10 from db import Users
11 
12 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6", max_overflow=0, pool_size=5)
13 Session = sessionmaker(bind=engine)
14 
15 
16 def task(arg):
17     session = Session()
18 
19     obj1 = Users(name="alex1")
20     session.add(obj1)
21 
22     session.commit()
23 
24 
25 for i in range(10):
26     t = threading.Thread(target=task, args=(i,))
27     t.start()
多线程执行示例
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 import threading
 5 
 6 from sqlalchemy.ext.declarative import declarative_base
 7 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
 8 from sqlalchemy.orm import sessionmaker, relationship
 9 from sqlalchemy import create_engine
10 from sqlalchemy.sql import text
11 
12 from db import Users, Hosts
13 
14 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6", max_overflow=0, pool_size=5)
15 Session = sessionmaker(bind=engine)
16 
17 session = Session()
18 
19 # ################ 添加 ################
20 """
21 obj1 = Users(name="wupeiqi")
22 session.add(obj1)
23 
24 session.add_all([
25     Users(name="wupeiqi"),
26     Users(name="alex"),
27     Hosts(name="c1.com"),
28 ])
29 session.commit()
30 """
31 
32 # ################ 删除 ################
33 """
34 session.query(Users).filter(Users.id > 2).delete()
35 session.commit()
36 """
37 # ################ 修改 ################
38 """
39 session.query(Users).filter(Users.id > 0).update({"name" : "099"})
40 session.query(Users).filter(Users.id > 0).update({Users.name: Users.name + "099"}, synchronize_session=False)
41 session.query(Users).filter(Users.id > 0).update({"age": Users.age + 1}, synchronize_session="evaluate")
42 session.commit()
43 """
44 # ################ 查询 ################
45 """
46 r1 = session.query(Users).all()
47 r2 = session.query(Users.name.label('xx'), Users.age).all()
48 r3 = session.query(Users).filter(Users.name == "alex").all()
49 r4 = session.query(Users).filter_by(name='alex').all()
50 r5 = session.query(Users).filter_by(name='alex').first()
51 r6 = session.query(Users).filter(text("id<:value and name=:name")).params(value=224, name='fred').order_by(Users.id).all()
52 r7 = session.query(Users).from_statement(text("SELECT * FROM users where name=:name")).params(name='ed').all()
53 """
54 
55 
56 session.close()
基本的增删改查操作
 1 # 条件
 2 ret = session.query(Users).filter_by(name='alex').all()
 3 ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()
 4 ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all()
 5 ret = session.query(Users).filter(Users.id.in_([1,3,4])).all()
 6 ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all()
 7 ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all()
 8 from sqlalchemy import and_, or_
 9 ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all()
10 ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all()
11 ret = session.query(Users).filter(
12     or_(
13         Users.id < 2,
14         and_(Users.name == 'eric', Users.id > 3),
15         Users.extra != ""
16     )).all()
17 
18 
19 # 通配符
20 ret = session.query(Users).filter(Users.name.like('e%')).all()
21 ret = session.query(Users).filter(~Users.name.like('e%')).all()
22 
23 # 限制
24 ret = session.query(Users)[1:2]
25 
26 # 排序
27 ret = session.query(Users).order_by(Users.name.desc()).all()
28 ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all()
29 
30 # 分组
31 from sqlalchemy.sql import func
32 
33 ret = session.query(Users).group_by(Users.extra).all()
34 ret = session.query(
35     func.max(Users.id),
36     func.sum(Users.id),
37     func.min(Users.id)).group_by(Users.name).all()
38 
39 ret = session.query(
40     func.max(Users.id),
41     func.sum(Users.id),
42     func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all()
43 
44 # 连表
45 
46 ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all()
47 
48 ret = session.query(Person).join(Favor).all()
49 
50 ret = session.query(Person).join(Favor, isouter=True).all()
51 
52 
53 # 组合
54 q1 = session.query(Users.name).filter(Users.id > 2)
55 q2 = session.query(Favor.caption).filter(Favor.nid < 2)
56 ret = q1.union(q2).all()
57 
58 q1 = session.query(Users.name).filter(Users.id > 2)
59 q2 = session.query(Favor.caption).filter(Favor.nid < 2)
60 ret = q1.union_all(q2).all()
常用操作
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 import threading
 5 
 6 from sqlalchemy.ext.declarative import declarative_base
 7 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
 8 from sqlalchemy.orm import sessionmaker, relationship
 9 from sqlalchemy import create_engine
10 from sqlalchemy.sql import text
11 from sqlalchemy.engine.result import ResultProxy
12 from db import Users, Hosts
13 
14 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6", max_overflow=0, pool_size=5)
15 Session = sessionmaker(bind=engine)
16 
17 session = Session()
18 
19 # 查询
20 # cursor = session.execute('select * from users')
21 # result = cursor.fetchall()
22 
23 # 添加
24 cursor = session.execute('insert into users(name) values(:value)',params={"value":'wupeiqi'})
25 session.commit()
26 print(cursor.lastrowid)
27 
28 session.close()
原生SQL语句
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 import threading
 5 
 6 from sqlalchemy.ext.declarative import declarative_base
 7 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
 8 from sqlalchemy.orm import sessionmaker, relationship
 9 from sqlalchemy import create_engine
10 from sqlalchemy.sql import text
11 from sqlalchemy.engine.result import ResultProxy
12 from db import Users, Hosts, Hobby, Person
13 
14 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6?charset=utf8", max_overflow=0, pool_size=5)
15 Session = sessionmaker(bind=engine)
16 session = Session()
17 # 添加
18 """
19 session.add_all([
20     Hobby(caption='乒乓球'),
21     Hobby(caption='羽毛球'),
22     Person(name='张三', hobby_id=3),
23     Person(name='李四', hobby_id=4),
24 ])
25 
26 person = Person(name='张九', hobby=Hobby(caption='姑娘'))
27 session.add(person)
28 
29 hb = Hobby(caption='人妖')
30 hb.pers = [Person(name='文飞'), Person(name='博雅')]
31 session.add(hb)
32 
33 session.commit()
34 """
35 
36 # 使用relationship正向查询
37 """
38 v = session.query(Person).first()
39 print(v.name)
40 print(v.hobby.caption)
41 """
42 
43 # 使用relationship反向查询
44 """
45 v = session.query(Hobby).first()
46 print(v.caption)
47 print(v.pers)
48 """
49 
50 session.close()
基于relationship操作ForeignKey
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 import threading
 5 
 6 from sqlalchemy.ext.declarative import declarative_base
 7 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
 8 from sqlalchemy.orm import sessionmaker, relationship
 9 from sqlalchemy import create_engine
10 from sqlalchemy.sql import text
11 from sqlalchemy.engine.result import ResultProxy
12 from db import Users, Hosts, Hobby, Person, Group, Server, Server2Group
13 
14 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6?charset=utf8", max_overflow=0, pool_size=5)
15 Session = sessionmaker(bind=engine)
16 session = Session()
17 # 添加
18 """
19 session.add_all([
20     Server(hostname='c1.com'),
21     Server(hostname='c2.com'),
22     Group(name='A组'),
23     Group(name='B组'),
24 ])
25 session.commit()
26 
27 s2g = Server2Group(server_id=1, group_id=1)
28 session.add(s2g)
29 session.commit()
30 
31 
32 gp = Group(name='C组')
33 gp.servers = [Server(hostname='c3.com'),Server(hostname='c4.com')]
34 session.add(gp)
35 session.commit()
36 
37 
38 ser = Server(hostname='c6.com')
39 ser.groups = [Group(name='F组'),Group(name='G组')]
40 session.add(ser)
41 session.commit()
42 """
43 
44 
45 # 使用relationship正向查询
46 """
47 v = session.query(Group).first()
48 print(v.name)
49 print(v.servers)
50 """
51 
52 # 使用relationship反向查询
53 """
54 v = session.query(Server).first()
55 print(v.hostname)
56 print(v.groups)
57 """
58 
59 
60 session.close()
基于relationship操作m2m
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import time
 4 import threading
 5 
 6 from sqlalchemy.ext.declarative import declarative_base
 7 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
 8 from sqlalchemy.orm import sessionmaker, relationship
 9 from sqlalchemy import create_engine
10 from sqlalchemy.sql import text, func
11 from sqlalchemy.engine.result import ResultProxy
12 from db import Users, Hosts, Hobby, Person, Group, Server, Server2Group
13 
14 engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6?charset=utf8", max_overflow=0, pool_size=5)
15 Session = sessionmaker(bind=engine)
16 session = Session()
17 
18 # 关联子查询
19 subqry = session.query(func.count(Server.id).label("sid")).filter(Server.id == Group.id).correlate(Group).as_scalar()
20 result = session.query(Group.name, subqry)
21 """
22 SELECT `group`.name AS group_name, (SELECT count(server.id) AS sid
23 FROM server
24 WHERE server.id = `group`.id) AS anon_1
25 FROM `group`
26 """
27 
28 
29 # 原生SQL
30 """
31 # 查询
32 cursor = session.execute('select * from users')
33 result = cursor.fetchall()
34 
35 # 添加
36 cursor = session.execute('insert into users(name) values(:value)',params={"value":'wupeiqi'})
37 session.commit()
38 print(cursor.lastrowid)
39 """
40 
41 session.close()
其他
PS:注意
1. 默认不能修改表的字段,如果修改需要用的到sqlalchemy的一个组件进行修改字段	
2. pool_recycle=-1 永远不回收
3. ctime = Column(DateTime, default=datetime.datetime.now)   
    datetime.datetime.now不能加括号,加括号默认值就是第一次插入时间

  

  

  

posted @ 2018-01-11 15:19  Pythia丶陌乐  阅读(12179)  评论(0编辑  收藏  举报