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