问题
Every time, I submit a form supposed to create a Deal and sending a very high nb of Prizes (>200K) to the Prize table using a transaction and raw postgresql, I have first the error 'undefined method exec_prepared' then if I reload the form then I get a new error 'ERROR: prepared statement 'xixie' already exists'.
I used this question wrong number of arguments (1 for 2..3) for Active Record postgresql query (Rails 4/postgresql 9.4) and Prepared Statement on Postgresql in Rails to create the following Postgresql query:
models deals.rb
CONNEXION = ActiveRecord::Base.connection.raw_connection
def create_prizes
Deal.transaction do
self.prize_number.times do |i|
st = CONNEXION.prepare('xixie', 'INSERT INTO prizes (deal_id) values ($1)')
values = [ { value: self.id} ]
st.exec_prepared('xixie', values )
st.close()
end
end
end
I have this problem in Local (not production) and I am not using any puma/unicorn. I do use Zeus and Guard.
Is it impossible with Rails4/postgresql prepared_statements to insert multiple rows at a time ?
How can I change the query to make it work ?
Also as Rails gives me ' ERROR: prepared statement 'xixie' already exists', I had to change multiple times the name of the prepared_statements but will they "live" forever? how can I "kill" them after I do all theses iterations trying to find the appropriate query.
EDIT
Updated the code after some proposed answer:
CONNECTION = ActiveRecord::Base.connection.raw_connection
def create_prizes
Deal.transaction do
self.prize_number.times do |i|
CONNECTION.prepare('mimiku', 'INSERT INTO deal_prizes (deal_id, created_at, updated_at) values ($1, $2, $3)')
CONNECTION.exec_prepared('mimiku', [ { value: self.id}, { value: '2009-01-23 20:21:13' }, { value: '2009-01-23 20:21:13' } ] )
end
# CONNECTION.close()
end
end
(added '2009-01-23 20:21:13' as Rails required created_at and updated_at for some reason).
I get this error:
ERROR: prepared statement "mimiku" already exists
Even if I change the name from 'mimiku' to 'somethingelse', I still get this type of error.
回答1:
The prepare method returns a result according to the docs:
http://deveiate.org/code/pg/PG/Connection.html#method-i-prepare
Maybe try call exec_prepared on the connection object
connection = ActiveRecord::Base.connection.raw_connection
def create_prizes
begin
connection.describe_prepared('xixie')
rescue PG::InvalidSqlStatementName
connection.prepare('xixie', 'INSERT INTO prizes (deal_id) values ($1)')
end
Deal.transaction do
self.prize_number.times do |i|
connection.exec_prepared('xixie', [ { value: self.id} ] )
end
end
end
UPDATE: I reworked the code above to first check if a prepared statement exists. If it doesn't exist it creates it. Sorry I haven't realized it in the first place but you don't need to prepare a statement more than once. This is the actual benefit of such a statement, since it has to be only parsed once and can than be executed with different values, which is then much faster than a regular query. As prepared statements last for the duration of the AR connection you only need to prepare it once.
来源:https://stackoverflow.com/questions/32444971/undefined-method-exec-prepared-on-rails-4-postgresql-query