如何设置与Sinatra,Sequel和Rack的基于会话的数据库连接

问题描述:

我在Puma/Rack服务器中使用了Sinatra的Sequel。如何设置与Sinatra,Sequel和Rack的基于会话的数据库连接

我希望将会话的续集数据库连接对象(不是全局的)存储起来,这样我就可以为每个登录用户拥有单独的数据库连接池。目的是为每个Web服务器登录都有一个数据库服务器登录。

因为Sequel数据库对象似乎是全局单例,所以我无法解决这个问题。例如,如果我尝试序列化数据库对象并将其存储在会话中,我将收到一条错误消息:TypeError - can't dump anonymous class:我不想在每个路由请求上连接到数据库。

我该怎么做?以下是一些示例代码,希望可以指示我正在尝试实现的内容:

require 'sinatra/base' 
require 'pp' 
require 'sequel' 
require 'json' 
require 'java'    
require 'sqljdbc4.jar' 
require 'yaml' 

class MyApp < Sinatra::Base 

    set :sessions, true 

    use Rack::Session::Cookie, :key => 'rack.session', 
     :expire_after => 2592000, 
     :secret => 'sydasx' 

    get '/' do 
    db = session[:db] 
    DB = YAML::Load(db) 

    response = '' 
    DB['select * from SEC_USER'].each do |row| 
     response += row.to_s 
    end 

    response.to_json 
    end 

    get '/login/:username' do 

    username = params['username'] 

    puts "username: #{username}" 

    conn_str = "jdbc:sqlserver://localhost:1434;databaseName=#{username};integratedSecurity=true;"  
    DB = Sequel.connect(conn_str) 
    puts "DB: #{DB.pretty_inspect}" 
    db = YAML::dump(DB) 
    puts "db: #{db}" 

    session[:db] = db 

    "logged in" 
    end 

end 
+0

嗯 - 只是想知道 - 是另一种问这个问题的方法 - 机架允许会话状态存储在内存中吗?还是会话状态总是需要序列化? –

+0

哦 - 只是将数据库对象添加到全局哈希似乎这样做。我想这是行得​​通的。 –

您无法序列化Sequel :: Database对象。你有几个像样的选择:

  1. 使用创建每个请求的续集::数据库对象,使用该对象仅适用于要求机架中间件。在这种情况下,您不会将Sequel.connect的结果分配给常量,您可以传递一个块并调用该块内的下一个变量。

  2. 在顶层创建一个Sequel :: Database对象,并将其存储在数据库常量中。 Sequel :: Database对象中的arbitrary_servers和server_block扩展。然后使用机架中间件,在该块的持续时间内检查到适当服务器的连接。

  3. 如果您的客户很少,可以仅使用Sequel的分片支持,并且只使用server_block扩展名而不使用任意服务器。这样做的一个好处是可以缓存连接,因此您不会为每个请求创建单独的数据库连接(对于1.和2.而言都是如此)。

  4. 正如您所提到的那样使用全局散列,其中的键是用户名和值为Sequel :: Database对象。如果你这样做,你需要确保你有足够的内存来存储你想跟踪的所有对象。

+0

谢谢杰里米。选项2听起来很有趣。我们意识到我们与从Sequel :: Model继承的模型类有一个类似的问题,它们是包含数据库连接的全局单例。选项2也可以解决这个问题。 –