引用http://dyldragon.javaeye.com/blog/789374
一、什么是Java事務(wù)
通常的觀念認(rèn)為,事務(wù)僅與數(shù)據(jù)庫(kù)相關(guān)。
事務(wù)必須服從ISO/IEC所制定的ACID原則。
ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫(xiě)。
事務(wù)的原子性表示事務(wù)執(zhí)行過(guò)程中的任何失敗都將導(dǎo)致事務(wù)所做的任何修改失效。
一致性表示當(dāng)事務(wù)執(zhí)行失敗時(shí),所有被該事務(wù)影響的數(shù)據(jù)都應(yīng)該恢復(fù)到事務(wù)執(zhí)行前的狀態(tài)。
隔離性表示在事務(wù)執(zhí)行過(guò)程中對(duì)數(shù)據(jù)的修改,在事務(wù)提交之前對(duì)其他事務(wù)不可見(jiàn)。
持久性表示已提交的數(shù)據(jù)在事務(wù)執(zhí)行失敗時(shí),數(shù)據(jù)的狀態(tài)都應(yīng)該正確。
通俗的理解,事務(wù)是一組原子操作單元,從數(shù)據(jù)庫(kù)角度說(shuō),就是一組SQL指令,要么全部執(zhí)行成功,若因?yàn)槟硞€(gè)原因其中一條指令執(zhí)行有錯(cuò)誤,則撤銷(xiāo)先前執(zhí)行過(guò)的所有指令。更簡(jiǎn)答的說(shuō)就是:要么全部執(zhí)行成功,要么撤銷(xiāo)不執(zhí)行。
既然事務(wù)的概念從數(shù)據(jù)庫(kù)而來(lái),那Java事務(wù)是什么?之間有什么聯(lián)系? 實(shí)際上,一個(gè)Java應(yīng)用系統(tǒng),如果要操作數(shù)據(jù)庫(kù),則通過(guò)JDBC來(lái)實(shí)現(xiàn)的。增加、修改、刪除都是通過(guò)相應(yīng)方法間接來(lái)實(shí)現(xiàn)的,事務(wù)的控制也相應(yīng)轉(zhuǎn)移到Java程序代碼中。因此,數(shù)據(jù)庫(kù)操作的事務(wù)習(xí)慣上就稱(chēng)為Java事務(wù)。
二、為什么需要事務(wù)
事務(wù)是為解決數(shù)據(jù)安全操作提出的,事務(wù)控制實(shí)際上就是控制數(shù)據(jù)的安全訪問(wèn)。具一個(gè)簡(jiǎn)單例子:比如銀行轉(zhuǎn)帳業(yè)務(wù),賬戶A要將自己賬戶上的1000 元轉(zhuǎn)到B賬戶下面,A賬戶余額首先要減去1000元,然后B賬戶要增加1000元。假如在中間網(wǎng)絡(luò)出現(xiàn)了問(wèn)題,A賬戶減去1000元已經(jīng)結(jié)束,B因?yàn)榫W(wǎng)絡(luò)中斷而操作失敗,那么整個(gè)業(yè)務(wù)失敗,必須做出控制,要求A賬戶轉(zhuǎn)帳業(yè)務(wù)撤銷(xiāo)。這才能保證業(yè)務(wù)的正確性,完成這個(gè)操走就需要事務(wù),將A賬戶資金減少和B賬戶資金增加方到一個(gè)事務(wù)里面,要么全部執(zhí)行成功,要么操作全部撤銷(xiāo),這樣就保持了數(shù)據(jù)的安全性。
三、Java事務(wù)的類(lèi)型
Java 事務(wù)的類(lèi)型有三種:JDBC事務(wù)、JTA(Java Transaction API)事務(wù)、容器事務(wù)。
1、JDBC事務(wù)
JDBC 事務(wù)是用 Connection 對(duì)象控制的。JDBC Connection 接口( java.sql.Connection )提供了兩種事務(wù)模式:自動(dòng)提交和手工提交。 java.sql.Connection 提供了以下控制事務(wù)的方法:
public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
使用 JDBC 事務(wù)界定時(shí),您可以將多個(gè) SQL 語(yǔ)句結(jié)合到一個(gè)事務(wù)中。JDBC 事務(wù)的一個(gè)缺點(diǎn)是事務(wù)的范圍局限于一個(gè)數(shù)據(jù)庫(kù)連接。一個(gè) JDBC 事務(wù)不能跨越多個(gè)數(shù)據(jù)庫(kù)。
2、JTA(Java Transaction API)事務(wù)
JTA 是一種高層的,與實(shí)現(xiàn)無(wú)關(guān)的,與協(xié)議無(wú)關(guān)的API,應(yīng)用程序和應(yīng)用服務(wù)器可以使用JTA來(lái)訪問(wèn)事務(wù)。
JTA允許應(yīng)用程序執(zhí)行分布式事務(wù)處理--在兩個(gè)或多個(gè)網(wǎng)絡(luò)計(jì)算機(jī)資源上訪問(wèn)并且更新數(shù)據(jù),這些數(shù)據(jù)可以分布在多個(gè)數(shù)據(jù)庫(kù)上。JDBC驅(qū)動(dòng)程序的JTA支持極大地增強(qiáng)了數(shù)據(jù)訪問(wèn)能力。
如果計(jì)劃用 JTA 界定事務(wù),那么就需要有一個(gè)實(shí)現(xiàn) javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource接口的 JDBC 驅(qū)動(dòng)程序。一個(gè)實(shí)現(xiàn)了這些接口的驅(qū)動(dòng)程序?qū)⒖梢詤⑴c JTA 事務(wù)。一個(gè) XADataSource 對(duì)象就是一個(gè)XAConnection 對(duì)象的工廠。 XAConnection s 是參與 JTA 事務(wù)的 JDBC 連接。
您將需要用應(yīng)用服務(wù)器的管理工具設(shè)置 XADataSource 。從應(yīng)用服務(wù)器和 JDBC 驅(qū)動(dòng)程序的文檔中可以了解到相關(guān)的指導(dǎo)。
J2EE 應(yīng)用程序用 JNDI 查詢數(shù)據(jù)源。一旦應(yīng)用程序找到了數(shù)據(jù)源對(duì)象,它就調(diào)用 javax.sql.DataSource.getConnection() 以獲得到數(shù)據(jù)庫(kù)的連接。
XA 連接與非 XA 連接不同。一定要記住 XA 連接參與了 JTA 事務(wù)。這意味著 XA 連接不支持 JDBC 的自動(dòng)提交功能。同時(shí),應(yīng)用程序一定不要對(duì) XA 連接調(diào)用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() 。相反,應(yīng)用程序應(yīng)該使用 UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() 。
3、容器事務(wù)
容器事務(wù)主要是J2EE應(yīng)用服務(wù)器提供的,容器事務(wù)大多是基于JTA完成,這是一個(gè)基于JNDI的,相當(dāng)復(fù)雜的API實(shí)現(xiàn)。相對(duì)編碼實(shí)現(xiàn)JTA 事務(wù)管理,我們可以通過(guò)EJB容器提供的容器事務(wù)管理機(jī)制(CMT)完成同一個(gè)功能,這項(xiàng)功能由J2EE應(yīng)用服務(wù)器提供。這使得我們可以簡(jiǎn)單的指定將哪個(gè)方法加入事務(wù),一旦指定,容器將負(fù)責(zé)事務(wù)管理任務(wù)。這是我們土建的解決方式,因?yàn)橥ㄟ^(guò)這種方式我們可以將事務(wù)代碼排除在邏輯編碼之外,同時(shí)將所有困難交給 J2EE容器去解決。使用EJB CMT的另外一個(gè)好處就是程序員無(wú)需關(guān)心JTA API的編碼,不過(guò),理論上我們必須使用EJB。
四、三種事務(wù)差異
1、JDBC事務(wù)控制的局限性在一個(gè)數(shù)據(jù)庫(kù)連接內(nèi),但是其使用簡(jiǎn)單。
2、JTA事務(wù)的功能強(qiáng)大,事務(wù)可以跨越多個(gè)數(shù)據(jù)庫(kù)或多個(gè)DAO,使用也比較復(fù)雜。
3、容器事務(wù),主要指的是J2EE應(yīng)用服務(wù)器提供的事務(wù)管理,局限于EJB應(yīng)用使用。
JTA
Java事務(wù)API(JTA;Java Transaction API)和它的同胞Java事務(wù)服務(wù)(JTS;Java Transaction Service),為J2EE平臺(tái)提供了分布式事務(wù)服務(wù)。一個(gè)分布式事務(wù)(distributed transaction)包括一個(gè)事務(wù)管理器(transaction manager)和一個(gè)或多個(gè)資源管理器(resource manager)。一個(gè)資源管理器(resource manager)是任意類(lèi)型的持久化數(shù)據(jù)存儲(chǔ)。事務(wù)管理器(transaction manager)承擔(dān)著所有事務(wù)參與單元者的相互通訊的責(zé)任。下圖顯示了事務(wù)管理器和資源管理的間的關(guān)系。
JTA事務(wù)比JDBC事務(wù)更強(qiáng)大。一個(gè)JTA事務(wù)可以有多個(gè)參與者,而一個(gè)JDBC事務(wù)則被限定在一個(gè)單一的數(shù)據(jù)庫(kù)連接。下列任一個(gè)Java平臺(tái)的組件都可以參與到一個(gè)JTA事務(wù)中:
JDBC連接
- JDO PersistenceManager 對(duì)象
- JMS 隊(duì)列
- JMS 主題
- 企業(yè)JavaBeans(EJB)
- 一個(gè)用J2EE Connector Architecture 規(guī)范編譯的資源分配器。
DAO
DAO是Data Access Object數(shù)據(jù)訪問(wèn)接口,數(shù)據(jù)訪問(wèn):顧名思義就是與數(shù)據(jù)庫(kù)打交道。夾在業(yè)務(wù)邏輯與數(shù)據(jù)庫(kù)資源中間。對(duì)數(shù)據(jù)庫(kù)進(jìn)行CURD(增刪查改操作)。
在核心J2EE模式中是這樣介紹DAO模式的:為了建立一個(gè)健壯的J2EE應(yīng)用,應(yīng)該將所有對(duì)數(shù)據(jù)源的訪問(wèn)操作抽象封裝在一個(gè)公共API中。用程序設(shè)計(jì)的語(yǔ)言來(lái)說(shuō),就是建立一個(gè)接口,接口中定義了此應(yīng)用程序中將會(huì)用到的所有事務(wù)方法。在這個(gè)應(yīng)用程序中,當(dāng)需要和數(shù)據(jù)源進(jìn)行交互的時(shí)候則使用這個(gè)接口,并且編寫(xiě)一個(gè)單獨(dú)的類(lèi)來(lái)實(shí)現(xiàn)這個(gè)接口在邏輯上對(duì)應(yīng)這個(gè)特定的數(shù)據(jù)存儲(chǔ)。
JDBC
JDBC(Java Data Base Connectivity,java數(shù)據(jù)庫(kù)連接)是一種用于執(zhí)行SQL語(yǔ)句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供統(tǒng)一訪問(wèn),它由一組用Java語(yǔ)言編寫(xiě)的類(lèi)和接口組成。JDBC為工具/數(shù)據(jù)庫(kù)開(kāi)發(fā)人員提供了一個(gè)標(biāo)準(zhǔn)的API,據(jù)此可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫(kù)開(kāi)發(fā)人員能夠用純 Java API 編寫(xiě)數(shù)據(jù)庫(kù)應(yīng)用程序,同時(shí),JDBC也是個(gè)商標(biāo)名。
有了JDBC,向各種關(guān)系數(shù)據(jù)發(fā)送SQL語(yǔ)句就是一件很容易的事。換言之,有了JDBC API,就不必為訪問(wèn)Sybase數(shù)據(jù)庫(kù)專(zhuān)門(mén)寫(xiě)一個(gè)程序,為訪問(wèn)Oracle數(shù)據(jù)庫(kù)又專(zhuān)門(mén)寫(xiě)一個(gè)程序,或?yàn)樵L問(wèn)Informix數(shù)據(jù)庫(kù)又編寫(xiě)另一個(gè)程序等等,程序員只需用JDBC API寫(xiě)一個(gè)程序就夠了,它可向相應(yīng)數(shù)據(jù)庫(kù)發(fā)送SQL調(diào)用。同時(shí),將Java語(yǔ)言和JDBC結(jié)合起來(lái)使程序員不必為不同的平臺(tái)編寫(xiě)不同的應(yīng)用程序,只須寫(xiě)一遍程序就可以讓它在任何平臺(tái)上運(yùn)行,這也是Java語(yǔ)言“編寫(xiě)一次,處處運(yùn)行”的優(yōu)勢(shì)。
簡(jiǎn)單地說(shuō),JDBC 可做三件事:與數(shù)據(jù)庫(kù)建立連接、發(fā)送 操作數(shù)據(jù)庫(kù)的語(yǔ)句并處理結(jié)果。
JDO
JDO(Java Data Object )是一個(gè)JAVA用于存取某種數(shù)據(jù)倉(cāng)庫(kù)中的對(duì)象的標(biāo)準(zhǔn)化API。JDO提供了透明的對(duì)象存儲(chǔ),因此對(duì)開(kāi)發(fā)人員來(lái)說(shuō),存儲(chǔ)數(shù)據(jù)對(duì)象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經(jīng)轉(zhuǎn)移到JDO產(chǎn)品提供商身上,使開(kāi)發(fā)人員解脫出來(lái),從而集中時(shí)間和精力在業(yè)務(wù)邏輯上。另外,JDO很靈活,因?yàn)樗梢栽谌魏螖?shù)據(jù)底層上運(yùn)行。JDBC只是面向關(guān)系數(shù)據(jù)庫(kù)(RDBMS)JDO更通用,提供到任何數(shù)據(jù)底層的存儲(chǔ)功能,比如關(guān)系數(shù)據(jù)庫(kù)、文件、XML以及對(duì)象數(shù)據(jù)庫(kù)(ODBMS)等等,使得應(yīng)用可移植性更強(qiáng)。
JNDI
英文全稱(chēng)是:Java Naming and Directory Interface
術(shù)語(yǔ)解釋?zhuān)阂唤M幫助做多個(gè)命名和目錄服務(wù)接口的API。
JNDI(Java Naming and Directory Interface)是SUN公司提供的一種標(biāo)準(zhǔn)的Java命名系統(tǒng)接口,JNDI提供統(tǒng)一的客戶端API,通過(guò)不同的訪問(wèn)提供者接口JNDI SPI的實(shí)現(xiàn),由管理者將JNDI API映射為特定的命名服務(wù)和目錄系統(tǒng),使得Java應(yīng)用程序可以和這些命名服務(wù)和目錄服務(wù)之間進(jìn)行交互。集群JNDI實(shí)現(xiàn)了高可靠性JNDI[8],通過(guò)服務(wù)器的集群,保證了JNDI的負(fù)載平衡和錯(cuò)誤恢復(fù)。在全局共享的方式下,集群中的一個(gè)應(yīng)用服務(wù)器保證本地JNDI樹(shù)的獨(dú)立性,并擁有全局的JNDI樹(shù)。每個(gè)應(yīng)用服務(wù)器在把部署的服務(wù)對(duì)象綁定到自己本地的JNDI樹(shù)的同時(shí),還綁定到一個(gè)共享的全局JNDI樹(shù),實(shí)現(xiàn)全局JNDI和自身JNDI的聯(lián)系。
JNDI(Java Naming and Directory Interface)是一個(gè)應(yīng)用程序設(shè)計(jì)的API,為開(kāi)發(fā)人員提供了查找和訪問(wèn)各種
命名和目錄服務(wù)的通用、統(tǒng)一的接口,類(lèi)似JDBC都是構(gòu)建在抽象層上。
JNDI可訪問(wèn)的現(xiàn)有的目錄及服務(wù)有:DNS、XNam 、Novell目錄服務(wù)、LDAP(Lightweight Directory Access Protocol 輕型目錄訪問(wèn)協(xié)議)、 CORBA對(duì)象服務(wù)、文件系統(tǒng)、Windows XP/2000/NT/Me/9x的注冊(cè)表、RMI、
DSML v1&v2、NIS。
JNDI與JDBC
JNDI提供了一種統(tǒng)一的方式,可以用在網(wǎng)絡(luò)上查找和訪問(wèn)服務(wù)。通過(guò)指定一個(gè)資源名稱(chēng),該名稱(chēng)對(duì)應(yīng)于數(shù)據(jù)庫(kù)或命名服務(wù)中的一個(gè)記錄,同時(shí)返回?cái)?shù)據(jù)庫(kù)連接建立所必須的信息。
JNDI主要有兩部分組成:應(yīng)用程序編輯接口和服務(wù)供應(yīng)商接口。應(yīng)用程序編程接口提供了Java應(yīng)用程序訪問(wèn)各種命名和目錄服務(wù)的功能,服務(wù)供應(yīng)商接口提供了任意一種服務(wù)的供應(yīng)商使用的功能。
- try{
- Context cntxt = new InitialContext();
- DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt");
- }
- catch(NamingException ne){
- ...
- }
From now, i will restart my blog , try to record sth of my life, including some thoughts and research results of technology, the only little hope is that the blog can leave my memory of life, as time flying, when i open it , i can get something.
Technology - Hibernate collection:
Maybe i used to write sth related before.
Several points as follows:
1. Define interface as property, for Hibernate will use its own implementation during runtime.
2. <key> element is used to identiry foreign key for specified table.
3. <element> and <composite-element> is used for value type definition while <one-to-many> and <many-to-many> is used for entities type.
4. indexed-collections contain : map, list, index is used to record position for certain record in the container.<map-key> for map while <index-list> for list.
Next two items is for bidirection:
5. inverse can be set in either sides for many-to-many relation.
6. For one-to-many, many sides will mantain relationship between object. exception happened when many side is index container.in this situation, it is not a completely "bidirectoinal".
7. Sort is done in memory while order by is down in DB.
8. <Bag> is used when property is defined as list, but <index-list> is not welcome.
9. <idbag> is a list which can generate an id for primary key.
package testSchema;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultNamespace;
import org.iso_relax.verifier.Schema;
import org.iso_relax.verifier.Verifier;
import org.iso_relax.verifier.VerifierConfigurationException;
import org.iso_relax.verifier.VerifierFactory;
import org.iso_relax.verifier.VerifierFilter;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import com.sun.msv.verifier.jarv.TheFactoryImpl;
public class ValidateXML {
public Document validate(InputStream stream, String xsdName) throws IOException{
Document result = null;
InputStream xmlStream = stream;
InputStream schemaStream = this.getClass().getResourceAsStream(xsdName);
SAXReader reader;
try {
reader = createSAXReader(schemaStream);
result = reader.read(xmlStream);
xmlStream.close();
schemaStream.close();
} catch (DocumentException e) {
System.out.println("Validate failed !");
e.printStackTrace();
} catch(IOException e) {
System.out.println("Xsd file does not exist !");
e.printStackTrace();
}
catch (Exception e) {
System.out.println("Xsd file format error !");
e.printStackTrace();
}
return result;
}
private SAXReader createSAXReader(InputStream xsdStream) throws VerifierConfigurationException, SAXException, IOException {
VerifierFactory factory = new TheFactoryImpl();
Schema schema = factory.compileSchema(xsdStream);
Verifier verifier = schema.newVerifier();
verifier.setErrorHandler(new ErrorHandler() {
public void error(SAXParseException e) {
System.out.println("ERROR: " + e);
}
public void fatalError(SAXParseException e) {
System.out.println("FATAL: " + e);
}
public void warning(SAXParseException e) {
System.out.println("WARNING: " + e);
}
});
// now install the verifying filter
VerifierFilter filter = verifier.getVerifierFilter();
SAXReader reader = new SAXReader();
reader.setXMLFilter(filter);
return reader;
}
public static void main(String[] args) throws IOException {
ValidateXML validateXML = new ValidateXML();
// InputStream schemaStream = validateXML.getClass().getResourceAsStream("Response.xml");
// validateXML.validate(schemaStream, "BAK-Response.xsd");
validateXML.validateByDtd("hibernate-configuration-3.0.dtd", "src\\testSchema\\hibernate.cfg.xml");
}
public Document validateByDtd(String dtdFile, String xmlFile) {
List errors = new ArrayList();
SAXReader saxReader = new SAXReader();
saxReader.setEntityResolver(new DTDEntityResolver(dtdFile));
saxReader.setErrorHandler(new ErrorLogger(xmlFile, errors));
saxReader.setValidation(true);
Document doc = null;
try {
doc = saxReader.read(xmlFile);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return doc;
}
public static class ErrorLogger implements ErrorHandler {
private String file;
private List errors;
ErrorLogger(String file, List errors) {
this.file=file;
this.errors = errors;
}
public void error(SAXParseException error) {
System.err.println( "Error parsing XML: " + file + '(' + error.getLineNumber() + ") " + error.getMessage() );
errors.add(error);
}
public void fatalError(SAXParseException error) {
System.err.println(error);
}
public void warning(SAXParseException warn) {
System.err.println( "Warning parsing XML: " + file + '(' + warn.getLineNumber() + ") " + warn.getMessage() );
}
}
public static class DTDEntityResolver implements EntityResolver, Serializable {
private static final Log log = LogFactory.getLog( DTDEntityResolver.class );
private String dtdFile;
public DTDEntityResolver(String dtdFile) {
this.dtdFile = dtdFile;
}
public InputSource resolveEntity(String publicId, String systemId) {
if ( systemId != null ) {
InputStream dtdStream = this.getClass().getResourceAsStream(dtdFile);
InputSource source = new InputSource( dtdStream );
source.setPublicId( publicId );
source.setSystemId( systemId );
return source;
}
// use default behavior
return null;
}
}
}