- 问题
DatabaseError: (cx_Oracle.DatabaseError) ORA-01000: maximum open cursors exceeded
- 原因(book/document/source code)
result.py
def fetchone(self): | |
"""Fetch one row, just like DB-API ``cursor.fetchone()``. | |
After all rows have been exhausted, the underlying DBAPI | |
cursor resource is released, and the object may be safely | |
discarded. | |
Calls to :meth:`.ResultProxy.fetchone` after all rows have | |
been exhausted will return ``None``. | |
After the :meth:`.ResultProxy.close` method is | |
called, the method will raise :class:`.ResourceClosedError`. | |
.. versionchanged:: 1.0.0 - Added "soft close" behavior which | |
allows the result to be used in an "exhausted" state prior to | |
calling the :meth:`.ResultProxy.close` method. | |
""" | |
try: | |
row = self._fetchone_impl() | |
if row is not None: | |
return self.process_rows([row])[0] | |
else: | |
self._soft_close() | |
return None | |
except BaseException as e: | |
self.connection._handle_dbapi_exception( | |
e, None, None, | |
self.cursor, self.context) |
query.py
def first(self): | |
"""Return the first result of this ``Query`` or | |
None if the result doesn't contain any row. | |
first() applies a limit of one within the generated SQL, so that | |
only one primary entity row is generated on the server side | |
(note this may consist of multiple result rows if join-loaded | |
collections are present). | |
Calling :meth:`.Query.first` results in an execution of the underlying query. | |
.. seealso:: | |
:meth:`.Query.one` | |
:meth:`.Query.one_or_none` | |
""" | |
if self._statement is not None: | |
ret = list(self)[0:1] | |
else: | |
ret = list(self[0:1]) | |
if len(ret) > 0: | |
return ret[0] | |
else: | |
return None |
- 验证测试 fetchone 和 first 方法区别:
def test_cursor(): | |
""" | |
first(): Returns the first record if there is one and closes the connection. | |
fetchone(): Returns one row, and leaves the cursor open for you to make additional fetch calls. | |
scalar(): Returns a single value if a query results in a single record with one column. | |
""" | |
# 测试 fetchone (), 当我们获取到 execute_1 对象时,可以重复使用该对象的 fetchone () 方法去获取结果(每次获取的结果不同) | |
# 此时 cursor 会一直存在,第一次调用 fetchone () 方法时 cursor 在第一行,返回第一个结果, | |
# 再次调用方法时 cursor 会移动到第二行,以此类推,cursor 一直向最后一行移动,直到取不到行数时,cursor 才会释放 | |
sql = text("SELECT * FROM STUDENT") # 该表返回多条学生记录 | |
execute_1 = engine.execute(sql) | |
for item in range(30): | |
result_1 = execute_1.fetchone() | |
print(result_1) | |
# 测试 first (),当获取到 execute_2 对象时,仅可以对该对象执行一次 first () 方法,重复执行 first () 方法会抛异常 | |
# 异常信息:ResourceClosedError: This result object is closed. | |
# 说明 first () 方法在获取一次结果后该连接已经关闭,不再提供持续的连接 | |
sql = text("SELECT * FROM STUDENT") | |
execute_2 = engine.execute(sql) | |
for item in range(30): | |
result_2 = execute_2.first() | |
print(result_2) |
- 解决方式:
避免使用 fetchone,将所有 sql 查询使用的 fetchone () 方法替换为 first () 方法
参考:
同样的问题:https://blog.csdn.net/heminhao/article/details/73433711
截图 1 来自《Essential SQLAlchemy》第二章,下载地址:http://vdisk.weibo.com/s/ugG0f_qkHRVY4
截图 2 来自 SQLAlchemy 1.3 Documentation,
参考:https://docs.sqlalchemy.org/en/latest/core/connections.html#basic-usage
4.oracle 查询相关配置信息 sql,有点乱,记录一下
--- 查询 oracle db 版本信息 | |
select * from v$version where rownum=1; | |
--- 查询 oracle 设置的进程参数 | |
select name,value from v$parameter where name='processes'; | |
--- 查询当前进程数量或详细进程信息 | |
select count(*) from v$process; | |
select * from v$process; | |
--- 查询游标 cursors 信息 | |
select sum(a.value) total_cur, | |
avg(a.value) avg_cur, | |
max(a.value) max_cur, | |
s.username, | |
s.machine | |
from v$sesstat a, v$statname b, v$session s | |
where a.statistic# = b.statistic# | |
and s.sid=a.sid | |
and b.name = 'opened cursors current' | |
group by s.username, s.machine | |
order by 1 desc; | |
--- 查看 oracle 当前的连接数 | |
select * from v$session where username is not null; | |
--- 查看不同用户的连接数 | |
select username,count(username) from v$session where username is not null group by username; | |
--- 总连接数 | |
select count(*) from v$session; | |
--- 并发连接数 | |
select count(*) from v$session where status='ACTIVE'; | |
--- 游标设置参数 | |
SELECT value FROM v$parameter WHERE name = 'open_cursors'; | |
select q.sql_text from v$open_cursor o,v$sql q where q.hash_value=o.hash_value and o.sid=217; | |
select count(*) from v$open_cursor where user_name='STAPUSER'; | |
select count(*) from v$open_cursor; | |
--- 通过 session 查询开启的游标 | |
select a.value, | |
s.username, | |
s.sid, | |
s.serial# | |
from v$sesstat a, v$statname b, v$session s | |
where a.statistic# = b.statistic# | |
and s.sid=a.sid | |
and b.name = 'opened cursors current'; | |
select a.value, s.username, s.sid, s.serial# | |
from v$sesstat a, | |
v$statname b, | |
v$session s | |
where a.statistic# = b.statistic# | |
and s.sid = a.sid | |
and b.name = 'opened cursors current' | |
and s.username is not null | |
and a.value>10; | |
select * from v$sesstat where ROWNUM<10; | |
---V_$SESSION 表列数 | |
select count(column_name) from dba_tab_columns where table_name='V_$SESSION'; | |
select sid, sql_text, USER_NAME | |
from v$open_cursor | |
where sid in ('388') and user_name='STAPUSER'; | |
select sid , | |
sql_text, | |
count(*) as "OPEN CURSORS", | |
USER_NAME | |
from v$open_cursor | |
where sid in ('388') | |
group by count(*); | |
SELECT max(a.value) as highest_open_cur, | |
p.value as max_open_cur | |
FROM v$sesstat a, | |
v$statname b, | |
v$parameter p | |
WHERE a.statistic# = b.statistic# | |
and b.name = 'opened cursors current' | |
and p.name = 'open_cursors' | |
group by p.value; |
https://stackoverflow.com/questions/5669878/when-to-close-cursors-using-mysqldb