如何使用 Sinatra、Sequel 和 Rack 设置基于会话的数据库连接
How to setup session based database connections with Sinatra, Sequel and Rack
我在 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
您不能序列化 Sequel::Database 对象。你有几个不错的选择:
使用机架中间件为每个请求创建一个 Sequel::Database 对象,只为请求使用该对象。在这种情况下,您不会将 Sequel.connect 的结果分配给常量,您会传递一个块并调用该块内的下一个变量。
在顶层创建单个 Sequel::Database 对象并将其存储在数据库常量中。 arbitrary_servers 和 server_block 扩展到 Sequel::Database 对象中。然后使用机架中间件在块的持续时间内检查到适当服务器的连接。
如果您的客户很少,可以只使用 Sequel 的分片支持,只使用 server_block 扩展而不使用 arbitrary_servers。这样做的一个好处是可以缓存连接,这样您就不会为每个请求建立单独的数据库连接(1. 和 2. 都是这种情况)。
使用您提到的全局哈希,键是用户名,值是 Sequel::Database 对象。如果你这样做,你需要确保你有足够的内存来存储你想要跟踪的所有对象。
我在 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
您不能序列化 Sequel::Database 对象。你有几个不错的选择:
使用机架中间件为每个请求创建一个 Sequel::Database 对象,只为请求使用该对象。在这种情况下,您不会将 Sequel.connect 的结果分配给常量,您会传递一个块并调用该块内的下一个变量。
在顶层创建单个 Sequel::Database 对象并将其存储在数据库常量中。 arbitrary_servers 和 server_block 扩展到 Sequel::Database 对象中。然后使用机架中间件在块的持续时间内检查到适当服务器的连接。
如果您的客户很少,可以只使用 Sequel 的分片支持,只使用 server_block 扩展而不使用 arbitrary_servers。这样做的一个好处是可以缓存连接,这样您就不会为每个请求建立单独的数据库连接(1. 和 2. 都是这种情况)。
使用您提到的全局哈希,键是用户名,值是 Sequel::Database 对象。如果你这样做,你需要确保你有足够的内存来存储你想要跟踪的所有对象。