?? day04.txt
字號:
JDBC_day04 langna 2007-9-11 星期二
一、JDBC2.0擴展
1)DataSource:
數據庫為了保證安全:用戶名和密碼經常換,并且很多時候我們根本就不知道用戶名和密碼;
每個客戶端都要帶著JdbcUtil ,分發重復,所以我們就想到了數據源
1、數據源是服務器產生和維護的;客戶端只需去取就行;(不需要分發;不用每個點都去更新;)
2、客戶端通過jndi服務器獲得數據源的引用;
數據源是由服務器產生的,連接數據庫用的,客戶端和服務器往往不在一臺機子上;
或不在一個虛擬機上;
將數據源放到公共區域中,(數據庫不行)
2)JNDI
JNDI:java的命名和路徑服務接口;
Java Naming and Directory Interface (JNDI) 的命名操作
JDBC和JNDI比較:
JDBC JNDI
接口集 接口集
驅動 服務提供者
物理存儲(數據庫) 文件系統、注冊表、應用服務器等
JDBC 服務器:存儲的數據海量的,有規則的,需要大規模檢索;使用了SQL大規模的查詢語言;
(集裝箱)
JNDI 服務器:存的是個別的,種類繁多的,不需要大規模檢索的;(儲藏室)
存的都是java對象;
存:bind(name,object);
取:lookup(name);
基本功能、結構一樣;
存的量和存的方法不同;
由于我們沒有應用服務器;(tomcat等帶有jndi服務器);
(1)造數據源對象,一般都是服務器產生的,我們不需要寫;
(2)放到jndi服務器上,也不需要我們掌握;
(3)取數據源對象,需要我們掌握;
jndi的驅動就能把文件系統當成物理存儲;加載驅動:(classpath)providerutil.jar/fscontext.jar
(1) 在服務器上造數據源對象
a. 連接jndi服務器:
在c盤中建一個jdbc文件夾;即提供jndi服務;
驅動的參數;
url:文件系統;file:c:/jdbc (file:/home/soft/jdbc)//創建一個jndi服務器
Context ctx=null;
ctx=new InitialContext(env);
b. 造一個數據源對象
OracleDataSource ods=new OracleDataSource();
ods.setDriverType("thin");
ods.setServerName("192.168.0.201");
ods.setNetworkProtocol("tcp");
ods.setPortNumber(1521);
ods.setDatabaseName("tarena");
ods.setUser("xjh0704");
ods.setPassword("xjh0704");
c. 將數據源對象存入jndi服務器
ctx.bind("oracle20",ods);
(2)寫一個客戶端:
a.連接jndi服務器
Hashtable env=new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:c:/jdbc");
ctx=new InitialContext(env);
b.獲得數據源對象
DataSource ds=(DataSource)ctx.lookup("oracle20");
c.操作數據庫
Connection con=ds.getConnection();
Statement st=con.createStatement();
ResultSet rs=st.executeQuery("select * from ln_student");
while(rs.next()) {
System.out.print(rs.getInt(1)+"\t");
System.out.print(rs.getString(2)+"\t");
System.out.print(rs.getString(3)+"\t");
System.out.println();
}
jndi就是放藏寶圖的地方;而數據庫就是寶藏,它肯定存在;需要藏寶圖去訪問它;
3)連接池:
事先把連接準備好,一般用數據源得到的連接都是池里的連接;
并在程序使用過之后不關閉連接,再放回連接池中等
待其他的程序在需要時來取用,這樣可以大量的節省銷毀和創建連接的資源消耗。
4)分布式事務:
a數據庫:T1 提交 ,--> 轉帳 --> b數據庫:T2回滾;沒有辦法控制
將T1和T2合起來作為一個事務;
必須有第三方;weblogic,websphere 等應用服務器;
T1交給應用服務器,T2也交給應用服務器,每一個監控都有資源管理器;
所有資源管理器都讓提交才能提交;
分布式的事務都是通過聲明的配置進行的;
針對多個不同數據庫同時操作,要保證原子操作的不可分割,
也不用再自己寫commit,和rollback,全部都交給中間服務器來處理。
(兩階段提交),也就是在中間服務器發送sql語句等待數據庫回應,
都回應操作成功才提交,否則同時回滾。
除非特別大的公司,一般不用分布式事務;
5)RowSet:行集
桌面上做快速開發的組件;將Connection,ResultSet,Statement集于一身;
是一個JavaBean的機制;
(1)綜合對象
(2)JavaBean的結構,可以有圖形界面、事件機制、序列化;
自帶緩沖區,可以在網絡上傳遞
缺點:
不夠靈活
行集不屬于jdbc的主流技術,ojdbc14 沒有它的實現類;
提供一個jar包:rowset.jar
CachedRowSetImpl crs=null;
try{
//1.注冊驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//2. 建立數據庫連接并執行sql語句
crs = new CachedRowSetImpl();
crs.setUrl("jdbc:oracle:thin:@192.168.0.201:1521:tarena");
crs.setUsername("xjh0704");
crs.setPassword("xjh0704");
crs.setCommand("select * from ln_student");
crs.execute();
//3.更新操作
crs.moveToInsertRow();
crs.updateInt("id", 99988878);
crs.updateString("name", "tony");
crs.insertRow();
crs.moveToCurrentRow();
crs.acceptChanges();
//4. 處理結果集
JdbcUtil.printRs(crs);
crs.first();
System.out.println(
"=============== crs.first() ===============");
JdbcUtil.printRs(crs);
}catch(Exception e){ e.printStackTrace();}
finally{
JdbcUtil.close(crs);
}
}
二、面向對象的數據庫設計
對象ID:Accout a1,a2 ;
對象唯一性:變成記錄存到數據庫中,然后讀出來時也要保證唯一;
對象在內存中天然的是唯一的,根據內存地址來區分;
但是存內存地址又是無意義的;java中不能存,即使用c++能存,但是這塊內存是要被釋放掉的;
再放對象的話,有可能構成重復;
內存中的對象放到數據庫中要保證OID:
1)不重復;
2)足夠使用;
分配OID的計數器必須是公用的,并且不能重復;
Oracle 中用sequence;或維護一個一行一列的表;并發時;但是性能上潛在不太好;
1、數學中的高低位算法:HighLow算法
對于一個應用程序:只讀一次 :高位;
在數據庫存一個公共計數器:
表里存的是高位:1 2 3 ... ;
在本機配一個私有計數器:
應用程序1)配一個低位值10001給一個對象,再來一個對象10002...
應用程序2)配一個低位值20001給一個對象,再來一個對象20002...
中國086-
北京:010-
廣州:020-
上海:021-
2、 類應當對應到表,屬性對應字段,對象對應記錄。
類之間的關系對應表之間的關系或對應表;
繼承關系:父類子類;
關聯關系:有方向的;
OID作主鍵;
對于一個引用對象,存到另外一張表里;
(1) 繼承關系的表建立:
1)每個類建一個表,為父子類每個類都對應的創建表,這種方法類關系清晰,
但是如果類比較多就不適合了;
父類的OID為外鍵,子類引用父類的OID,存一個子類的對象會存兩個表的兩條記錄;
體現繼承關系;
特點:
最接近于面向對象的結構;
查詢效率低,任何一個查詢都要連接表;不利于做報表;
在類比較多的情況下用這個;
2)所有類對應一張表,這種方法是在表中加上一個Type字段來區分父子類,
但是只能用于類屬性較少的情況下,而且數據會有冗余。
特點:
結構簡單,就一個表,查詢效率高,做報表也很方便;
表太大,不太好維護,做索引不好做;子類的字段可以為空的;
這種用法還是比較多的;
3)只有具體類才建表,也就是把父類中的屬性均勻分配到子類的表中,
也就是父類不建表,這種表關系不能使用多態;所有的父類字段都出現在
子類的表中,定義冗余;
特點:
查詢效率也不是很高;
對多態支持不好;
優點不太突出,用的很少;
(2) 關聯關系的表的建立:
一對一:汽車和發動機;看類之間引用的數目;
一對多:訂單中有多個訂單項的引用;
(維護一個訂單項的集合)1:m(維護一個訂單的引用)
多對多:客戶和地址;m:m
通過中間表來維護;
中間表引用兩表的主鍵當作聯合主鍵,就可以實現多對多關聯
三、類型轉換查API即可;
四、程序設計:
1、程序分層
(1)什么叫分層?幾種分層的方法?
兩種分層的方法:
1)縱向分層:J2EE/JavaEE 按功能劃分:
web層: 圖形界面,跟用戶做I/O的;
技術:Servlet,JSP(JSF/Ajax),Struts
業務層: 業務處理、計算;
POJO(JavaBean),EJB,Spring
持久層: OR/Mapping;對象關系之間的轉化;跟數據庫打交道
JDBC,Hibernate
2)橫向劃分:按抽象程度劃分;
JDBC:接口集(抽象層)--驅動(實現層)
web:實現層 5
業務:抽象層 1
實現層 3
持久:抽象層 2
實現層 4
業務層的抽象-->持久層的抽象-->業務層的實現-->持久層的實現--> 畫界面(web)
(2)為什么要分層:
1) 使得程序符合設計原則;
因為設計原則來源于實踐和需求 ;
開閉原則:對擴展開放,對修改關閉;
依賴于抽象:不依賴于具體,減少耦合性;
組件和組件之間抽象耦合:
web層調用業務層的接口;
業務層調用持久性的接口;
2) 物理原因:web服務器和應用服務器和數據庫服務器不在同一個地方;
3) 便于維護;便于擴展;便于交付使用;
設計:15%
開發:15%
測試:10%
維護:60%
以后的課程慢慢去體會;
補充:
CallableStatement cs=con.prepareCall("{call ln_pro_test(?)}");//調存儲過程, p_test為存儲過程的名字;
1) 存儲過程是預編譯的;
2) 為了安全;在代碼中不能出現sql;從外部訪問數據庫沒法訪問;只能用存儲過程;
可以寫到sql文件里 ln.sql:
create or replace procedure ln_pro_test(i in number)as
begin
insert into ln_student values(i,'langna','shanghai');
end;
@ln.sql;/
存儲過程相當于sql 語句,可以當腳本執行;
con=JdbcUtil.getConnection();
cs=con.prepareCall("{call ln_pro_test(?)}");
cs.setInt(1,14);
cs.execute();
五、分析項目:
1、定義業務接口,AccountService: 存,取,轉帳
2、定義持久層接口,AccountDao:存,取,轉帳
轉帳沒有更新數據;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -