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

时间:2016-08-19 04:39:31

标签: ruby rack sequel puma

我在Puma / Rack服务器上使用Sequel和Sinatra。

我希望将Sequel数据库连接对象存储在会话中 - 而不是全局 - 这样我就可以为每个登录用户创建一个单独的数据库连接池。目的是为每个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

1 个答案:

答案 0 :(得分:2)

您无法序列化Sequel :: Database对象。你有一些不错的选择:

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

  2. 在顶层创建一个Sequel :: Database对象并将其存储在DB常量中。将arbitrary_servers和server_block扩展到Sequel :: Database对象中。然后使用机架中间件在块的持续时间内检出与相应服务器的连接。

  3. 如果客户很少,可以使用Sequel的分片支持,只使用server_block扩展名而不使用arbitrary_servers。这样做的一个优点是可以缓存连接,因此您不会为每个请求建立单独的数据库连接(对于1.和2都是如此)。

  4. 如上所述使用全局哈希,键是用户名,值是Sequel :: Database对象。如果这样做,您需要确保有足够的内存来存储要跟踪的所有对象。