2013-04-06 128 views
2

你好,我試圖在Django中使用mysql準備語句。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

+0

你爲什麼要使用預處理語句?它是爲了性能優勢,還是在不暴露SQL注入泄露的情況下編寫原始SQL? – Thomas

+0

@Thomas 這是學校派遣,我不能使用ORM,我必須使用準備好的語句 – ChuckBorris

回答

0

我懷疑你正在構建的PreparedStatement對象視圖之外並訪問它作爲一個全球性的。

您需要注意的是,django沒有連接池的概念,每個頁面視圖都使用全新的數據庫連接。 MySQL預處理語句只存在於定義它們的連接/會話期間。因此,第一個pagview加載PreparedStatement所在的模塊,並將其放入數據庫中,但第二個連接嘗試執行在上一次連接中準備的語句,該語句明顯失敗。

要解決這個問題,在你需要它,或者使用類似這樣的視圖中創建PreparedStatement的(這樣做有點更pythonically,不模仿PHP):

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) 

聲明:我沒有測試過這個,但它應該運行或很容易調整到運行。

+0

感謝您的解釋和解決方案。它不是這樣工作的,我不瞭解使用變量的變化。但是我重寫了我的解決方案,現在它可以工作。 – ChuckBorris

0

感謝Thomas我得到它的工作是這樣的:使用

class PreparedStatement(object): 

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

    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.get_prepared().append(self.name) 
     self.__executeQuery(SQL + " %s ;", self.query) 

    def get_prepared(self): 
     try: 
      getattr(connection, "__prepared") 
     except AttributeError: 
      setattr(connection,"__prepared",[]) 
     finally: 
      return getattr(connection, "__prepared") 

    def f_execute(self): 
     return self.execute().fetchall() 

    def execute(self): 
     if not self.name in self.get_prepared(): 
      self.prepare() 
     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()