如何在Sinatra应用中创建跨HTTP请求留存数据的持久对象
Sinatra 跨请求持久化内存对象解决方案
你之前尝试的方案失效原因如下:
- 控制器
initialize方法:Sinatra每次收到HTTP请求都会新建一个控制器实例处理请求,因此实例变量@transactions每次请求都会重新初始化,自然无法跨请求保留 - 类变量写在
configure块内:块作用域会改变类变量的所属上下文,你定义的@@transactions不属于应用类本身,路由内访问时自然返回nil - 如果你之前用
set :transactions, Transactions.new不生效,大概率是访问方式错误,没有通过settings对象读取配置
以下是3种可行的实现方案:
方案1:使用Sinatra内置settings机制(最推荐)
这是Sinatra官方推荐的应用级全局配置方式,配置对象在应用启动时初始化,不会随请求重建。
写法示例(模块化风格):
class App < Sinatra::Base # 应用启动时初始化一次 set :transactions, Transactions.new get '/add' do # 路由内通过settings访问 settings.transactions.add(params[:amount]) 'ok' end end
经典风格直接在顶层写set :transactions, Transactions.new,路由内同样用settings.transactions访问即可。
方案2:定义全局常量(极简场景适用)
直接在应用启动代码的最顶层定义全局常量,整个应用生命周期内都不会被重新初始化:
# 应用启动时执行一次 TRANSACTIONS = Transactions.new class App < Sinatra::Base get '/add' do TRANSACTIONS.add(params[:amount]) 'ok' end end
方案3:应用类级别的类变量
将类变量定义在应用类的直接作用域下,不要嵌套在configure等块内:
class App < Sinatra::Base @@transactions = Transactions.new get '/add' do @@transactions.add(params[:amount]) 'ok' end end
注意事项
- 以上所有方案都是内存级存储,应用重启、进程退出后数据会全部丢失
- 如果你使用prefork模式的服务器(如Unicorn、Puma多worker模式),每个worker进程会持有一份独立的
transactions副本,数据不会跨worker同步,如果需要全应用统一数据,还是需要引入Redis这类共享内存存储 - 如果使用多线程服务器,需要给
Transactions类的写操作加互斥锁,避免并发写入导致的数据异常
内容的提问来源于stack exchange,提问作者csecrepublic
相关产品推荐
相关产品推荐

