23287


PythonでのPyMySQLに関してですが、テーブルからユーザー名を取得する関数を作ったのですが、そのユーザーをmysqlから消しても、関数が返す値が同じです。何がいけないのでしょうか？

以下が作った関数です

[code]

    import sys
    import time
    import pymysql
    
    conn = pymysql.connect(host='localhost',
                           user='user',
                           password='password',
                           db='database',
                           charset='utf8')
    
    def get_user():
        cursor = conn.cursor()
        query = """SELECT username FROM users WHERE username=testuser"""
        cursor.execute(query)
        result = cursor.fetchone()[0]
        cursor.close()
        return result
    
    
    def worker():
        try:
            while True:
                time.sleep(1)
                print(get_user())
        except KeyboardInterrupt:
            print("Stopeed")
    
    
    if __name__ == '__main__':
        worker()
    
[/code]

testuserを消した後、get_user()を実行すると、テーブルには存在しないのに返ってきてます。なぜでしょうか？

よろしくお願いします。


CC BY-SA 3.0
2016-03-19T12:07:57.310
23278
2016-03-22T23:34:42.080
2016-03-21T10:29:20.943
3054
14857
question
python mysql
PyMySQLでの問合せ結果がテーブルデータ変更後も変化しない


コードを一目で見ると、一つの問題は`'`のマークのことにあると思います。特に、この行：

[code]

    >>> testuser = "me"
    >>> query = 'SELECT username FROM users WHERE username='testuser''
    
[/code]

この関数を実行すると、`SyntaxError`が発生するでしょう。例えば：

[code]

    >>> query = 'SELECT username FROM users WHERE username='testuser''
      File "<stdin>", line 1
        query = 'SELECT username FROM users WHERE username='testuser''
                                                                   ^
    SyntaxError: invalid syntax
    
[/code]

そしたら、`SELECT`の`query`が正確に実行されていないと思いますので、他に問題が発生する可能性もあると思います。

そのために、下記の方はどうですか。

[code]

    query = """SELECT username FROM users WHERE username='%s'""", (testuser)
    
[/code]

出力の例：

[code]

    >>> testuser = "me"
    >>> query = """SELECT username FROM users WHERE username='%s'""", (testuser)
    >>> query
    ("SELECT username FROM users WHERE username='%s'", 'me')
    
[/code]

* * *

### 更新

もっと調べてみると、これは「キャッシュ」のことにつながっている問題ではないでしょうか。特に、「`autocommit`」という設定に[関係があるかもしれません](https://github.com/PyMySQL/PyMySQL/issues/76)。しかし、[suzukis](https://ja.stackoverflow.com/users/5793/suzukis)さんの回答のように、`commit`のことはやはり[`MySQL
Query Cache`](http://dev.mysql.com/doc/refman/5.6/ja/query-
cache.html)に関係がないようですが。

それにしても、下記のメソードを呼び出すと、「キャッシュっぽい効果」を避けることが出来るようです。

`conn.autocommit(True)`

[このスレでは、martaaayさんの説明](https://github.com/PyMySQL/PyMySQL/issues/76#issuecomment-10236696)のように、`autocommit(False)`という設定は最新のチェンジを無視して、次の`commit`を実行する前に、前のデータを使用する状態になってしまうのです。他方では、`autocommit(True)`という設定は自動的に最新のトランザクションを`commit`して、これからは最新の`commit`されたデータを使用することが出来ます。

将来の参照のために、`autocommit`のこと自体については[suzukisさんの説明](https://ja.stackoverflow.com/a/23328/4129)と共に、MySQLのトランザクションについての[リファレンス](http://dev.mysql.com/doc/refman/5.6/ja/commit.html)もあると思います。トランザクションということ自体は大切な概念で、特に[ACID](https://ja.wikipedia.org/wiki/ACID_\(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E7%A7%91%E5%AD%A6\))には[役に立ちます](https://stackoverflow.com/a/3740307)。


CC BY-SA 3.0
2016-03-20T00:51:47.393
23287
2016-03-22T17:26:05.550
2017-05-23T12:38:56.467
-1
4129
23278
answer


autocommitを有効にしたら期待したとおりの動作になったということで、それはトランザクションによるものです。

トランザクションというのはデータベースにおける一連の処理の塊のことで、「コミット」という操作をすることでDBに反映が永続化されます。また、「ロールバック」という操作で処理を取り消すことも出来ます。

autocommit(自動コミット)が無効の場合、明示的にcommitないしはrollbackするまではトランザクションの内部にいることになります。ここで、他のトランザクションによりDBが変更されたとしても、その変更を読み取ることは出来ません。(細かいことを言うとトランザクション分離レベルにもよる)

autocommitを有効にすると、1つクエリを発行した時点でトランザクションが完結します。他のトランザクションによる変更後に発行されたクエリではその変更を読み取ることが出来ます。

キャッシュとは全く違う概念です。

データベース理論の入門的な内容ですがデータベースのACID特性について学んでもらえば、これがデータベースの信頼性に関わる根本的な部分に関連していて、キャッシュとは全く違うものであることが理解できると思います。


CC BY-SA 3.0
2016-03-22T00:53:37.353
23328
2016-03-22T23:34:42.080
2016-03-22T23:34:42.080
5793
5793
23278
answer