11

我熟悉Ruby on Rails,DB(MS)驱动程序和存储过程之间长久以来的爱恨关系,自从版本2.3.2开始,我一直在开发Rails应用程序。为什么Rails(3 +)仍然不支持存储过程?

但是,每隔一段时间就会出现一种情况,即SP仅仅是将数据组合在(慢得多)应用程序级别上的更好选择。特别是,运行组合多个表的数据的报告通常更适合于SP。

为什么存储过程仍然很少集成到Rails或MySQL gem中。我目前正在使用Rails 3.0.10和MySQL2 gem 0.2.13开发一个项目,但据我所知,即使是最新的Edge Rails和MySQL gem 0.3+,当您使用SP时仍然会发脾气。

一直存在的问题是,调用SP后数据库连接丢失。

>> ActiveRecord::Base.connection.execute("CALL stored_proc") 
=> #<Mysql::Result:0x103429c90> 
>> ActiveRecord::Base.connection.execute("CALL stored_proc") 
ActiveRecord::StatementInvalid: Mysql::Error: Commands out of sync; 
[...] 
>> ActiveRecord::Base.connection.active? 
=> false 
>> ActiveRecord::Base.connection.reconnect! 
=> nil 
>> ActiveRecord::Base.connection.execute("CALL proc01") 
=> #<Mysql::Result:0x1034102e0> 
>> ActiveRecord::Base.connection.active? 
=> false 

这是一个真正难以解决的问题,技术上还是这是Rails的设计选择?

+0

FWIW:从2006年2月,DHH采访时说:“我在花哨的功能,如存储过程完全不感兴趣,触发器之类的东西“ - http://dev.mysql.com/tech-resources/interviews/david-heinemeier-hansson-rails.html – 2012-07-25 19:36:21

+0

另外[”我认为存储过程和限制恶劣和鲁莽的连贯驱逐舰“](http://web.archive.org/web/20060418215514/http://www.loudthinking.com/arc/000516.html)... – dbr 2012-07-25 19:39:01

+7

2006 ...古代的原则(是的,6年是古老的在一个世界里e Rails)对于技术的发展很少有意义(640k就足够了,任何人都可以) 这里有理论和实践领域。理论上我绝对支持Rails范式,但有时候最好的规范化数据库会给现实世界带来最差的性能。 当一个SP可以在不到100ms的时间内为我的报告收集数据,并且通过Rails的方式完成这个过程需要2-3秒钟,并且多个查询在一个共享数据库中被触发时,我知道谁是明显的赢家。 – ChrisDekker 2012-07-25 19:50:41

回答

10

轨道中支持存储过程。你得到的不同步错误是因为MySQL的MULTI_STATEMENTS标志在默认情况下在Rails中未启用。该标志允许过程返回多于1个结果集。

在这里看到有关如何启用它的代码示例:https://gist.github.com/wok/1367987

存储过程制定出与MS SQL Server的盒子。

我一直在使用存储过程几乎所有我的MySQL和SQL Server的rails项目没有任何发布。

3

这是为postgres执行一个返回MyClass实例的存储过程。

sql=<<-SQL 
select * from my_cool_sp_with_3_parameters(?, ?, ?) as 
foo(
    column_1 <type1>, 
    column_2 <type2> 
) 
SQL 

MyClass.find_by_sql([sql, param1, param2, param3]); 

将foo()中的列列表替换为模型列和存储过程结果中的列。我相信通过检查课程的专栏可以使其成为通用的。

0

那些获取同步错误的人可能会生成多个结果的过程。你需要做这样的事情来处理它们:

raise 'You updated Rails. Check this duck punch is still valid' unless Rails.version == "3.2.15" 
module ActiveRecord 
    module ConnectionAdapters 
    class Mysql2Adapter 
     def call_stored_procedure(sql) 
     results = [] 
     results << select_all(sql) 
     while @connection.more_results? 
      results << @connection.next_result 
     end 
     results 
     end 
    end 
    end 
end 

这样调用:

ActiveRecord::Base.connection.call_stored_procedure("CALL your_procedure('foo')") 
相关问题