添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

python SQLAlchemy数据库连接池使用问题

在使用SQLAlchemy做MySQl数据库访问时,遇到了连接池的问题,导致MySQL连接达到最大可允许连接上限,连接拒绝情况。说一下我的应用情况,单线程访问数据库,在单个线程中会涉及到多次数据库操作,并且有个别操作非常耗时,为了避免数据库常连接问题,这里我们采取的方案是 每次重新连接数据库

遇到的问题:

  1. 其实单线程的应用没有必要使用数据库连接池

  2. 原有代码在每次访问时都会走一遍以下的代码逻辑,导致建立多个连接池

    1
    2
    3
    4
    5
    engine = create_engine(self.conn_str, echo=False, pool_recycle=7200, pool_size=10)
    Session = sessionmaker()
    Session.configure(bind=engine, autocommit=True)
    session = Session()
    self.session = session

    解决方案:

  3. 针对第一个问题,需要去掉连接池,改为直连数据库, 参考此文章

    1
    engine = create_engine(self.conn_str, echo=False, poolclass=NullPool)
  4. 针对第二个问题,应该修改为针对单个线程,共用一个engine, 对于每次数据库访问仅实例化不同的session即可。

分析过程:

针对应用场景,编写了以下的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#! encoding=utf-8
# 导入:
from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.pool import NullPool
import time


Base = declarative_base()

# 定义User对象:
class User(Base):

def __init__(self, id, name):
self.id = id
self.name = name
# 表的名字:
__tablename__ = 'user'

# 表的结构:
id = Column(String(20), primary_key=True)
name = Column(String(20))


# 初始化数据库连接:
engine = create_engine("mysql://root:[email protected]:3306/local_test", echo=False, pool_recycle=7200)
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine, autocommit=True)

print 'add record'
# 创建session对象:
session = DBSession()
session.begin(subtransactions=True)
# 创建新User对象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到数据库:
session.commit()
# 关闭session:
session.close()
time.sleep(10)

# # 初始化数据库连接:
# engine = create_engine("mysql://root:[email protected]:3306/local_test", echo=False, pool_recycle=7200)
# # 创建DBSession类型:
# DBSession = sessionmaker(bind=engine, autocommit=True)
print 'query record'
# 创建Session:
session = DBSession()
session.begin(subtransactions=True)
# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
user = session.query(User).filter(User.id=='5').one()
# 打印类型和对象的name属性:
print 'type:', type(user)
print 'name:', user.name
# session.commit()
# 关闭Session:
session.close()
time.sleep(10)

# # 初始化数据库连接:
# engine = create_engine("mysql://root:[email protected]:3306/local_test", echo=False, pool_recycle=7200)
# # 创建DBSession类型:
# DBSession = sessionmaker(bind=engine, autocommit=True)
print 'delete record'
# 创建Session:
session = DBSession()
session.begin(subtransactions=True)
# delete操作
session.delete(new_user)
session.commit()
# 关闭Session:
session.close()
time.sleep(10)
说明:
  1. 如果将engine在每次执行操作前都进行初始化,则会导致数据库连接数为 3 ,而如果共用一个engine,则连接数为 1
    每次初始化engine
  2. 如果采用了数据库连接池,对于session.close并非真正将连接关闭,而仅仅是将连接重新交回连接池,session.commit()也会有此效果。
  3. 关于数据库连接池中的连接,默认情况下,连接个数为5;但是我看到的情况是,假设你只有一个数据库操作,真正的连接数为1;而如果你有10个操作,连接池中的连接才会有5个。

    也就是说,该连接池的并非在启动时已经实例化好了数据库连接,而是按需初始化。

查看资料印证了自己的想法:
连接池原理

如果这篇文章对您有所帮助,感谢支持!
艺超(yi_chao_jiang) 微信支付

微信支付

艺超(yi_chao_jiang) 支付宝

支付宝