mysql 连接池释放连接_mysql连接池, 连接的释放, 连接的回收, 连接释放机制

本文探讨了MySQL数据库连接池的管理,通过示例展示了如何在Python中使用`sqlalchemy`创建连接池。当连接耗尽时,线程不会阻塞,而是立即报告错误。在某些情况下,如网络中断,连接可以自动回收。文中还提到,即使不显式关闭连接,连接池也能回收资源。最后,分析了DBUtils库中PooledDB的源码,揭示了连接池可能导致所有线程阻塞的原因,并给出了模拟示例代码。
摘要由CSDN通过智能技术生成

#!/bin/python

from sqlalchemy.pool import QueuePool

import threading

import MySQLdb

import time

def creator():

c = MySQLdb.connect(host="192.168.41.76", db="test", user="root", passwd="root", port=3306)

return c

pool = QueuePool(creator, pool_size=2, max_overflow=0, timeout=1)

class Demo(object):

def proc(self):

ident = threading.currentThread().getName()

conn = pool.connect()

print ident, id(conn), id(conn.connection)

cur = conn.cursor()

cur.execute("select * from t_user")

res = cur.fetchall()

# conn.close()

time.sleep(2)

def __del__(self):

print "__del__"

def target():

while True:

try:

ident = threading.currentThread().getName()

d = Demo()

d.proc()

# conn = pool.connect()

# print ident, id(conn)

# cur = conn.cursor()

# cur.execute("select * from t_user")

# res = cur.fetchall()

# # conn.close()

# time.sleep(2)

except Exception,e:

print ident, e

def main():

for i in range(3):

t = threading.Thread(target=target)

t.setDaemon(True)

t.start()

while True:

try:

time.sleep(10)

except:

import sys,traceback

print traceback.format_exc()

sys.exit(1)

if __name__ == "__main__":

main()

连接池sqlalchemy使用模拟引发下面问题:

线程数小于连接数, 当连接数耗光, 不至于所有的线程都堵死在获取连接上, 而是立马报错连接不够

连接获取之后, 如果打开防火墙屏蔽ip, 会阻塞在execute上面, 这个是mysql的特性

这种情况下, 连接是可以自动释放回收的, 即使不写conn.close()

如果屏蔽Demo类的使用, 打开下面注释, 不显示写conn.close() 则连接无法释放回收

下面代码解释自动回收conn

# coding=gbk

#!/bin/python

import weakref

import threading

import Queue

import time

import MySQLdb

class ObjFairy(object):

"""封装相关对象, 方便回收的时候操作

"""

def __init__(self, _pool, _echo):

self.pool = _pool

self.echo = _echo

def callback(ref):

"""弱引用在gc的时候callback, ref为回收对象

"""

print "gc callback, do clean", ref

class Pool(object):

"""xx池(比如sqlalchemy的QueuePool)

"""

@staticmethod

def checkout():

fairy = ObjFairy(None, None)

current = weakref.ref(fairy, callback)

return current

# =========测试========== #

class DemoBusi(object):

"""业务类

"""

def proc(self):

current = Pool.checkout() # 取出某可重复使用对象, 无需显示清理

def target():

while True:

demo = DemoBusi() # 模拟业务handler, 一次请求过来, new BusiHandler

demo.proc()

# current = Pool.checkout(None)

time.sleep(1)

def main():

for i in range(3):

t = threading.Thread(target=target)

t.setDaemon(True)

t.start()

while True:

time.sleep(2 * 60)

break

if __name__ == "__main__":

main()

sqlalchemy连接池源码

@classmethod

def checkout(cls, pool):

rec = pool._do_get()

try:

dbapi_connection = rec.get_connection()

except:

with util.safe_reraise():

rec.checkin()

echo = pool._should_log_debug()

fairy = _ConnectionFairy(dbapi_connection, rec, echo)

rec.fairy_ref = weakref.ref(

fairy,

lambda ref: _finalize_fairy and

_finalize_fairy(

dbapi_connection,

rec, pool, ref, echo)

)

_refs.add(rec)

if echo:

pool.logger.debug("Connection %r checked out from pool",

dbapi_connection)

return fairy

跟踪DBUtils.py里面的PooledDB源码发现, 3个线程2个连接会导致所有的线程阻塞,是因为在建立连接或者获取连接的时候阻塞, 导致重入锁不释放(RLock)

下面模拟代码

#coding=utf8

import threading

from threading import Condition

import time

class Obj(object):

def __init__(self):

self.bt = time.time()

self.cond = Condition()

obj = Obj()

class Demo(object):

def __init__(self):

pass

def proc(self):

et = time.time()

if et - obj.bt > 6:

print "block(%s)" % threading.currentThread().getName()

raw_input()

time.sleep(1)

print "proc(%s)" % threading.currentThread().getName()

def f():

while 1:

print "----acquire(%s)" % threading.currentThread().getName()

obj.cond.acquire()

Demo().proc()

obj.cond.release()

time.sleep(0.1)

print "-----release(%s)" % threading.currentThread().getName()

def main():

for i in range(3):

t = threading.Thread(target=f)

t.setDaemon(True)

time.sleep(2)

t.start()

time.sleep(10000)

if __name__ == "__main__":

main()

这个是源码

self._condition.acquire()

try:

while (self._maxconnections

and self._connections >= self._maxconnections):

self._condition.wait()

# connection limit not reached, get a dedicated connection

try: # first try to get it from the idle cache

con = self._idle_cache.pop(0)

except IndexError: # else get a fresh connection

con = self.steady_connection()

else:

con._ping_check() # check connection

con = PooledDedicatedDBConnection(self, con)

self._connections += 1

finally:

self._condition.release()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值