?? 實體對象的抽象以及一種基于數(shù)據(jù)庫的實現(xiàn)(轉(zhuǎn)).txt
字號:
PreparedStatement ps=_conn.prepareStatement ("insert into account(accountid,name) values(?,?)");
ps.setInt (1,accountId);
ps.setString (2,name);
ps.execute();
ps.close();
super.insert(); //注意,重載insert方法必須要有這一句
}
//重定義這個方法,執(zhí)行實際的sql命令
public void update() throws SQLException {
PreparedStatement ps=_conn.prepareStatement ("update account set accountid=?, name=? Where accountid=?");
ps.setInt(1,accountId);
ps.setString(2,name);
ps.setInt(3,accountId);
ps.execute();
ps.close();
super.update(); //注意,重載update方法必須要有這一句
}
//重定義這個方法,執(zhí)行實際的sql命令
public void delete() throws SQLException {
if (isDbStored()) {
PreparedStatement ps=_conn.prepareStatement("delete account where accountid = ? ");
ps.setInt(1,accountId);
ps.execute();
ps.close();
}
super.delete();
}
//下面這個方法把一個ResultSet轉(zhuǎn)換成對象中的屬性,下面所有的getByXXX方法都會用到這個方法。
public void _setAttribute(java.sql.ResultSet rs) throws SQLException {
accountId=rs.getInt(1);
name=rs.getString(2);
super._setAttribute(rs); //注意,重載_setAttribute方法必須要有這一句
}
//根據(jù)條件取得對象
public boolean getByAccountId(int id) throws SQLException {
clearDbStored();
PreparedStatement ps=_conn.prepareStatement ("select AccountId,Name from account where AccountId=?");
//這里的select語句得到的結(jié)果集必須與上面的_setAttribute方法假定的結(jié)果集一致
ps.setInt(1,id);
ResultSet rs=ps.executeQuery();
if (rs.next())
_setAttribute(rs);
rs.close();
ps.close();
return (isDbStored());
}
//根據(jù)條件取得對象并企圖修改
public boolean getByAccountIdForUpdate(int id) throws SQLException {
clearDbStored();
PreparedStatement ps=_conn.prepareStatement ("select AccountId,Name from account where AccountId=? for update");
ps.setInt(1,id);
ResultSet rs=ps.executeQuery();
if (rs.next())
_setAttribute(rs);
rs.close();
ps.close();
return (isDbStored());
}
}
上面說到的對象中,只有g(shù)etByXXX()這樣的方法,這種方法只會返回唯一的對象,這時,也不用保存數(shù)據(jù)庫結(jié)果集,如果出現(xiàn)返回一組對象的情況,就不能不保存結(jié)果集了,這時需要一個輔助類來實現(xiàn)。這個輔助類稱為對象瀏覽器,下面定義對象瀏覽器。
import java.sql.*;
/**所有實體對象的瀏覽器的父類*/
abstract class EntityBrowser {
protected ResultSet _rs;
protected Connection _conn;
protected boolean _hasMoreElement;
/**瀏覽器是否還有下一個記錄*/
public boolean hasMoreElement() throws SQLException{
return _hasMoreElement;
}
/**返回下一個記錄,子類必須重載這個函數(shù)*/
abstract public Object nextElement() throws SQLException;
/**關(guān)閉這個瀏覽器*/
public void close () throws SQLException{
_rs.getStatement().close();
}
/**瀏覽器構(gòu)造函數(shù),指定一個數(shù)據(jù)庫連接*/
public EntityBrowser(ResultSet rs) throws SQLException {
_rs=rs;
_conn=_rs.getStatement().getConnection();
_hasMoreElement=_rs.next();
}
//子類重載nextElement()時調(diào)用這個方法
protected Object _nextEntityObj(EntityObject eo) throws SQLException {
if (_hasMoreElement) {
eo._setAttribute(_rs);
} else eo=null;
_hasMoreElement=_rs.next();
return (eo);
}
}
有了EntityBrowser類后,我們來修改剛才定義的Account類。第一步是要在Account類里定義一個私有的EntityBrowser子類,這個子類只要定義一個構(gòu)造函數(shù)并重載nextElement()方法即可。這里使用了在一個類里定義另一個類的技巧,這個技巧在java的容器類庫中經(jīng)常使用。第二步是在Account類中增加一個方法getAllByXX(),返回一組實體對象的方法名常用getAll打頭。請看以下修改的代碼片段。
import java.sql.*;
public class Account extends EntityObject {
。。。
/*以下是新修改的代碼*/
//定義一個子類
private class AccountBrowser extends EntityBrowser {
AccountBrowser (ResultSet rs) throws SQLException { super(rs); }
Public Object nextElement() throws SQLException{
Account ac=new Account(_conn);
return (_nextEntityObj(ac));
}
}
//下面是實體對象的方法
public EntityBrowser getAll() throws SQLException {
PreparedStatement ps=_conn.prepareStatement("select AccountId,Name from account ");
ResultSet rs=ps.executeQuery();
return (new AccountBrowser(rs));
}
public EntityBrowser getAllByName(String name) throws SQLException {
PreparedStatement ps=_conn.prepareStatement(“select AccountId,Name from account where name like ?”;
ps.setString(1,name);
ResultSet rs=ps.executeQuery();
return (new AccountBrowser(rs));
}
接下來,討論一下數(shù)據(jù)表的連接關(guān)系,關(guān)系數(shù)據(jù)庫主要有一對一,一對多,多對多,多對一的關(guān)系。比如教師和學(xué)生之間的教課關(guān)系,這是一種多對多的關(guān)系。有的關(guān)系是有自己的屬性,比如教課時間,我們可以把所有的關(guān)系都看作一個實體對象。但是為了簡化程序,對于那些沒有自己屬性的一對一,一對多關(guān)系我們可以把它簡化成父、子表的關(guān)系。表示數(shù)據(jù)庫中的主表和子表有兩種方法。
一種方法把子表和主表看作一個實體對象,子表用Vector或HashTable這樣的Collection定義成主表的一個屬性,在_setAttribute方法中,再執(zhí)行一次sql查詢,把查詢出的子表數(shù)據(jù)放入collection中。同時還要修改insert,update方法,使得主表的實體對象每次數(shù)據(jù)插入或修改時都要刪除并重新插入子表的數(shù)據(jù)。這里實際上把子表看作主表的一種附屬數(shù)據(jù)結(jié)構(gòu),而不是獨立的對象,子表的數(shù)據(jù)庫操作全部由主表來完成。
另一種方法是把子表看作一個單獨的實體類,實際上這時不存在主表和子表的概念了。只有兩個實體對象,他們之間是一種關(guān)聯(lián)的關(guān)系。主表通過getXXByXX()的方法來返回一個子表類的Browser??梢酝ㄟ^定義主表的一個方法insertXX(), 調(diào)用子表的insert()來插入一個新的子表項目;定義deleteXXX()來刪除子表項目。至于更新子表數(shù)據(jù),可以直接調(diào)用子表實體類的update()方法,不需要使用主表類的任何方法。
對于一個視圖,也可以參照定義實體類的方法定義一個視圖類,不過要盡量少用視圖類,因為視圖類和其他實體對象雖然語法上看不出關(guān)聯(lián),但語義上實際上是有關(guān)聯(lián)的。一個實體類的修改常常要修改所有相關(guān)的視圖類,這對于數(shù)據(jù)封裝是很不利的。只有出于性能的考慮我們才使用它。
最后,探討一下數(shù)據(jù)庫事務(wù)的概念。事務(wù)是建立在數(shù)據(jù)庫連接的基礎(chǔ)上的,可以一次提交或回滾一系列操作。要實現(xiàn)事務(wù),必須把數(shù)據(jù)庫連接的自動提交屬性設(shè)為false。java缺省的連接都是自動提交的,實現(xiàn)事務(wù)必須強制執(zhí)行一個conn.setAutoCommit(false)。如果連接不是自動提交的,那么要注意,每當(dāng)一個事務(wù)完成時必須執(zhí)行commit或rollback,就算是select語句也必須提交事務(wù)。而且事務(wù)最好能盡早提交,比如每次select后提交,這樣可以減少數(shù)據(jù)庫資源的占用。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -