數據存儲是計算機編程中常見的問題。CPAN Persistent 類通過一個簡化數據創建、檢索和管理的通用接口,使數據存儲變得簡單。通過 面向對象 的方法,可以在項目中將 Persistent 類作為自己的數據類的父類透明地使用。 持久性介紹 所有 程序員 都有必須解決數
數據存儲是計算機編程中常見的問題。CPAN Persistent 類通過一個簡化數據創建、檢索和管理的通用接口,使數據存儲變得簡單。通過
面向對象的方法,可以在項目中將 Persistent 類作為自己的數據類的父類透明地使用。
持久性介紹 所有
程序員都有必須解決數據持久性問題的經歷。例如,對於如將文檔存入文件和將事務存入
數據庫等任務,即使最簡單的應用程序也需要大量工作。可以將數據持久性定義為程序和存儲設備之間達成的契約,該契約指定如何存儲和檢索數據。
CPAN 定義: “CPAN 是綜合 Perl 檔案
網絡。綜合:其目的是包含可能需要的所有 Perl 資料。檔案:從 1999 年 9 月至今,已有 760 兆字節。網絡:全世界有超過一百個 CPAN 鏡像站點。”
本文集中講述在作者和讀者事先都知道對象屬性的情況下,如何使對象屬性持久。本文不討論動態發現對象屬性和存儲屬性以外的特性(如行為)的主題,因為需要很多篇幅才能把這些主題講清楚。
熟悉面向對象編程、數據庫、Perl 和 Perl 繼承將對閱讀本文有幫助。
使對象屬性持久只是軟件
開發過程的一小部分。首先,必須確定持久性的
需求。需要保存什麼?需要恢復什麼?在恢復存儲的數據之前,需要手工編輯嗎?諸如此類的問題將確定軟件如何將持久數據歸檔。不幸地是,沒有一份調查表可以確定項目確切的持久性需要。軟件設計師必須通過智能設計,定義並滿足項目需求。很重要的一點是,最後的
解決方案要確實是問題的解決方案,而不只是時髦的行業詞語。例如,XML 解決數據持久性問題的能力比只用磚頭來建造房屋好不到哪裡。
持久數據示例 Perl 文件 simple 顯示了預定義的關鍵字集合如何能夠實現簡單的持久性。這種方法有很多問題:文件格式是任意的,只保存一個關鍵字集合,根本沒有對象、數據值限制到一行文本等等。
Persistent 類的簡單使用:Persistent::File
Persistent 類旨在使數據持久性變得簡單。為此,您必須閱讀文檔。對於掌握處理持久數據的方便的預制類而言,這只是很小的代價。所以,先花上幾分鐘或幾小時來做這件事,以後將節省您的時間。有關文檔和示例,請參閱 Persistent 類主頁(請參閱參考資料)。
第一個示例 first 將基於 Persistent::File 模塊文檔中給出的 simple 示例,並將描述達到持久性的步驟。
清單 1:定義數據
my %problems = (
'Homework 1, Problem 1' => [0,5,2],
'Homework 1, Problem 2' => [1,8,5],
'Homework 1, Problem 3' => [2,2,4],
'Homework 1, Problem 4' => [3,0,3],
'Homework 1, Problem 5' => [4,1,2],
);
首先,定義要存儲在數據存儲器中的數據。在 Persistent 類中,數據存儲器是抽象存儲設備,例如,它可以是文件或數據庫。該例是自包容的,但是數據也可能來自別處。
清單 2:使用 eval 來捕獲錯誤
use English;
eval
{
};
print "An error o
clearcase/" target="_blank" >ccurred: $EVAL_ERROR\n" if $EVAL_ERROR;
因為不希望程序在出現執行錯誤時終止,所以將所有操作放在 eval 語句中。English 模塊使我們可以使用 $EVAL_ERROR 、而不是 $@ 來表示錯誤消息。
清單 3:定義數據存儲器
# 從文件創建持久對象
my $equation = new Persistent::File('variables.txt');
我們在這裡創建了新的 Persistent::File 對象,其內容將存儲在文件 variables.txt 中。
清單 4:定義屬性
$equation->add_attribute('name', 'ID', 'VarChar', undef, 80);
$equation->add_attribute('x', 'Persistent', 'Number', 0, 10);
$equation->add_attribute('y', 'Persistent', 'Number', 0, 10);
$equation->add_attribute('z', 'Persistent', 'Number', 0, 10);
$equation->add_attribute('answer', 'Transient', 'Number', undef, 10);
我們創建了五個屬性:一個唯一標識、三個持久數據成員和一個非持久(暫時)數據成員。Persistent 類將自動創建必要的函數(例如,$equation->answer())來訪問數據成員。
清單 5:清除數據存儲器
$equation->restore_all();
$equation->delete while $equation->restore_next();
restore_all 方法檢索整個數據存儲器的內容。restore_where 和 restore 方法分別用來選擇符合某些標准的對象和單一對象。delete 方法除去當前等式,restore_next 方法移至下一個恢復的對象。
清單 6:存儲對象數據
# 現在將問題存儲到數據存儲器
foreach my $key (keys %problems)
{
$equation->clear;
$equation->name($key);
$equation->x($problems{$key}->[0]);
$equation->y($problems{$key}->[1]);
$equation->z($problems{$key}->[2]);
$equation->save;
}
我們清除舊屬性,設置新屬性,並將對象存儲到數據存儲器。因為剛剛清除過數據存儲器,所以我們知道,不會有 name 鍵沖突,但是,通常要進行檢查,以便在用 save 方法試圖重寫現有鍵時不會導致異常。
清單 7:檢索 homework 1 等式
# 在數據存儲器中查詢 homework 1 中的等式
$equation->restore_where(qq{name =~ 'Homework 1'});
while ($equation->restore_next())
{
# do something with each equation
}
最後,遍歷數據存儲器,查找那些 name 鍵包含字符串 'Homework 1' 的對象,然後對這些對象中的每一個執行操作。
這個例子本身並不使人難忘,但是,請考慮:
現在可以將任何數量的屬性添加到持久對象
可以有選擇地檢索任何存儲的對象
任何知道對象屬性的其它程序都可以使用同樣的數據存儲器(這方面的詳細信息在“從 Persistent 類繼承”中)。
通過使用預制的模塊,我們已經用簡單的方法解決了棘手的問題。這很有趣。
使用 Persistent::DBI
請閱讀 Persistent::DBI 文檔,來獲得有關 Persistent::DBI 和 Persistent::Base 類之間區別的最新討論。基本上,Persistent::DBI 允許我們連接到數據庫,並在建立連接之後,象其它 Persistent::Base 類那樣操作。可以將清單 3 中顯示的代碼行用以下替代:
清單 8:定義要作為數據庫的數據存儲器
my $database = 'test_database';
my $host = 'db_host';
my $user = 'dali';
my $password = 'MeltingClocks';
my $table = 'persistence_test_table';
my $equation = new Persistent::
MySQL(
"DBI:
mysql:database=$database;host=$hostname",
$user,
$password,
$table);
請注意,Persistent::MySQL 是 Persistent::DBI 的子類。只使用 Persistent::DBI 本身沒什麼用,必須使用特定於我們數據庫的模塊。令人欣慰的是,除了通過名稱來引用 Persistent::MySQL 之外(例如 use 語句和 new 語句),在切換數據庫時不需要更改代碼。有關通過使用繼承來將程序與數據庫選項隔離的方法,請參閱“從 Persistent 類繼承”。
清單 9:不同的查詢語法
# 在數據存儲器中查詢 homework 1 中的等式
$equation->restore_where(qq{name LIKE '%Homework 1%'});
因為現在使用的是 SQL SELECT 語句,所以 restore_where 自變量從 Perl 模式匹配改成 SQL WHERE 子句。
表必須事先存在,Persistent::MySQL 將不創建表。編寫一個單獨的程序來創建表,或者繼承時在類中添加必需的功能。
表必需與屬性定義匹配,例如,等式表的主數據庫鍵必須也是 Persistent 類的主鍵。(這是在實現工作之前必須有良好設計的情況。)
清單 8 和清單 9 只顯示了為使用 SQL 而必須在 first 中做的更改。腳本 second 包含這些更改。
從 Persistent 類繼承 文件 Equation.pm 包含從 Persistent::DBI 類繼承所需的所有代碼。很簡單,不是嗎?基本上,在本地 initialize 方法中執行 add_attribute 調用。在這裡還可以做更多操作:例如,如果數據庫中不存在表,則創建表。但是,基本方法很簡單。
安全性注意事項: 通常,只有數據庫中的特權用戶才能創建表,所以最好與數據庫管理員討論表的創建,以確保不會因為安全性策略而導致您辛苦創建的表無法工作。
清單 10:Equation.pm 模塊,擴展 Persistent::MySQL
#! /usr/bin/perl -w
package Equation;
@ISA = qw(Persistent::MySQL);
use strict;
use Persistent::MySQL;
sub initialize
{
my $self = shift;
$self->SUPER::initialize(@_);
# define attributes of the object (the contract)
# this is the primary object identifier key, a 10-character name
$self->add_attribute('name', 'ID', 'VarChar', undef, 80);
# x, y, and z are persistent numbers with default values of 0 and length of 10
$self->add_attribute('x', 'Persistent', 'Number', 0, 10);
$self->add_attribute('y', 'Persistent', 'Number', 0, 10);
$self->add_attribute('z', 'Persistent', 'Number', 0, 10);
# this attribute will NOT be saved
$self->add_attribute('answer', 'Transient', 'Number', undef, 10);
}
1;
請注意 @ISA 這行,它告述 Perl:Equation 類從 Persistent::SQL 繼承。
文件 third 是文件 second 去掉 add_attribute 行和 "use Persistent::MySQL",而添加了清單 11 的結果:
清單 11:新的 use 語句
use lib '.';
use Equation;
這告訴 Perl 使用 Equation 模塊 equation,並在當前目錄中查找 Equation.pm。
這裡顯示的方法可以輕易擴展到復雜得多的問題。參考資料中的信息應該足以使您達到此目標。
結束語 CPAN Persistent 類是您搜索數據持久性解決方案時的有力幫手。通過使用,您將發現,使用 Persistent 類的最好方法是繼承它們。請記住,在實現成功的數據持久性時,好的設計和屬性的清晰定義與 Persistent 類同等重要。