Python mysql.connector.errors.InternalError: Unread result foundの根本的な解決

Python で mysql-connector-python を使用して、fetchone を行った時に起こるエラー

mysql.connector.errors.InternalError: Unread result found

についての根本的な解決策とその他の考えられる解決策について記載します。

 

エラーの意味

何故、このエラーが起きるのか?

原因は、fetchone() で1件データを取得しようとしているけど、結果が複数取ってこれる sql で、まだデータが残っているからダメだよ。という内容になります。

 

根本的な解決策

エラーの意味から、根本的な解決策としては次の方法が考えられます。

1.絶対に1件しか取れない sql を作成する。

2.そもそも指定する条件では1件だけしか登録されない仕組みを作る。

の2つが考えられます。

 

2に関しては、情報を登録する際の処理をしっかり考えて行うしかなく仕様によって変わるので言及はしません。

1に関して記載します。

絶対に1件しか取れない sql

例えば以下のような sql で実行するとした場合をベースに対策などを記載していきます。

con = mysql.connector.connect(host=xxxx,port=yyy,user=zzzz,passwd=****,database=dddd)
cursor_query = con.cursor()
cursor_query.execute("SELECT id, value FROM table WHERE value='text';")
row = cursor_query.fetchone()

確実に1件であるそのテーブルの PRIMARY KEY を指定

id が PRIMARY KEY の場合は、その id を指定できるのであればそれは確実です。

con = mysql.connector.connect(host=xxxx,port=yyy,user=zzzz,passwd=****,database=dddd)
cursor_query = con.cursor()
cursor_query.execute("SELECT id, value FROM table WHERE id='111111';")
row = cursor_query.fetchone()

limit 1 を指定

PRIMARY KEY 以外の条件を使いたい場合は以下の方法です。

本当は1件しかないはずだが、例外的に複数ある場合がある時は、limit 1 を指定します。

ORDER BY で並びを変えて必要な情報を取得するでもいいと思います。

con = mysql.connector.connect(host=xxxx,port=yyy,user=zzzz,passwd=****,database=dddd)
cursor_query = con.cursor()
cursor_query.execute("SELECT id, value FROM table WHERE value='text' LIMIT 1;")
row = cursor_query.fetchone()

その他の解決策

先に述べた sql だけでの対策以外では、次が考えられます。

A.fetchall() で取得して、Python の処理で必要な行のみ取得する。

B.cursor() のオプションを指定する。

 

A の場合は、fetchall() で複数取得して Python で1行だけ取得する処理を行えばよいです。

簡単に書くと以下です。

con = mysql.connector.connect(host=xxxx,port=yyy,user=zzzz,passwd=****,database=dddd)
cursor_query = con.cursor()
cursor_query.execute("SELECT id, value FROM table WHERE value='text';")
rows = cursor_query.fetchall()
row = None
if rows and len(rows) >= 1:
    row = rows[0]

B の場合については、注意点もあるためサンプルと注意点を次で記載します。

 

con.cursor(buffered=True) を使用するサンプルと注意点

cursor に buffered=True オプションを指定することによって、クエリ実行直後にまとめてメモリ上に結果を取得するため、複数取ってくる場合の fetchone() でもエラーを回避できます。

 

サンプル

con.cursor(buffered=True) を作ったサンプルコードは以下になります。

一番簡単に何も考えずに解決できると思いますが、注意点もあります。

con = mysql.connector.connect(host=xxxx,port=yyy,user=zzzz,passwd=****,database=dddd)
cursor_query = con.cursor(buffered=True)
cursor_query.execute("SELECT id, value FROM table WHERE value='text';")
row = cursor_query.fetchone()

注意点

注意点に関しては公式の記載にある通りです。

 

buffered=True を指定することにより、あまりに大きな値が返って来てしまった場合に、クエリが実行された直後に過度のメモリを使用する可能性があります。

本来、一件のデータを取得する処理で fetchone を使用しているはずなので問題はないと思いますが、システムの案税制を考えれば先に述べたようなオプション指定に頼らないやり方がよりよいと感じます。

 

公式サイト : 外部URL

※以下の記載部分が注意点が書かれています。更新されている可能性もあるので最新の情報は公式から確認してください。

 

まとめ

エラーの対策で考えられるいくつかの方法を記載しました。

どれが一番良いかは、システムによって変わってくるため、そのシステムの仕様や処理内容に最もあった方法を考え処理を行う事を推奨します。

 

オプション指定は一番簡単ですが、個人的には根本的な解決を行った方が保守性や安全性は確保されると考えています。

 

 

 


読んで頂き、ありがとうございます。
この記事が誰かにとって、一つの参考となれば幸いです。

新たな知識や技術を習得し続けていきたいです。

 

 

 

コメント