什么是JDBC
JDBC:Java Database Connectivity,提供一組Java API,用于java程序中訪問(wèn)關(guān)系數(shù)據(jù)庫(kù)。通過(guò)這些API,Java程序能夠執(zhí)行SQL語(yǔ)句并與任何SQL兼容的數(shù)據(jù)庫(kù)進(jìn)行交互。
JDBC提供了一種靈活的架構(gòu),可以編寫一個(gè)獨(dú)立于數(shù)據(jù)庫(kù)的應(yīng)用程序,該應(yīng)用程序可以在不同的平臺(tái)上并與不同的DBMS進(jìn)行修改。
JDBC的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|
簡(jiǎn)潔的SQL處理 | 用于大型應(yīng)用程序時(shí)比較復(fù)雜 |
處理大量數(shù)據(jù)有著良好的性能 | 資源占用開銷比較大 |
非常適用于小型應(yīng)用程序 | 沒(méi)有進(jìn)行封裝抽象 |
語(yǔ)法簡(jiǎn)單,學(xué)習(xí)成本較低 | 很難用于MVC模式開發(fā) |
只能用于DBMS查詢 |
為什么要進(jìn)行ORM關(guān)系映射(Object Relational Mapping)
當(dāng)我們使用面向?qū)ο蟮南到y(tǒng)時(shí),對(duì)象模型與關(guān)系數(shù)據(jù)庫(kù)之間存在不匹配。RDBMS以表格形式表示數(shù)據(jù),而面向?qū)ο蟮恼Z(yǔ)言(如Java和C#)將其表現(xiàn)為對(duì)象的互聯(lián)圖。如下所示:
public class Employee {
private int id;
private String first_name;
private String last_name;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.first_name = fname;
this.last_name = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public String getFirstName() {
return first_name;
}
public String getLastName() {
return last_name;
}
public int getSalary() {
return salary;
}
}
上面的對(duì)象需要被存儲(chǔ)和檢索到下面的RDBMS表:
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
那么就會(huì)存在以下兩個(gè)問(wèn)題:
- 如果我們需要在開發(fā)了幾個(gè)頁(yè)面之后或在應(yīng)用程序中修改數(shù)據(jù)庫(kù)的設(shè)計(jì)時(shí),應(yīng)該怎么處理?
- 在關(guān)系數(shù)據(jù)庫(kù)加載和存儲(chǔ)對(duì)象會(huì)暴露以下不匹配問(wèn)題:
不匹配問(wèn)題 | 描述 |
---|---|
Granularity(粒度) | 有時(shí),您將有一個(gè)對(duì)象模型,它具有比數(shù)據(jù)庫(kù)中對(duì)應(yīng)表數(shù)量更多的類。 |
Inheritance(繼承) | RDBMS不定義類似于繼承的任何東西,它是面向?qū)ο缶幊陶Z(yǔ)言中的自然范例。 |
Identity(對(duì)象同一性) | RDBMS正好定義了“同一性”的一個(gè)概念:主鍵。然而,Java定義了對(duì)象標(biāo)識(shí)(a == b)和對(duì)象相等(a.equals(b)) |
Associations | 面向?qū)ο笳Z(yǔ)言使用對(duì)象引用表示Associations,RDBMS使用外鍵列表示 |
Navigation | 在Java和RDBMS中訪問(wèn)對(duì)象的方式是完全不同的 |
對(duì)象關(guān)系映射(ORM)是處理所有上述不匹配問(wèn)題的解決方案。
粒度問(wèn)題
- 粒度:是指你正在使用的類型的大小。
繼承(子類型問(wèn)題)
- 在Java中,使用超類(superclass)和子類(subclass)來(lái)實(shí)現(xiàn)繼承模型。
- 在Java中,繼承是類型繼承(type Inheritance),而數(shù)據(jù)庫(kù)表并不是一種類型。
- 數(shù)據(jù)庫(kù)產(chǎn)品一般不實(shí)現(xiàn)類型或者表繼承。而且即使實(shí)現(xiàn)了,我們也會(huì)遇到數(shù)據(jù)完整性的問(wèn)題(對(duì)可更新視圖的有限完整性規(guī)則)。
- 一旦把繼承進(jìn)入到模型當(dāng)中,就有了
多態(tài)(polymorphism)
的可能。SQL數(shù)據(jù)庫(kù)缺乏一種明顯的表示多態(tài)關(guān)聯(lián)的方式,一個(gè)外鍵約束精確的引用一張目標(biāo)表,定義一個(gè)引用多表的外鍵并不容易。必須編寫一個(gè)程序化的約束來(lái)加強(qiáng)這種完整性規(guī)則。
子類型的這種不匹配的結(jié)果是:模型中的繼承結(jié)構(gòu)必須在一個(gè)不提供繼承策略的SQL數(shù)據(jù)庫(kù)中被持久化。
對(duì)象同一性
如果當(dāng)我們需要檢查兩個(gè)對(duì)象是否為同一個(gè)對(duì)象的時(shí)候。解決方法有三種:
-
在java中:
- 對(duì)象同一性(粗略等同于內(nèi)存位置,用a==b檢查)
- 等同性,通過(guò)equals()方法(也成為值等同)的實(shí)現(xiàn)來(lái)確定。
數(shù)據(jù)庫(kù)的同一性用主鍵值來(lái)表達(dá)。如果使用java中的方法來(lái)判斷,那么主鍵值必然會(huì)不相等。
什么是ORM
ORM(對(duì)象關(guān)系映射),是一種用于關(guān)系數(shù)據(jù)庫(kù)和面向?qū)ο缶幊陶Z(yǔ)言(如Java、C#)之間轉(zhuǎn)換數(shù)據(jù)的編程技術(shù)。相對(duì)于JDBC,ORM具有以下優(yōu)點(diǎn):
序號(hào) | 優(yōu)點(diǎn) |
---|---|
1 | 允許業(yè)務(wù)邏輯代碼訪問(wèn)對(duì)象而不是數(shù)據(jù)庫(kù)表 |
2 | 從面向?qū)ο蟮慕嵌瓤紤]隱藏SQL查詢的詳細(xì)信息 |
3 | 底層基于JDBC |
4 | 無(wú)需處理數(shù)據(jù)庫(kù)實(shí)現(xiàn) |
5 | 基于業(yè)務(wù)概念而不是數(shù)據(jù)庫(kù)結(jié)構(gòu)的實(shí)體 |
6 | 事務(wù)管理和秘鑰自動(dòng)生成 |
7 | 應(yīng)用快速開發(fā) |
ORM解決方案由以下四個(gè)模塊組成:
序號(hào) | 解決方案 |
---|---|
1 | 用于對(duì)持久化類的對(duì)象進(jìn)行基本CRUD操作的API |
2 | 用于指定引用類的類和屬性的查詢的語(yǔ)言或API |
3 | 用于指定映射元數(shù)據(jù)的可配置工具 |
4 | 用于實(shí)現(xiàn)ORM的一項(xiàng)技術(shù),與事務(wù)對(duì)象交互,執(zhí)行臟檢查、延遲關(guān)聯(lián)抓取以及其它優(yōu)化功能 |
Java中的ORM框架
Java中有幾個(gè)持久化框架和ORM選項(xiàng)。持久化框架是一種將對(duì)象存儲(chǔ)和檢索到關(guān)系數(shù)據(jù)庫(kù)中的ORM服務(wù)。
- Enterprise JavaBeans Entity Beans
- Java Data Objects
- Castor
- TopLink
- Spring DAO
- Hibernate
- ……. etc.
ORM和Hibernate的一些好處
生產(chǎn)力
與持久化相關(guān)的代碼可能會(huì)是java中最冗長(zhǎng)的一部分代碼,Hibernate除去了許多瑣碎的工作,讓我們可以把更多的精力集中于業(yè)務(wù)問(wèn)題的處理上。
無(wú)論我們喜歡哪一種應(yīng)用程序開發(fā)策略——自上而下,從一個(gè)領(lǐng)域模型開始;或者自底而上,從一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)Schema開始——Hibernate與適當(dāng)?shù)墓ぞ咭黄鹗褂?,將明顯減少開發(fā)時(shí)間。
可維護(hù)性
更少的代碼行使得系統(tǒng)更易于理解,因?yàn)樗鼜?qiáng)調(diào)業(yè)務(wù)邏輯甚于那些費(fèi)力的基礎(chǔ)性工作。更重要的是,系統(tǒng)包含的代碼越少則越利于重構(gòu)。自動(dòng)的對(duì)象/關(guān)系持久化充分減少了代碼行。
Hibernate更易于維護(hù)還有其它原因,在手工編碼的持久化系統(tǒng)中,關(guān)系表示法和對(duì)象模型實(shí)現(xiàn)領(lǐng)域之間存在一種必然的壓力。改變一個(gè),通常都要改變另一個(gè),并且一個(gè)表示法設(shè)計(jì)通常需要妥協(xié)以便適應(yīng)另一個(gè)的存在。ORM提供了兩個(gè)模型之間的一個(gè)緩沖,允許面向?qū)ο笤贘ava方面進(jìn)行更優(yōu)雅的利用,并且每個(gè)模型的微小變化都不會(huì)傳遞到另一個(gè)模型。
性能
手工編碼的持久化和自動(dòng)的持久化相比總是可以一樣快,并且經(jīng)常更快。這是事實(shí)。但是在實(shí)際開發(fā)中,會(huì)受到時(shí)間和預(yù)算的約束。
在有限時(shí)間的項(xiàng)目中,手工編碼的持久化通常允許你進(jìn)行一些優(yōu)化;Hibernate始終允許使用更多的優(yōu)化。
自動(dòng)的持久化能夠大大提高開發(fā)人員的工作效率,使得開發(fā)人員能夠花更多的時(shí)間對(duì)其它少數(shù)瓶頸進(jìn)行手工優(yōu)化。
實(shí)現(xiàn)ORM框架的人,可能在性能優(yōu)化方面比我們做的更好。
供應(yīng)商獨(dú)立性
ORM從底層的SQL數(shù)據(jù)庫(kù)和SQL方言中把應(yīng)用程序抽象出來(lái)。如果這個(gè)工具支持不同的數(shù)據(jù)庫(kù),這會(huì)給我們的應(yīng)用程序帶來(lái)一定程度的可移植性??梢詭臀覀儨p少一些被供應(yīng)商鎖定的風(fēng)險(xiǎn)。
數(shù)據(jù)庫(kù)的獨(dú)立性使得我們可以在開發(fā)時(shí)選擇一些輕量級(jí)的數(shù)據(jù)庫(kù),在部署時(shí),將實(shí)際的產(chǎn)品部署在不同的數(shù)據(jù)庫(kù)上。