2013-04-06 4 views
2

Привет, я пытаюсь использовать подготовленные команды mysql в django.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

Благодаря Томасу я получить это работает так:

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() 
Смежные вопросы