ActiveRecord错误:SAVEPOINT active_record_1不存在

时间:2012-10-31 15:28:21

标签: mysql ruby-on-rails activerecord

完整错误是

ActiveRecord::StatementInvalid: Mysql2::Error: SAVEPOINT active_record_1 does not exist: ROLLBACK TO SAVEPOINT active_record_1

我正在编写一个单元测试,每当我尝试创建一个新的ActiveRecord对象时都会收到此错误 - 但只是在某个点之后。这发生在这些行之后:

ActiveRecord::Base.connection.execute "DROP TABLE IF EXISTS foo"
ActiveRecord::Base.connection.execute "CREATE TABLE foo (id INTEGER PRIMARY KEY)"

(如果我的测试成功,表'foo'将填充数据)

在上述行之前,我可以写一些类似

的内容
User.create(email => 'foo@bar.com')

一切正常。但是,如果我在调用ActiveRecord :: Base.connection.execute之后尝试编写上面的行,那么我会得到上面描述的SAVEPOINT错误。我也尝试将我的执行语句放在一个事务中,但这没有帮助。我很难过。

仅供参考 - 我正在使用Rails 3.2.8

6 个答案:

答案 0 :(得分:20)

您正在使用Mysql DDE语句(create / drop / truncate table),这将导致implicit commit

由于隐式提交,当前事务的所有保存点都被删除(参见上面的文档)。

要解决此问题,您可以turn off transactions并使用DatabaseCleaner(截断模式)。

答案 1 :(得分:7)

要解决这个问题..

config.use_transactional_fixtures = false

答案 2 :(得分:2)

创建/删除表时可以使用“TEMPORARY”。

http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html 如果使用TEMPORARY关键字,则ALTER TABLE,CREATE TABLE和DROP TABLE不提交事务。 (这不适用于临时表上的其他操作,例如CREATE INDEX,它会导致提交。)但是,虽然没有发生隐式提交,但是语句都不能回滚。因此,使用此类语句将违反事务原子性:例如,如果使用CREATE TEMPORARY TABLE然后回滚事务,则该表仍然存在。

答案 3 :(得分:1)

只是澄清一下。您可以将触发MySql DDE语句的测试隔离到他们自己的文件中,然后在该文件中填写config.use_transactional_fixtures = false。这样,所有其他测试都不会受到影响。现在,您负责清理隔离的测试文件。

答案 4 :(得分:0)

答案 5 :(得分:0)

首先确保您已安装DatabaseCleaner gem,这将使您可以选择数据库清理策略。我们收到的错误意味着最好使用truncation策略。

# file: Gemfile

group :test do
  gem ‘database_cleaner’
end

将DatabaseCleaner配置添加到功能目录(参见下文)。

#file: features/support/database_cleaner.rb

begin
  require 'database_cleaner'
  require 'database_cleaner/cucumber'

  DatabaseCleaner.strategy = :truncation
rescue NameError
  raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end

Around do |scenario, block|
  DatabaseCleaner.cleaning(&block)
end