EJB技术有赖于2种重要技术的存在:Java RMI-IIOP和JNDI.EJB客户仅仅同其暴露的单一接口进行交互。其中暴露的接口
和企业Bean本身必须遵循EJB规范。EJB规范要求企业Bean暴露若干所要求的方法,而这些暴露的方法是供EJB容器统一管理他
们使用的,无论EJB组件部署在何种EJB容器中。
EJB2.1规范定义了3种EJB组件类型。
会话Bean:会话Bean用于建模业务过程。即为完成某些任务而存在。
实体Bean:实体Bean用于建模业务数据。他们是数据对象。实体Bean是用于缓存数据库信息的Java对象。
消息驱动Bean:MDB类似于会话Bean,因为它们都是为完成某些任务而存在的。
EJB组件是基于分布式对象构建的,远程系统能够调用分布式对象。当然,进程内的客户、进程外的客户及网络中的其他
客户都能够与分布式对象进行交互。具体过程如下:
客户调用存根:即为客户端提供的代理对象。存根负责将网络通信屏蔽掉,这对于客户而言意义深远。存根能够使用
Socket访问网络中的其他资源,其间将调用所需的参数构建成网络要求的调用格式。
借助于网络:存根能够实现与服务器端的骨架进行交互。骨架是为服务器端提供的代理对象。骨架负责将网络通信屏蔽
掉,这对于分布式对象而言意义深远。骨架能够处理来自Socket的访问请求。当然,骨架还能够将存根构建好的参数转换成
Java表示。
骨架将具体的客户调用委派给合适的分布式对象实现。因此,该对象将完成具体的访问请求,并将结果返回给骨架。依
此类推,骨架将结果返回给存根,最后客户将获得分布式对象的响应结果(通过存根获得)。
重要:存根和服务器端实现的对象都实现了同一接口(称之为远程接口)。其意味着存根克隆了分布式对象的方法签名。
调用存根中的方法的客户以为其自身直接调用了分布式对象,但实际情况是客户直接调用存根,而存根处理具体的网络访问
工作。因此,这可以称之为分布透明性。
分布式对象是对如下几个协作对象的一种抽象:存根、骨架、实现的对象,单一的参与者不可能构成分布式对象。
分布式对象是很诱人的,因为开发者能够基于网络构建应用。在开发大型的分布式对象应用的时候,需要借助于中间件
服务,如事务和安全性。
远程对象:
(1)、企业Bean的业务逻辑需要在Bean类中实现。EJB规范定义了企业Bean类待实现的若干接口。这些接口使得所有的企
业Bean类能够暴露同一套接口。各种企业Bean的Bean类都需要实现javax.ejb.EnterpriseBean接口。
当然,EJB规范分别为会话Bean、实体Bean和消息驱动Bean提供了更专属的接口类型,
SessionBean,EntityBean,MessageDriverBean.
(2)、当客户使用企业Bean类的某实例时,它并不是直接调用Bean类的方法,EJB容器将拦截客户调用,然后委派给企业
Bean实例。通过拦截客户请求,EJB容器能够自动操作隐式中间件服务。
因此,在客户和EJB组件间,引入了间接层,即EJB容器。引入的间接层将自身封装为单一的网络使能对象,即EJB对象,
EJB对象正是请求拦截器。EJB对象是代理对象,它可以与网络、事务、安全性等进行交互。企业Bean客户调用EJB对象提供的
方法,而不是企业Bean本身。因此,EJB对象必须复制企业Bean类暴露的业务方法。但是,自动生成EJB对象的工具是怎么知
道业务方法的呢?答案是,通过企业Bean提供者提供的接口来实现,即远程接口。这个接口复制企业Bean类暴露的业务方法。
EJB容器负责管理EJB组件,通过调用EJB组件提供的回调方法,EJB容器能够同EJB组件交互。这些回调方法仅供EJB容器管理
EJB组件使用。
EJB容器最为重要的一项工作是,提供EJB组件运行的环境。EJB容器宿主了EJB组件,从而供远程客户调用。因此,可以
认为EJB容器充当了客户和EJB组件的中间人。EJB容器负责将客户连接到EJB组件,完成事务协调工作,提供持久化能力,管
理EJB组件的声明周期及其他任务。
EJB的远程接口还需复制企业Bean类的业务方法。一旦企业Bean客户调用业务方法,EJB对象将把调用操作委派给相应的
Bean类。
(3)、Java RMI-IIOP和EJB对象:javax.ejb.EJBObject继承于java.rmi.Remote.任何实现了Remote接口的对象都是远程
对象,即能够从其他JVM中访问到它,这就是Java实现RMI方式。由于容器提供的EJB对象实现了EJB组件的远程接口,因此EJB
对象也间接实现了java.rmi.Remote接口。EJB对象是具有完整网络功能的RMI-IIOP对象,供其他JVM或者网络中其他物理机器
访问。实际上,EJB远程接口仅仅是RMI-IIOP远程接口,只不过它还遵循EJB规范罢了。
远程接口还必须遵从RMI-IIOP的参数传递约定。并不是所有的内容都能够跨越JVM传递的。方法中传递的参数必须是符合
RMI-IIOP约定的有效Java类型,如Java原型、序列化对象和RMI-IIOP对象。
总之,EJB容器需要负责权衡资源管理和管理已部署EJB组件的生命周期。
posted @
2009-10-28 15:39 王永庆 阅读(254) |
评论 (0) |
编辑 收藏
EJB组件技术吸收了企业级计算领域中各个方面的丰富经验和知识,比如分布式计算、数据库、安全性、组件驱动软件等。服务器端开发平台,即Java2平台企业版,企业Bean组件架构是J2EE的重要部分。
J2EE是对概念、编程标准、技术革新的统称,即基于Java编程语言开发服务器端应用。借助于J2EE,开发者能够快速构建分布式、扩展性强、可靠的、便携性好、安全的服务器端应用。
EJB,是基于Java的服务器端组件架构技术。在Java应用服务器提供商提供的分布式基础框架(比如,J2EE应用服务器)的基础之上,开发者能够快速、轻松的构建服务器端组件。EJB的重要设计初衷是保证应用能够在任一提供商提供的企业中间件服务上畅行无阻,而且其便携性、可重用性都是一流的。
分布式系统:通过将传统的大型应用系统分解成多层系统,这使得组成应用系统的各层相互独立,并且承担的职责各不相同。早先,在整个中间件领域至少存在50个应用服务器。起初,各个应用服务器分别以非标准、专有的方式提供组件服务。因此,它们对于组件服务的认识各不相同,而且对具体提供组件服务的方式都不尽相同。更不用谈组件同应用服务器的具体交互了。这样的结果是:一旦组件部署到某个应用服务器,则它就被锁定到该应用服务器上。这对于客户而言,是不希望看到的情景。
如果能够在不同ISV间达成共识,比如在应用服务器和组件间提供相同的接口,供开发和部署应用使用,则这将使得任何组件能够运行在任一应用服务器中。与此同时,组件也能够在不同应用服务器间实现热插拔,而且不用修改应用代码,甚至也不用重新编译组件本身。本书将这种共识称之为组件架构。
服务:就是一组提供具体业务操作功能的相关组件。SOA具有极强的独立性,这些SOA提供的服务能够同其他服务进行交互,而不管其实现方式和部署的目标平台如何。因此,将这些独立、松耦合的服务集成起来是很有现实意义的。
SOAP:简单对象访问协议,SOAP是基于XML、应用级的协议,供分布式网络中交换信息使用。目前,SOAP支持2种分布式计算模型:面向RPC和面向文档风格的SOAP消息。
Web服务为那些分布式、松耦合SOA应用场合提供了强有力的解决方案。借助于WSDL能够描述WEB服务;借助于SOAP能够访问到WEB服务。
EJB仅仅是J2EE的组成部分之一。其中,J2EE平台规范是由JCP指定。J2EE平台规范的使命是,提供平台独立的、便携的、多用户的、安全的、遵循标准的企业级平台。而且,它必须基于java和在服务器端部署。
posted @
2009-10-27 22:52 王永庆 阅读(185) |
评论 (0) |
编辑 收藏
Blob、Clob字段的映射
Blob和Clob字段的区别在于,Blob字段采用单字节存储,适合保存二进制数据,如图片文件。Clob字段采用多字节存储,适合保存大型文本数据。
在Oracle中Blob/Clob字段独特的访问方式,Oracle Blob/Clob字段本身拥有一个游标,JDBC必须必须通过游标对Blob/Clob字段进行操作,在Blob/Clob字段被创建之前,我们无法获取其游标句柄,这也意味着,我们必须首先创建一个空Blob/Clob字段,再从这个空Blob/Clob字段获取游标,写入我们所期望保存的数据。
实体粒度设计:
在Hibernate世界里,我们经常听到"fine-grained object model"直接翻译就是适当的细粒度对象模型。
适当的比较模糊,细粒度就是将原本业务模型中的对象加以细分,从而得到更加精细的对象模型。就是划分出更多的对象。分为:面向设计的细粒度划分和面向性能的细粒度划分。
对于单表的对象细分,在Hibernate中可借助Component节点的定义来完成。何谓Component?从名字上来看,既然称之为组件,则其必然是从属于某个整体的一个组成部分。在Hibernate语义中,我们将某个实体对象中的一个逻辑组成成为Component.Component与实体对象的根本差别,就在于Component没有标示,它作为一个逻辑组成,完全从属于实体对象。通过Component定义,我们将T_User表实际映射到了3个类,TUser,Contact和Name,这样我们就可以在传统关系型库表上,实现了面向对象的领域划分。
面向性能的细粒度划分:
当我们通过Hibernate加载TUser对象时,Hibernate会从库表中读取所有的字段数据,并构造TUser实例返回。这里就产生了一个性能方面的问题,作为blob/clob等重量级字段类型,数据库读取操作代价较高。对于需要处理resume和image的应用逻辑而言,这样的代价无法避免,而对于那些无需resume和image信息的操作而言,如此性能无谓的损耗实在可惜。
如何避免这个问题,Hibernate3提供了属性的延迟加载功能,通过这个功能,我们可以在调用TUser.getResume/getImage时才真正从数据库中读取数据。对于hibernate2来说我们通过继承关系,我们将一个对象进行纵向细分来解决这个问题。我们通过在子类的映射文件中class节点指定polymorphism="explicit"声明了一个显示多态关系。声明为显示多态的类,只有在明确指定类名的时候才会返回此类实例。
package com.wyq.hibernateLoad;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.wyq.hibernate.TUser2;
public class TUserOperator {
Session session = null;
//复合主键加载数据
public void loadData(){
TUser2 user = new TUser2();
user.setFirstname("Kevin");
user.setLastname("Shark");
user = (TUser2)session.load(TUser2.class, user);
System.out.println("User age is=>"+user.getAge());
}
//SQL保存图片
public void saveImage(){
TUser2 user = new TUser2();
user.setAge(new Integer(20));
try {
FileInputStream imgis = new FileInputStream("C:\\inimage.jpg");
Blob img = Hibernate.createBlob(imgis);
user.setImage(img);
Clob resume = Hibernate.createClob("This is Clob");
user.setResume(resume);
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//SQL读取图片
public void getImageObj(){
TUser2 user = (TUser2)session.load(TUser2.class,new Integer(3));
Clob resume = user.getResume();
Blob img = user.getImage();
try {
InputStream is = img.getBinaryStream();
FileOutputStream fos = new FileOutputStream("c:\\outimage.jpg");
byte[] buf = new byte[102400];
int len;
while((len=is.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
is.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//Oracle保存图片
public void saveForOracleImage(){
TUser2 user = new TUser2();
user.setAge(new Integer(20));
user.setImage(Hibernate.createBlob(new byte[1]));
user.setResume(Hibernate.createClob(" "));//注意这里的参数是一个空格
Transaction tx = session.beginTransaction();
session.save(user);
//调用flush方法,强制Hibernate立即执行insert sql
session.flush();
//通过refresh方法,强制Hibernate执行select for update
session.refresh(user, LockMode.UPGRADE);
//向Blob写入实际内容
oracle.sql.BLOB blob = (oracle.sql.BLOB)user.getImage();
try {
OutputStream out = blob.getBinaryOutputStream();
FileInputStream imgis = new FileInputStream("c:\\inimage.jpg");
byte[] buf = new byte[10240];//10k缓存
int len;
while((len=imgis.read(buf))>0){
out.write(buf,0,len);
}
imgis.close();
out.close();
//向CLOB写入实际内容
oracle.sql.CLOB clob = (oracle.sql.CLOB)user.getResume();
java.io.Writer writer = clob.getCharacterOutputStream();
writer.write("this is my resume");
writer.close();
session.save(user);
tx.commit();
} catch (SQLException e) {
e.printStackTrace();
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
实体层次设计:继承关系是关系型数据与面向对象数据结构之间的主要差异之一。
Hibernate中支持3种类型的继承形式:
1、表与子类之间的独立一对一关系。
2、每个子类对应一张子表,并与主类共享主表
3、表与类的一对多关系
posted @
2009-10-27 22:32 王永庆 阅读(219) |
评论 (0) |
编辑 收藏
对于新系统的设计开发而言,我们应该尽量避免在哭表中引入与业务逻辑相关的主键关系。
将业务逻辑主键引入库表,将使得底层库表结构与业务逻辑相耦合,之后业务逻辑的变化,将很可能对底层数据库结构产生连带影响。
复合主键的引入,很大程度上意味着业务逻辑已经侵入到数据存储逻辑之中。因此在新系统的设计过程中,我们应该尽量避免这样的情况出现。
Hibernate中,通过composite-id节点对复合主键进行定义。
对于复合主键而言,我们可以通过2种方式确定主键:
1>基于实体类属性的复合主键
复合主键由实体类中的属性组成,此时,实体类本身即同事扮演复合主键类的角色。
<hibernate-mapping>
<class name="com.wyq.hibernate.TUser2" table="T_User2">
<composite-id>
<key-property name="lastname" column="lastname" type="string"/>
<key-property name="firstname" column="firstname" type="string"/>
</composite-id>
<property name="age" column="age" type="integer">
</property>
</class>
</hibernate-mapping>
Hibernate要求复合主键类实现equals和hashcode方法,以作为不同数据之间识别的标志。
主键类的加载:我们可以将TUser2类对象本身作为查询条件进行检索:
2>基于主键类的复合主键
我们可以将主键属性独立到一个单独的类中。实现方法类似,只不过映射文件的composite-id节点要引入class和name属性。
posted @
2009-10-27 22:30 王永庆 阅读(142) |
评论 (0) |
编辑 收藏
有一周的时间没有更新技术了,最近离职(南京合荣欣业),交接的东西太多,最后还要完成一个场景(支付信息业务登记薄查询)的开发,当初都不应该接这个场景,现在每天都在弄,还好昨天弄完了,明天可以继续看书更新技术了,这3年一直在技术上追寻着,可能没有学到新的技术,但是,感觉架构的思想理解了不少,每一种技术的出现都是有他的原因的,不一定是新的技术就要用,要选择适合自己的。
3年的时间,做IT的自己认识的朋友有限,不管男女(女的更少,能称得上朋友的),很大程度上是自己的性格所限,没办法啊,老天爷给了这个性格,都说性格可以改变,那都是扯,俗话说得好,狗改不了吃屎,性格是天生的,除非后天遇到什么重大事件,否则很难改变。自己的这种沉默的性格,也有点好处,就是对程序来说,可能只关注代码吧,但是也没做到牛B的那种,是说技术大牛。
讨厌做程序的人,可能是太枯燥了,说到这里吧,下周开始继续博客,希望这次能坚持住。
posted @
2009-10-24 14:13 王永庆 阅读(131) |
评论 (0) |
编辑 收藏
package com.wyq.hibernate;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class EMailList implements UserType {
private List emails;
private static final char SPLITTER = ';';
private static final int[] TYPES = new int[]{Types.VARCHAR};
public boolean isMutable() {
return false;
}
public int[] sqlTypes() {
return TYPES;
}
public Class returnedClass() {
return List.class;
}
/**
* 创建一个新的List实例,包含原有List实例中的所有元素。
*/
public Object deepCopy(Object value) throws HibernateException {
List sourcelist = (List)value;
List targetlist = new ArrayList();
targetlist.addAll(sourcelist);
return targetlist;
}
/**
* 判断email list是否发生改变
*/
public boolean equals(Object x, Object y) throws HibernateException {
if(x == y)return true;
if(x!=null && y!=null){
List xList = (List)x;
List yList = (List)y;
if(xList.size() != yList.size())return false;
for(int i=0;i<xList.size();i++){
String str1 = (String)xList.get(i);
String str2 = (String)yList.get(i);
if(!str1.equals(str2))return false;
}
return true;
}
return false;
}
/**
* 从resultSet中取出email字段,并将其解析为List类型后返回
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String value = (String)Hibernate.STRING.nullSafeGet(rs,names[0]);
if(value!=null){
return parse(value);
}else{
return null;
}
}
/**
* 将List型的email信息组成字符串后保存到email字段
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
System.out.println("Set method executed");
if(value!=null){
String str = "";//assemble((List)value);
Hibernate.STRING.nullSafeSet(st, str, index);
}else{
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
/**
* 将String拼装为一个字符串,以";"分隔
*/
private String assemble(List emailList){
StringBuffer strBuf = new StringBuffer();
for(int i=0;i<emailList.size()-1;i++){
strBuf.append(emailList.get(i)).append(SPLITTER);
}
strBuf.append(emailList.get(emailList.size()-1));
return strBuf.toString();
}
/**
* 将以";"分隔的字符串解析为一个字符串数组
*/
private List parse(String value){
String[] strs = org.apache.commons.lang.StringUtils.split(value,String.valueOf(SPLITTER));
List emailList = new ArrayList();
for(int i=0;i<strs.length;i++){
emailList.add(strs[i]);
}
return emailList;
}
public Object assemble(Serializable arg0, Object arg1)
throws HibernateException {
// TODO Auto-generated method stub
return null;
}
public Serializable disassemble(Object arg0) throws HibernateException {
// TODO Auto-generated method stub
return null;
}
public int hashCode(Object arg0) throws HibernateException {
// TODO Auto-generated method stub
return 0;
}
public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
// TODO Auto-generated method stub
return null;
}
}
posted @
2009-10-16 16:57 王永庆 阅读(150) |
评论 (0) |
编辑 收藏
我们的目标是为数据逻辑层及业务逻辑层提供更加易于操作的对象,根据这里的情况,将email字段映射为一个List集合
类型是个不错的选择,如何将一个字段映射为List类型,Hibernate并没有提供原生支持,我们必须实现自己的UserType.
package com.wyq.hibernate;
public interface UserType {
/**
* 返回UserType所映射字段的SQL类型(java.sql.Types)
* 返回类型为int[],其中包含了映射各字段的SQL类型代码
* (UserType可以映射到一个或者多个字段)
* @see java.sql.Types
* @return int[] the typecodes
*/
public int[] sqlTypes();
/**
* UserType.nullSafeGet()所返回的自定义数据类型
* @return Class
*/
public Class returnedClass();
/**
* 自定义数据类型的对比方法
* 此方法将用作脏数据检查,参数x,y分别为数据的2个副本
* 如果equals方法返回false,则Hibernate将认为数据发生变化,并将变化更新到库表中
*/
public boolean equals(Object x,Object y)throws HiberanteException;
/**
* 从JDBC ResultSet读出数据,将其转换为自定义类型后返回
* (此方法要求对可能出现的null值进行处理)
* names中包含了当前自定义类型的映射字段名称。
*/
public Object nullSafeGet(ResultSet rs,String[] names,Object owner)throws HibernateException,SQLException;
/**
* 本方法将在Hibernate进行数据保存时被调用
* 我们可以通过PreparedStatement将自定义数据写入对应的库表字段
*/
public void nullSafeSet(PreparedStatement st,Object value,int index)throws HibernateException,SQLException;
/**
* 提供自定义类型的完全复制方法
* 本方法将用作构造返回对象
* 当nullSafeGet方法调用之后,我们获得了自定义数据对象,在向用户返回自定义数据之前,deepCopy方法将被调用,
* 它将根据自定义数据对象构造一个完全拷贝,并将此拷贝返回给用户使用。
* 此时,我们就得到了自定义数据对象的2个版本,第一个是从数据库读出的原始版本,其二是我们通过deepCopy构造的
* 复制版本,原始版本将由Hibernate负责维护,复制版本将由用户使用,原始版本用作稍后的脏数据检查一句;Hibernate
* 将在脏数据检查过程中将这2个版本的数据进行比对,如果数据发生了变化,则执行对应的持久化操作。
* 数据发生了变化,则执行对应的持久化操作。
*/
public Object deepCopy(Object value)throws HibernateException;
/**
* 本类型实例是否可变
*/
public boolean isMutable();
}
posted @
2009-10-16 15:59 王永庆 阅读(156) |
评论 (0) |
编辑 收藏
Java Transaction API(Java事务API) (JTA)Java Transaction API(Application Programming Interface)
什么是JTA Transaction?它有怎样的特点呢?JTA Transaction是指由J2EE Transaction manager去管理的事务。其最大的
特点是调用UserTransaction接口的begin,commit和rollback方法来完成事务范围的界定,事务的提交和回滚。JTA
Transaction可以实现同一事务对应不同的数据库,但是它仍然无法实现事务的嵌套。
分布式事务的规范由OMG的OTS所描述。
JTA是只是一组java接口用于描述,J2ee框架中事务管理器与应用程序,资源管理器,以及应用服务器之间的事务通讯。
它主要包括高层接口即面向应用程序的接口;XAResource接口即面向资源的接口;以及事务管理器的接口。值得注意的是JTA
只提供了接口,没有具体的实现。
JTS是服务OTS的JTA的实现。简单的说JTS实现了JTA接口,并且符合OTS的规范。
资源管理器只要其提供给事务管理器的接口符合XA接口规范,就可以被事务管理器处理。
所以,JTA可以处理任何提供符合XA接口的资源。包括:数据库,JMS,商业对象等等
“Java 事务 API”(JTA)启用两阶段提交功能。当配置 WebSphere Application Server 以访问数据库时,可选择具有
JTA 能力的驱动程序。如果需要两阶段提交功能,则必须使用启用 JTA 的驱动程序。
只要您在事务中调用了多个数据库连接,就需要 JTA。只要您在事务中调用了多个数据库服务器,就需要两阶段提交。这些
连接可以是相同的物理数据库服务器或多个数据库服务器。例如:
* 实体企业 Bean Entity1 在应用程序服务器 AppServer1 中部署。
* 实体企业 Bean Entity2 在应用程序服务器 AppServer1 中部署。
* 会话企业 Bean Session1 在应用程序服务器 AppServer1 中部署。
如果 Session1 对同一事务内的 Entity1 和 Entity2 调用了方法而这两个企业 Bean 正在使用不同的物理数据库连接,则
必须对 Entity1 和 Entity2 使用的数据源启用 JTA。当从相同的数据源对象获取那些连接时,这也是成立的。这需要具有
JTA 能力的驱动程序以提交事务。
当事务涉及到多个进程时,JTA 也是必需的。例如,一个事务可能会涉及在多个应用程序服务器中部署的企业 Bean。
* 实体企业 Bean Entity1 在应用程序服务器 AppServer1 中部署。
* 实体企业 Bean Entity2 在应用程序服务器 AppServer2 中部署。
* 会话企业 Bean Session1 在应用程序服务器 AppServer1 中部署。
如果 Session1 对同一事务(此事务构成一个分布式事务)内的 Entity1 和 Entity2 调用了方法,则必须对 Entity1 和
Entity2 使用的数据源启用 JTA。
性能实现JTA 启用的连接与非 JTA 启用的连接执行情况不同。基于此原因,如果您的应用程序不需要 JTA,则最好使用非
JTA 启用的驱动程序。
posted @
2009-10-16 14:23 王永庆 阅读(721) |
评论 (0) |
编辑 收藏
class属性有一下几种类型:
1、Assiged:主键由应用逻辑产生,数据交由Hibernate保存时,主键值已经设置完毕,无需Hibernate干预。
2、hilo:通过hi/lo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。
3、与hilo类似,通过hi/lo算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库。
4、incremaent:主键按数值顺序递增。此方式的实现机制为在当前应用中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。如果同一数据库有多个实例访问,此方式必须避免使用。
5、identity:采用数据库提供的主键生成机制.
6、sequence:采用数据库提供的sequence机制生成主键
7、native:由Hibernate根据数据库适配器中的定义,自动采用identity、hilo、sequence的其中一种作为主键生成方式。
8、uuid.hex:这种主键生成机制在最大程度上保证了产生ID的唯一性。
9、uuid.string:与uuid.hex类似。
10、foreign:使用外部表的字段作为主键。
由于常用的数据库,如SQLServer、MySql等,都提供了易用的主键生成机制。我们可以在数据库提供的主键生成机制上,采用generator-class=native的主键生成方式。
不过,值得注意的是,一些数据库提供的主键生成机制在效率上未必最佳,大量并发insert数据时可能会引起表之间的互锁。
数据库提供的主键生成机制,往往是通过在一个内部表中保存当前主键状态,之后每次插入数据会读取这个最大值,然后加上递增量作为新记录的主键值,之后再把这个新的最大值更新回内部表中,这样,一次Insert操作可能导致数据库内部多次表读写操作,同时伴随的还有数据的加锁解锁操作,这对性能产生了很大影响。
另外,对于借用Sequence作为主键产生机制的数据库而言,如Oracle,如果采用<generator class="sequence">设定,那么插入一条新的数据之前,Hibernate必须首先向数据库发起一条select sequence操作以获取主键值。
这样,一次保存操作实际上包含了2个过程,首先查询sequence获得主键,其次执行Insert插入记录,无疑操作效率相对较低。
大多数情况下,如果逻辑允许,可以考虑使用uuid.hex主键生成方式。
Hibernate3同时还提供了另一种与实体类型无关的映射方式:动态模型(Dynamic Model),所谓动态模型,即通过通用数据容器(Map)对库表记录进行表达。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class entity-name="DynamicUserMap" table="T_User">
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="name" type="java.lang.String" column="name"/>
<property name="age" type="java.lang.Integer" column="age"/>
</class>
</hibernate-mapping>
操作示例:
session = sessionFactory.openSession().getSession(EntityMode.MAP);
Map userMap = new HashMap();
userMap.put("name","ken");
userMap.put("age",new Integer(25));
Transaction tx = session.beginTransaction();
session.save("DynamicUserMap",userMap);
tx.commit();
首先,我们以EntityMode.MAP模式获取Session实例,以此表明Session操作的对象并非普通的实体类,而是Map类型数据。
其次,在执行实体操作时,须指明要操作的实体名:
session.save("DynamicUserMap",userMap);
posted @
2009-10-16 14:22 王永庆 阅读(208) |
评论 (0) |
编辑 收藏
为了使用Hibernate的Transaction API,我们必须通过hibernate.transaction.factory_class属性指定一个Transaction实例工厂类。Transaction API隐藏了底层的事务机制,允许Hibernate代码在受管制和非受管制的环境下都可以进行。
使用JDBC的事务处理机制:
hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
使用JTA
hiberante.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
jta.UserTransaction jta/usertransaction
O/R映射关系无疑是ORM框架中最为关键的组成部分,在进行Hibernate实体属性映射关系定义时,需要提供属性的数据类型设定,通过这些类型定义,Hibernate即可完成Java数据类型到数据库特定数据类型的映射关系。
实体映射技术作为类与表之间的联系纽带,在ORM实现中起着至关重要的作用。
实体映射的核心内容,即实体类与数据库表之间的映射定义。Hibernate中,类表映射主要包括3个部分内容:
a、表名-类名映射
b、主键映射
c、字段映射
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd>
<hibernate-mapping>
<class name="com.redsage.hibernate.db.entity.TUser" table="T_USER"/>
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="name" column="name" type="java.lang.String"/>
<property name="age" column="age" type="java.lang.Integer"/>
</class>
</hibernate-mapping>
XML文件头定义了本XML文档所采用的编码方式:encoding="UTF-8".并指定了当前XML的DTD,DTD文件对当前XML文档中的节点进行定义,这样我们加载配置文件之前,可通过指定的DTD对当前XML中的节点进行检查,确定XML结构和数据类型是否合法。
通过CLASS节点的配置,hibernate即可获知类与表的映射关系,即每个TUser类对象对应T_User表中的一条记录。
ID节点定义类实体类的标示(identity),在这里也就是对应库表主键的类属性,name="id"指定了当前映射类中的属性"id"对应了T_User表中的主键字段。
column="id"指定了当前映射表T_User唯一标示为"id"字段.id字段是T_User表的一个自增型字段,同时也是T_User表的主键。通过id字段我们即可唯一定位一条记录。
type="java.lang.Integer"指定了当前字段的数据类型。
<generator class="native"/>指定了主键生成方式,这里的class="native"设定,意味着将主键生成机制的实现方式交由hibernate决定,hibernate将根据底层数据库适配器的定义,采用不同数据库特定的主键生成方式。
posted @
2009-10-15 14:58 王永庆 阅读(198) |
评论 (0) |
编辑 收藏