.NET TIPS

[ASP.NET]データベース更新のタイミングでキャッシュを破棄するには?

山田 祥寛
2004/09/10

 「TIPS:[ASP.NET]キャッシュ破棄のタイミングを指定するには?」では、ファイルやほかのキャッシュが変更されたタイミングで、現在のキャッシュを破棄/更新する方法について紹介した。しかし、キャッシュ・データが必ずしもファイル・システム上のファイルを基に作成されているとは限らない。例えば、データベース・サーバから読み込んだ基本情報を基にキャッシュ・データが作成されている場合、データベースのデータが変更されたタイミングでキャッシュをリフレッシュさせる必要がある。

 そこで本稿では、先のTIPSでも紹介したCacheDependencyクラス(System.Web.Caching名前空間)を利用して、データベース内のデータを基に作られたキャッシュを、データベース更新のタイミングでリアルタイムに破棄/更新する方法について紹介する。

 具体的なコードは以下のとおり。このプログラムは、データベースの更新時に特定のファイルも更新しておき、データベースから取得したキャッシュ・データの破棄/更新のタイミングを、そのファイルの更新に依存させるというものである。

 なお、以下のサンプル・プログラムではDataGridコントロールを用いた編集を扱っているが、本稿では詳説しない。DataGridコントロール上でのデータ更新については、「TIPS:[ASP.NET]DataGridコントロールで編集を可能にするには?」が詳しいので、そちらを併せて参照いただきたい。

<%@ Page ContentType="text/html" Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="Server">
DataSet objDs=new DataSet();
void BindData() {
  // キャッシュ"Books"が存在する場合はキャッシュの内容を
  // 存在しない場合はbooksテーブルの内容をデータセットに読み込み、
 
// 同時にキャッシュにセット
  if(Cache.Get("Books")==null){
    SqlConnection db=new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet");
    SqlDataAdapter objDa=new SqlDataAdapter("SELECT isbn,title,price,publish,published FROM books ORDER BY published DESC",db);
    db.Open();
    objDa.Fill(objDs,"books");
    // ダミー・テキストcheck.txtに対して、依存関係ポリシーを設定
    CacheDependency objCd=new CacheDependency(Server.MapPath("check.txt"));
    Cache.Insert("Books",objDs,objCd);
    db.Close();
  } else {
    objDs=(DataSet)Cache.Get("Books");
  }
  DataBind();
}
void Page_Load(Object sender, EventArgs e) {
  if(!Page.IsPostBack){BindData();}
}
void objGrd_EditCommand(Object sender, DataGridCommandEventArgs e) {
  objGrd.EditItemIndex=e.Item.ItemIndex;
  BindData();
}
void objGrd_CancelCommand(Object sender, DataGridCommandEventArgs e) {
  objGrd.EditItemIndex=-1;
  BindData();
}
void objGrd_UpdateCommand(Object sender, DataGridCommandEventArgs e) {
  // データベース更新のタイミングでcheck.txtを更新
  StreamWriter objSw=new StreamWriter(Server.MapPath("check.txt"),
false,Encoding.GetEncoding("Shift_JIS"));
  objSw.WriteLine(DateTime.Now.ToString());
  objSw.Close();
  String strKey=(String)objGrd.DataKeys[e.Item.ItemIndex];
  TextBox objTitle=(TextBox)e.Item.Cells[1].Controls[0];
  TextBox objPrice=(TextBox)e.Item.Cells[2].Controls[0];
  TextBox objPublish=(TextBox)e.Item.Cells[3].Controls[0];
  TextBox objPublished=(TextBox)e.Item.Cells[4].Controls[0];
  SqlConnection objDb=new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet");
  SqlCommand objCom=new SqlCommand("UPDATE books SET title=@title, price=@price, publish=@publish, published=@published WHERE isbn=@isbn",objDb);
  objDb.Open();
  objCom.Parameters.Add("@title",objTitle.Text);
  objCom.Parameters.Add("@price",objPrice.Text);
  objCom.Parameters.Add("@publish",objPublish.Text);
  objCom.Parameters.Add("@published",objPublished.Text);
  objCom.Parameters.Add("@isbn",strKey);
  objCom.ExecuteNonQuery();
  objDb.Close();
  objGrd.EditItemIndex=-1;
  BindData();
}
</script>
<html>
<head>
<title>キャッシュの活用</title>
</head>
<body>
<form runat="Server">
  <asp:DataGrid id="objGrd" runat="Server"
    DataSource="<%# objDs %>" AutoGenerateColumns="False"
    OnEditCommand="objGrd_EditCommand" OnUpdateCommand="objGrd_UpdateCommand"
    OnCancelCommand="objGrd_CancelCommand" DataKeyField="isbn">
    <HeaderStyle BackColor="#BB2255" ForeColor="white" />
    <ItemStyle BackColor="#FFeeEE" />
    <AlternatingItemStyle BackColor="#FFDDDD" />
    <Columns>
      <asp:BoundColumn DataField="isbn" HeaderText="ISBNコード"
        ReadOnly="True" />
      <asp:BoundColumn DataField="title" HeaderText="書名" />
      <asp:BoundColumn DataField="price" HeaderText="価格" />
      <asp:BoundColumn DataField="publish" HeaderText="出版社" />
      <asp:BoundColumn DataField="published" HeaderText="配本日" />
      <asp:EditCommandColumn HeaderText="編集" ButtonType="PushButton"
        EditText="編集" UpdateText="更新" CancelText="取消" />
    </Columns>
  </asp:DataGrid>
</form>
</body>
</html>
データベース更新のタイミングでキャッシュを更新するサンプル・プログラム(C#)
 
<%@ Page ContentType="text/html" Language="VB" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="Server">
Dim objDs As New DataSet()
Sub BindData()
  ' キャッシュ"Books"が存在する場合はキャッシュの内容を
  ' 存在しない場合はbooksテーブルの内容をデータセットに読み込み、
 
' 同時にキャッシュにセット
  If IsDbNull(Cache.Get("Books")) Or IsNothing(Cache.Get("Books")) Then
    Dim db As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet")
    Dim objDa As New SqlDataAdapter("SELECT isbn,title,price,publish,published FROM books ORDER BY published DESC",db)
    db.Open()
    objDa.Fill(objDs,"books")
    ' ダミー・テキストcheck.txtに対して、依存関係ポリシーを設定
    Dim objCd As New CacheDependency(Server.MapPath("check.txt"))
    Cache.Insert("Books",objDs,objCd)
    db.Close()
  Else
    objDs=Cache.Get("Books")
  End If
  DataBind()
End Sub
Sub Page_Load(sender As Object, e As EventArgs)
  If Not Page.IsPostBack Then BindData()
End Sub
Sub objGrd_EditCommand(sender As Object, e As DataGridCommandEventArgs)
  objGrd.EditItemIndex=e.Item.ItemIndex
  BindData()
End Sub
Sub objGrd_CancelCommand(sender As Object, e As DataGridCommandEventArgs)
  objGrd.EditItemIndex=-1
  BindData()
End Sub
Sub objGrd_UpdateCommand(sender As Object, e As DataGridCommandEventArgs)
  ' データベース更新のタイミングでcheck.txtを更新
  Dim objSw As New StreamWriter(Server.MapPath("check.txt"),
False,Encoding.GetEncoding("Shift_JIS"))
  objSw.WriteLine(DateTime.Now.ToString())
  objSw.Close()
  Dim strKey As String =CType(objGrd.DataKeys(e.Item.ItemIndex),String)
  Dim objTitle As TextBox=CType(e.Item.Cells(1).Controls(0),TextBox)
  Dim objPrice As TextBox=CType(e.Item.Cells(2).Controls(0),TextBox)
  Dim objPublish As TextBox=CType(e.Item.Cells(3).Controls(0),TextBox)
  Dim objPublished As TextBox=CType(e.Item.Cells(4).Controls(0),TextBox)
  Dim objDb As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet")
  Dim objCom As New SqlCommand("UPDATE books SET title=@title, price=@price, publish=@publish, published=@published WHERE isbn=@isbn",objDb)
  objDb.Open()
  objCom.Parameters.Add("@title",objTitle.Text)
  objCom.Parameters.Add("@price",objPrice.Text)
  objCom.Parameters.Add("@publish",objPublish.Text)
  objCom.Parameters.Add("@published",objPublished.Text)
  objCom.Parameters.Add("@isbn",strKey)
  objCom.ExecuteNonQuery()
  objDb.Close()
  objGrd.EditItemIndex=-1
  BindData()
End Sub
</script>
<html>
<head>
<title>キャッシュの活用</title>
</head>
<body>
<form runat="Server">
  <asp:DataGrid id="objGrd" runat="Server"
    DataSource="<%# objDs %>" AutoGenerateColumns="False"
    OnEditCommand="objGrd_EditCommand" OnUpdateCommand="objGrd_UpdateCommand"
    OnCancelCommand="objGrd_CancelCommand" DataKeyField="isbn">
    <HeaderStyle BackColor="#BB2255" ForeColor="white" />
    <ItemStyle BackColor="#FFeeEE" />
    <AlternatingItemStyle BackColor="#FFDDDD" />
    <Columns>
      <asp:BoundColumn DataField="isbn" HeaderText="ISBNコード"
        ReadOnly="True" />
      <asp:BoundColumn DataField="title" HeaderText="書名" />
      <asp:BoundColumn DataField="price" HeaderText="価格" />
      <asp:BoundColumn DataField="publish" HeaderText="出版社" />
      <asp:BoundColumn DataField="published" HeaderText="配本日" />
      <asp:EditCommandColumn HeaderText="編集" ButtonType="PushButton"
        EditText="編集" UpdateText="更新" CancelText="取消" />
    </Columns>
  </asp:DataGrid>
</form>
</body>
</html>
データベース更新のタイミングでキャッシュを更新するサンプル・プログラム(VB.NET)

 Cacheオブジェクトの有無によって、新たにデータセットを作成するか、既存のキャッシュからデータセットを取り出すかを判定している部分は、「TIPS:[ASP.NET]データセットをキャッシングするには?」でも紹介したとおりだ。

 ここで注目していただきたいのは、DataGridコントロール上で[更新]ボタンがクリックされたときに実行されるobjGrd_UpdateCommandイベント・プロシージャの部分だ。本来の更新ロジックに先立って、check.txtという名前のダミー・ファイルに対して現在時刻を書き込んでいるのがお分かりになるだろうか。この部分がミソなのだ。Cacheオブジェクトが直接にデータベースの更新を認識できないならば、データベース更新のタイミングに合わせて、(Cacheオブジェクトが認識可能な)ファイルの方を更新してやればよい。

 あとは、「TIPS:[ASP.NET]キャッシュ破棄のタイミングを指定するには?」でも紹介したように、check.txtファイルに対して依存関係ポリシーを設定すればよい。これによって、データベース更新をCacheオブジェクトが間接的に認識し、リアルタイムにデータをリフレッシュすることができるというわけだ。

 それでは、実際に挙動を確かめてみよう。確かに[更新]ボタンをクリックしたタイミングで、データベースの変更内容が画面上にも反映されているのが確認できるはずだ(キャッシュ機構がきちんと働いているかどうかを疑われる方は、逆に、コード中の太字部分をコメントアウトしてみればよい。データベースを更新しても、その内容が即座に反映されないことが確認できるはずだ)。

【キャッシュ更新前】

【キャッシュ更新後】

データベース更新のタイミングでキャッシュを更新するプログラムの実行例
[更新]ボタンをクリックしたタイミングで、更新内容がDataGridコントロール上に反映される。

 ただし、本サンプル・プログラムでは、あくまでテキスト・ファイルにダミーの依存関係ポリシーを持たせているにすぎない。例えば、データベースをアプリケーションからではなく、データベース・サーバ上で直接に更新した場合には、Cacheオブジェクトはその更新を認識することができないので注意すること。End of Article

カテゴリ:Webフォーム 処理対象:キャッシング
使用キーワード:Cacheオブジェクト
使用ライブラリ:CacheDependencyクラス(System.Web.Caching名前空間)
関連TIPS:[ASP.NET]キャッシュ破棄のタイミングを指定するには?
関連TIPS:[ASP.NET]DataGridコントロールで編集を可能にするには?
関連TIPS:[ASP.NET]データセットをキャッシングするには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]キャッシュ破棄のタイミングを指定するには?
[ASP.NET]データセットをキャッシングするには?
[ASP.NET]リクエスト・パラメータごとにページをキャッシングするには?
[ASP.NET AJAX]UpdatePanelAnimationコントロールで部分更新前後にアニメーションを実行するには?
[ASP.NET]DataGridコントロールで編集を可能にするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間