当前位置: 首页 > news >正文

848给我做一下88网站给个免费资源

848给我做一下88网站,给个免费资源,医院内外网站建设,网站建设会议记录一、问题#xff1a; 有时在 Postgres 上部署 Rails 应用程序时#xff0c;可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来…一、问题 有时在 Postgres 上部署 Rails 应用程序时可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来提高性能。这个功能在rails中默认是开启的。 二、问题复现 我们可以用rspec来复现这个错误 it not raise ActiveRecord::PreparedStatementCacheExpired docreate(:user)User.firstUser.find_by_sql(ALTER TABLE users ADD new_metric_column integer;)ActiveRecord::Base.transaction { User.first }end三、产生的原理 rails查询语句如User.all被 active_record 解析成sql语句后发送给数据库先执行PREPARE预备语句sql语句会被解析、分析、优化并且重写。当后续发出一个EXECUTE命令时该预备语句会被规划并且执行。rails会把查询语句存到pg_prepared_statements中以方便下次调用同类语句时候直接execute statements中的语句而不用再进行解析、分析、优化避免重复工作提高效率。 User.first User.all # 执行上面的2个查询后用connection.instance_variable_get(:statements)就可以看到缓存的准备语句 ActiveRecord::Base.connection.instance_variable_get(:statements)ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::StatementPool:0x00000001086b13c8 cache{78368{\$user\, public-SELECT \users\.* FROM \users\ ORDER BY \users\.\id\ ASC LIMIT $1a7, \$user\, public-SELECT \users\.* FROM \users\ /* loading for inspect */ LIMIT $1a8}}, statement_limit1000, connection#PG::Connection:0x00000001086b31a0, counter8# 这个也可以看到会在数据库中去查询 ActiveRecord::Base.connection.execute(select * from pg_prepared_statements).values (0.5ms) select * from pg_prepared_statements[[a7, SELECT \users\.* FROM \users\ ORDER BY \users\.\id\ ASC LIMIT $1, 2024-07- 11T07:03:06.89100:00, {bigint}, false], [a8, SELECT \users\.* FROM \users\ /* loading for inspect */ LIMIT $1, 2024-07-11T07:04:47.77200:00, {bigint}, false]]在 Postgres 中如果表的模式(schema)更改影响返回结果则预准备语句缓存将失效。具体说就是给表增加、删除字段或者修改字段的类型、长度等ddl操作。 如下面的例子添加或删除字段后执行SELECT时pg数据库就会抛出cached plan must not change result typerails中active_record获取到这个错误然后会抛出ActiveRecord::PreparedStatementCacheExpired ALTER TABLE users ADD COLUMN new_column integer; ALTER TABLE users DROP COLUMN old_column; 添加或删除列然后执行 SELECT * 删除 old_column 列然后执行 SELECT users.old_column部署服务中运行增、减、修改字段的迁移时用户发出的查询语句会从预准备语句缓存中直接拿sql直接进行excute但这时候因为表结构变化了预准备语句缓存就失效了pg数据库就会抛出cached plan must not change result type错误查看active_record源码中的exec_cache方法发现rails对pg的这个错误处理方式是 事务transaction中会直接抛出 raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)事务外的会把缓存statements中的这句删除并 try重试后会重新解析、分析、优化sql语句并执行prepare_statement方法放入预准备语句缓存中 module ActiveRecordmodule ConnectionHandlingdef exec_cache(sql, name, binds)materialize_transactionsmark_transaction_written_if_write(sql)update_typemap_for_default_timezonestmt_key prepare_statement(sql, binds)type_casted_binds type_casted_binds(binds)log(sql, name, binds, type_casted_binds, stmt_key) doActiveSupport::Dependencies.interlock.permit_concurrent_loads doconnection.exec_prepared(stmt_key, type_casted_binds)endendrescue ActiveRecord::StatementInvalid eraise unless is_cached_plan_failure?(e)# Nothing we can do if we are in a transaction because all commands# will raise InFailedSQLTransactionif in_transaction?raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)elselock.synchronize do# outside of transactions we can simply flush this query and retrystatements.delete sql_key(sql)endretryendendend end所以出现在事务transaction中的这个错误就会导致事务回滚对业务来说就是请求失败了需要我们自己来处理 四、解决方法 1. 禁用缓存准备语句功能不推荐 rails6 以上可以把 database中 prepared_statements 设为 false来禁用这个功能 default: defaultadapter: postgresqlencoding: unicodeprepared_statements: falserails6以下没测试如果上面的不行可以试试新建个初始化文件 # config/initializers/disable_prepared_statements.rb: db_configuration ActiveRecord::Base.configurations[Rails.env] db_configuration.merge!(prepared_statements false) ActiveRecord::Base.establish_connection(db_configuration)验证 User.all ActiveRecord::Base.connection.execute(select * from pg_prepared_statements).values[]结论小型项目中其实禁用这个功能无所谓性能几乎不影响但是大型项目中用户越多越复杂的查询语句这个功能带来的受益越大所以可以根据实际情况来决定是否禁用 2. 使select * 变为 select id, name这样的具体字段 rails7中的官方解决方案就是这样的但只能解决新增字段引起的报错 rails7中 enumerate_columns_in_select_statements 设为 true # config/application.rb module MyAppclass Application Rails::Applicationconfig.active_record.enumerate_columns_in_select_statements trueend endrails7以下没有这个配置可以用 ignored_columns来实现 class ApplicationRecord ActiveRecord::Baseself.abstract_class true#__fake_column__是自定义的不要是某个表中的字段就行如果是[:id],那么 User.all就会被解析为select name from users,没有id了self.ignored_columns [:__fake_column__] end结论这个方案存在的问题是增加字段可以完美解决但是删除字段还会出现报错比如删除name字段后预准备语句select id, name from users中的name不存在了就会报错。 删除字段可以在 User.rb 中增加 self.ignored_columns [:name], 然后先重启服务再进行部署部署时候最好把 self.ignored_columns [:name] 删掉避免以后再加回 name 字段后select 不到rails7 官方的方案也存在这个问题所以这个方案感觉很麻烦 3. 重启rails应用 预准备语句缓存的生命周期只存在于一个数据库会话中关闭数据库连接重启应用会关闭原连接重新建立新连接那原来的预准备语句缓存就会清空重启后的sql请求就会重新缓存预准备语句就能正常拿到数据。 结论重启应用会出现短暂服务502不可用当然部署应用时候也是要重启服务的也会出现502所以最好是没人访问的时候半夜进行部署这样就会尽可能少的出现PreparedStatementCacheExpired报错 4. 重写 transaction 方法 class ApplicationRecord ActiveRecord::Baseclass selfdef transaction(*args, block)retried || falsesuperrescue ActiveRecord::PreparedStatementCacheExpiredif retriedraiseelseretried trueretryendendend end重写后代码里写事务的地方改为使用 ApplicationRecord.transaction do ... end 或者 MyModel.transaction或者obj.transaction, 只要不用ActiveRecord::Base.transaction就行 结论重要提示如果在事务中有发送电子邮件、post到 API 或执行其他与外界交互的操作这可能会导致其中一些操作偶尔发生两次。这就是为什么 Rails官方不会自动执行重试而是将其留给应用程序开发人员。 我本人测试这个方法还是会继续报错 5. 手动清除预准备语句缓存 ActiveRecord::Base.connection.clear_cache!五、最终答案 没有找到一个完美的解决方案
http://www.dnsts.com.cn/news/189931.html

相关文章:

  • 网站建优化免费十大软件大全下载安装
  • 网站栏目结构南京软件定制
  • 网站建设与设计ppt模板下载二级网站 备案
  • 长春广告公司网站建设网站运营难吗
  • 湖南省建设厅网站首页有什么好的书写网站
  • 持续推进网站建设怎样做收费网站
  • 网站 备案微信公众 wordpress
  • 做私活的网站郑州短视频代运营公司
  • 宿迁网站建设多少钱最近新闻摘抄
  • 做美篇发网站wordpress为什么打开商城非常慢
  • 做招聘网站如何宣传wordpress表单拖拽
  • 福安建设网站济南网站开发培训
  • 福州品牌网站设计服装商城的网站策划书
  • 网站开发的广告词首页wordpress主题
  • 如何进行网络推广和宣传seo技术外包 乐云践新专家
  • 南昌定制网站开发wordpress问答功能
  • 怎么做pc端移动网站360免费wifi电脑版
  • 永久免费企业网站申请北京网站建设制作方案
  • 北京知名网站建设seo搜索引擎是什么
  • 赤水市住房和城乡建设局网站手机网站建设的重要性
  • 群晖nas建设网站wordpress path主题
  • 金融网站策划免费注册tk域名
  • wordpress重复安装朝阳seo排名优化培训
  • 网站建设打造wordpress站点地图无法读取
  • 三亚做网站推广中企动力地址
  • 成都电商网站制作Wordpress会员充值积分
  • 网站结构 seo微信公众平台续费步骤
  • 免费网站建设公司联系方式郑州百姓网免费发布信息
  • 意大利设计网站用wordpress 扒站
  • 南通做网站ntwsd网站建设专题