30、Rails 缓存与数据库迁移:提升性能与管理数据库架构

Rails 缓存与数据库迁移:提升性能与管理数据库架构

1. 片段缓存

在 Rails 中,对于其他请求,若调用 stale? fresh_when 方法,Rails 会为你生成必要的 HTTP 头。这两个方法都接受 :last_modified 时间戳(UTC 格式)和 :etag etag 可以是响应所依赖的对象,也可以是这类对象的数组,这些对象需要能响应 cache_key to_param 方法,ActiveRecord 会处理好这些。

1.1 stale? fresh_when 方法的使用

  • stale? 方法 :通常在涉及自定义渲染的 if 语句中使用,示例代码如下:
def show
  @article = Article.find(params[:id])
  if stale?(:etag=>@article, :last_modified=>@article.created_at.utc)
    # ...
  end
end
  • fresh_when 方法 :在使用默认渲染时更方便,因为它会为你生成 304 Not Modified 响应,示例代码如下:
def show
  fresh_when(:etag=>@article, :last_modified=>@article.created_at.utc)
end

1.2 页面片段缓存的作用

在动态网站中,缓存页面的部分内容非常有用。例如,博客应用可能会为每个用户定制问候语和侧边栏,这种情况下无法使用页面缓存,但文章列表在不同用户之间不会改变,就可以使用片段缓存。只需构建一次显示文章的 HTML,然后将其包含在提供给每个用户的定制页面中。

1.3 示例代码说明

1.3.1 控制器代码
class BlogController < ApplicationController
  def list
    @dynamic_content = Time.now.to_s
  end
end
1.3.2 模拟的 Article 类
class Article
  attr_reader :body
  def initialize(body)
    @body = body
  end
  def self.find_recent
    [ new("It is now #{Time.now.to_s}"),
      new("Today I had pizza"),
      new("Yesterday I watched Spongebob"),
      new("Did nothing on Saturday") ]
  end
end
1.3.3 视图模板代码
<%= @dynamic_content %>
<!-- Here's dynamic content. -->
<% cache do %>
  <!-- Here's the content we cache -->
  <ul>
    <% for article in Article.find_recent %>
      <li><p><%= h(article.body) %></p></li>
    <% end %>
  </ul>
<% end %>
<!-- End of cached content -->
<%= @dynamic_content %>
<!-- More dynamic content. -->

这里的 cache 方法是关键,该方法关联的代码块内生成的所有输出都会被缓存。下次访问该页面时,动态内容仍会渲染,但代码块内的内容将直接从缓存中获取,不会重新生成。

1.4 避免将应用级代码放入视图模板的方法

可以让动作测试缓存片段是否存在,如果存在,动作就绕过昂贵的数据库操作,示例代码如下:

class Blog1Controller < ApplicationController
  def list
    @dynamic_content = Time.now.to_s
    unless read_fragment(:action => 'list')
      logger.info("Creating fragment")
      @articles = Article.find_recent
    end
  end
end

视图模板代码如下:

<%= @dynamic_content %> <!-- Here's dynamic content. -->
<% cache do %>
  <!-- Here's the content we cache -->
  <ul>
    <% for article in @articles %>
      <li><p><%= h(article.body) %></p></li>
    <% end %>
  </ul>
<% end %>
<!-- End of the cached content -->
<%= @dynamic_content %> <!-- More dynamic content. -->

1.5 过期缓存片段

当文章更新时,缓存的文章列表版本会过时,需要使用 expire_fragment 方法使其过期。默认情况下,片段使用渲染页面的控制器和动作名称进行缓存。例如,要使文章列表的缓存片段过期,控制器可以调用:

expire_fragment(:controller => 'blog', :action => 'list')

如果页面上有多个片段,可以通过向 cache 方法添加参数(使用 url_for 约定)来覆盖片段的名称,示例代码如下:

<% cache(:action => 'list', :part => 'articles') do %>
  <ul>
    <% for article in @articles %>
      <li><p><%= h(article.body) %></p></li>
    <% end %>
  </ul>
<% end %>
<% cache(:action => 'list', :part => 'counts') do %>
  <p>
    There are a total of <%= @article_count %> articles.
  </p>
<% end %>

在控制器中,可以传递相同的参数给 expire_fragment 来删除特定的片段,示例代码如下:

class Blog2Controller < ApplicationController
  def list
    @dynamic_content = Time.now.to_s
    @articles = Article.find_recent
    @article_count = @articles.size
  end
  def edit
    # do the article editing
    expire_fragment(:action => 'list', :part => 'articles')
    redirect_to(:action => 'list')
  end
  def delete
    # do the deleting
    expire_fragment(:action => 'list', :part => 'articles')
    expire_fragment(:action => 'list', :part => 'counts')
    redirect_to(:action => 'list')
  end
end

expire_fragment 方法还可以接受一个正则表达式作为参数,用于使名称匹配的所有片段过期,示例代码如下:

expire_fragment(%r{/blog2/list.*})

1.6 缓存技术总结

通过学习,我们掌握了三种可使网站响应更快的技术:
- 缓存整个页面,避免处理可由缓存提供服务的请求时的所有 Ruby、Rails 和数据库开销,适用于高流量且很少更改的页面。
- 缓存控制器动作的结果,避免渲染和数据库开销,适用于需要运行过滤器(通常用于身份验证)的情况。
- 缓存页面片段,让我们能够完全控制优化和动态内容生成之间的平衡。

2. 数据库迁移

2.1 迁移的概念和作用

在 Rails 应用开发中,数据库架构会随着开发的进行不断演变,如添加表、重命名列等。Rails 通过迁移来实现这些步骤,迁移是应用程序 db/migrate 目录中的 Ruby 源文件。

2.2 创建和运行迁移

2.2.1 迁移文件的命名

每个迁移文件的名称以数字(通常是十四位)和下划线开头,这些数字是迁移的版本号,即创建迁移时的协调世界时(UTC)时间戳。例如, 20110211000001_create_products.rb

2.2.2 生成迁移文件的方法
  • 模型生成器 :创建与模型关联的表的迁移(除非指定 --skip-migration 选项),示例命令如下:
depot> rails generate model discount

会生成 db/migrate/20110211000010_create_discounts.rb 文件。
- 单独生成迁移 :示例命令如下:

depot> rails generate migration add_price_column

会生成 db/migrate/20110211000011_add_price_column.rb 文件。

2.2.3 运行迁移

使用 db:migrate Rake 任务运行迁移,示例命令如下:

depot> rake db:migrate

运行迁移时,Rails 会维护一个名为 schema_migrations 的表,该表只有一个 version 列,每个成功应用的迁移都会在该表中添加一行。运行 rake db:migrate 时,任务会先查找 schema_migrations 表,如果不存在则创建,然后检查 db/migrate 目录中的所有迁移文件,跳过版本号已在数据库中的文件,应用其余的迁移。

2.2.4 强制数据库到特定版本

可以通过为 rake db:migrate 命令提供 VERSION= 参数来强制数据库到特定版本,示例命令如下:

depot> rake db:migrate VERSION=20110211000009

如果指定的版本号大于尚未应用的迁移版本号,这些迁移将被应用;如果小于 schema_migrations 表中列出的一个或多个版本号,Rails 会撤销相应的迁移,直到没有超过指定版本号的版本为止。

2.2.5 重新执行迁移

可以使用 rake db:migrate:redo 任务重新执行一个或多个迁移,默认情况下会回滚一个迁移并重新运行,要回滚多个迁移,可以传递 STEP= 参数,示例命令如下:

depot> rake db:migrate:redo STEP=3

2.3 迁移的结构

迁移是 ActiveRecord::Migration 类的子类,创建的类应至少包含 up down 两个类方法,示例代码如下:

class SomeMeaningfulName < ActiveRecord::Migration
  def self.up
    # ...
  end
  def self.down
    # ...
  end
end

类名在所有大写字母转换为小写并加上下划线后,必须与文件名中版本号之后的部分匹配。 up 方法负责应用迁移的架构更改, down 方法负责撤销这些更改。例如,添加 e_mail 列到 orders 表的迁移代码如下:

class AddEmailToOrders < ActiveRecord::Migration
  def self.up
    add_column :orders, :e_mail, :string
  end
  def self.down
    remove_column :orders, :e_mail
  end
end

2.4 列类型和选项

2.4.1 列类型

add_column 方法的第三个参数指定数据库列的类型,Rails 迁移使用逻辑类型来隔离底层数据库类型系统,不同数据库对同一逻辑类型的映射不同。支持的类型有 :binary :boolean :date :datetime :decimal :float :integer :string :text :time :timestamp

2.4.2 列选项

定义大多数列时可以指定最多三个选项,十进制列还可以额外指定两个选项,常见选项如下:
| 选项 | 说明 |
| ---- | ---- |
| :null => true or false | 如果为 false ,底层列会添加 not null 约束(如果数据库支持) |
| :limit => size | 设置字段大小的限制,会在数据库列类型定义后追加 (size) |
| :default => value | 设置列的默认值,默认值在运行迁移时计算一次 |
| :precision | 对于十进制列,指定要存储的有效数字位数 |
| :scale | 对于十进制列,确定小数点在这些数字中的位置 |

示例列定义代码如下:

add_column :orders, :attn, :string, :limit => 100
add_column :orders, :order_type, :integer
add_column :orders, :ship_class, :string, :null => false, :default => 'priority'
add_column :orders, :amount, :decimal, :precision => 8, :scale => 2

2.5 重命名和更改列

2.5.1 重命名列

可以使用 rename_column 方法重命名数据库列,示例代码如下:

class RenameEmailColumn < ActiveRecord::Migration
  def self.up
    rename_column :orders, :e_mail, :customer_email
  end
  def self.down
    rename_column :orders, :customer_email, :e_mail
  end
end

重命名不会破坏与列关联的现有数据,但并非所有适配器都支持重命名。

2.5.2 更改列

使用 change_column 方法更改列的类型或选项,示例代码如下:

def self.up
  change_column :orders, :order_type, :string
end

但从字符串列转换为整数列可能会有问题,例如下面的代码可能会有问题:

def self.down
  change_column :orders, :order_type, :integer
end

通过以上内容,我们了解了 Rails 中的片段缓存和数据库迁移的相关知识,这些技术可以帮助我们提升应用的性能和管理数据库架构。

2.6 迁移操作流程图

下面是一个 mermaid 格式的流程图,展示了迁移操作的主要流程:

graph LR
    A[开始] --> B[运行 rake db:migrate]
    B --> C{schema_migrations 表存在?}
    C -- 否 --> D[创建 schema_migrations 表]
    C -- 是 --> E[检查 db/migrate 目录中的迁移文件]
    D --> E
    E --> F{版本号是否已在数据库中?}
    F -- 是 --> G[跳过该迁移文件]
    F -- 否 --> H[应用迁移]
    H --> I[在 schema_migrations 表中添加一行]
    G --> J{是否还有迁移文件?}
    I --> J
    J -- 是 --> E
    J -- 否 --> K[结束]

2.7 迁移的注意事项

  • 迁移顺序 :在多用户使用版本控制系统存储迁移文件时,可能会出现迁移文件版本号顺序不一致的情况。此时运行迁移可能会导致迁移顺序混乱,因此需要确保迁移之间相互独立,或者将数据库回滚到之前的状态,然后按顺序应用迁移。
  • 数据完整性 :在进行列的重命名和更改操作时,要特别注意数据的完整性。例如,重命名列时虽然不会破坏现有数据,但某些数据库适配器可能不支持该操作;更改列类型时,可能会出现数据转换问题,如从字符串列转换为整数列时,非数字字符串可能会导致错误。

3. 总结与应用建议

3.1 缓存技术总结

  • 页面缓存 :适用于高流量且很少更改的页面,能显著减少 Ruby、Rails 和数据库的开销,提高响应速度。例如,电商网站的产品目录页面,由于产品信息更新频率较低,可以使用页面缓存。
  • 动作缓存 :在需要运行过滤器(通常用于身份验证)的情况下,缓存控制器动作的结果,避免渲染和数据库开销。比如,用户登录后的个人信息页面,每次访问都需要验证用户身份,可以使用动作缓存。
  • 片段缓存 :提供了对优化和动态内容生成的精细控制。对于动态网站中部分内容变化频繁,而部分内容相对稳定的情况,如博客文章列表和动态问候语的组合,使用片段缓存可以在保证页面动态性的同时提高性能。

3.2 数据库迁移总结

  • 迁移的灵活性 :Rails 的迁移机制允许开发者在开发过程中灵活地修改数据库架构,如添加表、重命名列等,适应不断变化的需求。
  • 版本控制 :迁移文件的版本号和 schema_migrations 表的使用,确保了数据库架构的版本控制,方便团队协作和项目的维护。
  • 数据处理 :在进行迁移操作时,要充分考虑数据的完整性和兼容性,避免因迁移操作导致数据丢失或错误。

3.3 应用建议

  • 缓存策略 :根据页面的特点和访问频率,合理选择缓存技术。对于静态页面或变化较少的页面,优先使用页面缓存;对于需要身份验证的页面,考虑使用动作缓存;对于页面中部分动态内容和静态内容混合的情况,使用片段缓存。
  • 迁移管理 :在开发过程中,及时创建迁移文件来记录数据库架构的变化。在团队协作时,定期同步迁移文件,确保数据库架构的一致性。同时,在进行复杂的迁移操作前,先在测试环境中进行测试,避免对生产环境造成影响。

通过合理运用 Rails 的缓存技术和数据库迁移机制,可以有效提升应用的性能和可维护性,为用户提供更流畅的体验。在实际开发中,要根据具体需求和场景,灵活选择和组合这些技术,不断优化应用的性能和数据库架构。

基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样统计,通过模拟系统元件的故障修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值