Rails中Postgresql的预准备语句

66bbxpm5  于 2023-03-08  发布在  PostgreSQL
关注(0)|答案(2)|浏览(117)

现在我正在从SQLite迁移到Postgresql,我遇到了这个问题。下面的预处理语句可以在SQLite中使用:

id = 5
st = ActiveRecord::Base.connection.raw_connection.prepare("DELETE FROM my_table WHERE id = ?")
st.execute(id)
st.close

不幸的是,它不能与Postgresql一起工作-它在第2行抛出了一个异常。我正在寻找解决方案,遇到了这个:

id = 5
require 'pg'
conn = PG::Connection.open(:dbname => 'my_db_development')
conn.prepare('statement1', 'DELETE FROM my_table WHERE id = $1')
conn.exec_prepared('statement1', [ id ])

这个在第3行失败。当我像这样打印异常时

rescue => ex

ex包含此内容

{"connection":{}}

在命令行中执行SQL可以工作。知道我做错了什么吗?
先谢了!

huwehgph

huwehgph1#

如果您想像这样使用prepare,那么您需要做一些更改:

  1. PostgreSQL驱动程序希望看到带编号的占位符($1$2,...)而不是问号,您需要为预准备语句命名:
ActiveRecord::Base.connection.raw_connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")

1.调用序列为prepare,后跟exec_prepared

connection = ActiveRecord::Base.connection.raw_connection
connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
st = connection.exec_prepared('some_name', [ id ])

上面的方法对我来说适用于ActiveRecord和PostgreSQL,如果你连接正确,你的PG::Connection.open版本应该可以工作。
另一种方法是自己引用:

conn = ActiveRecord::Base.connection
conn.execute(%Q{
    delete from my_table
    where id = #{conn.quote(id)}
})

这就是ActiveRecord通常在你背后做的事情。
直接与数据库交互往往会给Rails带来一些麻烦,因为Rails人员认为您永远不应该这样做。
如果您真的只想删除一行而不产生干扰,可以使用delete

    • 删除()**

[...]
只需对记录的主键使用SQL DELETE语句删除该行,并且不执行回调。
所以你可以这么说:

MyTable.delete(id)

然后将一个简单的delete from my_tables where id = ...发送到数据库中。

uelo1irk

uelo1irk2#

为了补充一个已经被接受的答案,任何人在Rails中搜索预准备语句进行自定义查询,这里有一个更简单的方法,通过现有的ActiveRecord接口(例如Postgresql):

ActiveRecord::Base.connection.exec_query("select * from table_name where id = $1", 
"example_query", [1], prepare: true)

如果输入binding.pry,您将看到预准备语句确实已创建:

ActiveRecord::Base.connection.exec_query('select * from pg_prepared_statements')

参考:https://api.rubyonrails.org/v7.0.4.2/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html

相关问题