4

こんにちは、django で mysql プリペアド ステートメントを使用しようとしています。

次のクラスを作成しました。

class PreparedStatement(object):

    def __init__(self,name,query):
        self.name = name
        self.query = query
        self.vars = []
        self.prepare()

    def setVar(self,name,var):
        name = "@%s" % name
        if name not in self.vars:
            self.vars.append(name)
        SQL = "SET %s = " % (name)
        self.__executeQuery(SQL+" %s;",var)

    def prepare(self):
        SQL = "PREPARE %s FROM " % self.name
        self.__executeQuery(SQL + " %s ;", self.query)

    def execute(self):
        SQL = "EXECUTE %s " % self.name

        if len(self.vars):
            params = ""
            for var in self.vars:
            params += var + ", "
            params = params[:-2]
            SQL += "USING %s " % params
        result =  self.__executeQuery(SQL)
        self.vars = []
        return result

    def __executeQuery(self,query,*args):
        cursor = connection.cursor()
        if args:
            cursor.execute(query,args)
        else:
            cursor.execute(query)
        return cursor

そして、私はそれを次のように使用します:

getDiscountsById = PreparedStatement("getDiscountsById","""SELECT * FROM table 
WHERE id = ? LIMIT 1""")
getDiscountsById.setVar("id",5)
result = getDiscountsById.execute()

最初にロードされたページでは正常に動作していますが、URL を変更したり、ページをリロードしたりした後、MySQL は準備されたステートメントが見つからないというエラーを返します。

どこに問題があるのでしょうか? 解決策はありますか?

返信ありがとうございます。私の英語で申し訳ありません:D

4

2 に答える 2

2

ビューの外で PreparedStatement オブジェクトを構築し、グローバルとしてアクセスしていると思われます。

django には接続プールの概念がなく、すべてのページ ビューでまったく新しいデータベース接続が使用されることに注意する必要があります。MySQL の準備済みステートメントは、それらが定義されている接続/セッションの存続期間中のみ存在します。したがって、最初の pagview は PreparedStatement が含まれているモジュールをロードし、それを DB に配置しますが、2 番目の接続は以前の接続で準備されたステートメントを実行しようとしますが、明らかに失敗します。

これを修正するには、必要なビューで PreparedStatement を作成するか、次のようなものを使用します (PHP を模倣するのではなく、もう少し Python 的に実行します)。

class PreparedStatement(object):

    def __init__(self, name, query, vars):
        self.name = name
        self.query = query
        self.vars = vars

    def prepare(self):
        SQL = "PREPARE %s FROM " % self.name
        self.__executeQuery(SQL + " %s ;", self.query)

    def get_prepared(self):
        # store a map of all prepared queries on the current connection
        return getattr(connection, "__prepared", default={})

    def execute(self, **kwvars):

        if not self.name in self.get_prepared().keys()
           # Statement will be prepared once per session.
           self.prepare()

        SQL = "EXECUTE %s " % self.name

        if self.vars:
            missing_vars = set(self.vars) - set(kwvars)
            if missing_vars:
                raise TypeError("Prepared Statement %s requires variables: %s" % (
                                    self.name, ", ".join(missing_variables) ) )

            param_list = [ var + "=%s" for var in self.vars ]
            param_vals = [ kwvars[var] for var in self.vars ]

            SQL += "USING " + ", ".join( param_list )

            return self.__executeQuery(SQL, *param_vals)
        else:
            return self.__executeQuery(SQL)

    def __executeQuery(self,query, *args):
        cursor = connection.cursor()
        if args:
            cursor.execute(query,args)
        else:
            cursor.execute(query)
        return cursor

そして、このように使用します

# Global
getDiscountsById = PreparedStatement(
     "getDiscountsById",
     "SELECT * FROM table WHERE id = ? LIMIT 1",
     vars=["id"] # List out the names of the placeholders. This will assist in error checking.
)

#local to a view
result = getDiscountsById.execute(id=5)

免責事項:私はこれをテストしていませんが、実行するか、微調整して実行するのに十分簡単である必要があります。

于 2013-04-07T12:39:17.307 に答える