Rails2.3をMySQL4.xで使うときのRELEASE SAVEPOINTの問題
MySQL4系ではRELEASE SAVEPOINT をサポートしていないので、Rails2.3がMySQL4.xに向けて、RELEASE SAVEPOINTを使ってもエラーになるという話です。
エラーの再現
User.connection.transaction do User.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1 User.find(:all) end end # RELEASE SAVEPOINT active_record_1 ActiveRecord::StatementInvalid: Mysql::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE SAVEPOINT active_record_1' at line 1: RELEASE SAVEPOINT active_record_1 from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.3.11/lib/active_record/connection_adapters/abstract_adapter.rb:227:in `log' from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.3.11/lib/active_record/connection_adapters/mysql_adapter.rb:324:in `execute' from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.3.11/lib/active_record/connection_adapters/mysql_adapter.rb:370:in `release_savepoint' from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.3.11/lib/active_record/connection_adapters/abstract/database_statements.rb:161:in `transaction' from (irb):87 from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.3.11/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction' from (irb):86
ActiveRecordのコード
activerecord-2.3.11/lib/active_record/connection_adapters/abstract/mysql_adapter.rb
369 def release_savepoint 370 execute("RELEASE SAVEPOINT #{current_savepoint_name}") 371 end
activerecord-2.3.11/lib/active_record/connection_adapters/abstract/database_statements.rb
153 if outside_transaction? 154 @open_transactions = 0 155 elsif transaction_open 156 decrement_open_transactions 157 begin 158 if open_transactions == 0 159 commit_db_transaction 160 else 161 release_savepoint 162 end 163 rescue Exception => database_transaction_rollback 164 if open_transactions == 0 165 rollback_db_transaction 166 else 167 rollback_to_savepoint 168 end 169 raise 170 end 171 end
RELEASE SAVEPOINT を execute で実行していることが分かります。
対応
使えないものは仕方ないので、こちらのように、RELEASE SAVEPOINT を発行しないようにしました。下記の内容を config/initializers/unset_release_savepoint_method.rb に記述しました。
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do # Unset release savepoint method def release_savepoint end end
エラーが再現しないことを確認
User.connection.transaction do User.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1 User.find(:all) end end => [#User id・・・・・・・]
もう、MySQL5を使えと言うことですね・・・。