|
.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オブジェクトはその更新を認識することができないので注意すること。
|
generated by
|
|
Insider.NET 記事ランキング
本日
月間