JavaSSH框架技术规范.doc_第1页
JavaSSH框架技术规范.doc_第2页
JavaSSH框架技术规范.doc_第3页
JavaSSH框架技术规范.doc_第4页
JavaSSH框架技术规范.doc_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

航安项目(三期)框架技术规范日期版本简述作者2011年3月1日V1.0指定本系统的技术规范2011年9月25日V2.0指定本系统的技术规范 框架技术规范航安项目框架技术规范目 录1、规范配置说明12、系统三层架构规范配置说明12.1 Dao22.2 Entity42.3 Service43、Spring规范配置说明53.1 IOC配置说明53.2 集成Hibernate配置说明53.3 AOP配置说明64、Hibernate规范配置说明74.1 Hiebernate的基本配置74.2 对象标识符号84.3 Hibernate映射类型94.4 Hibernate的HQL语言105、Struts规范配置说明135.1 struts2-convention插件概述135.2 struts2-convention具体配置及规范说明145.3 Struts.xml配置文件155.4 Web目录规范说明166、JPA规范配置说明176.1 Entity Identity 实体标识176.2 Accessor of Persistent Fields and Properties 持久化值域和属性的访问器186.3 Persistence Context 持久化上下文186.4 Entity Instances Life Cycle 实例对象生命周期196.5 Entity Relationships 实体关系196.6 Inheritance 继承206.7 Optimistic Locking and Concurrency 乐观锁及并发控制206.8 本系统JPA例子216.9JPA注解详细说明22ii框架技术规范1、规范配置说明在JavaEE企业级开发中,以SSH框架为核心的应用非常广泛,航安项目实现全注解式的开发。用到SSH框架的版本为:Struts2.1.6+Spring2.5.6+Hibernate3.6.4+JPA,用到的工作流流程管理框架为JBPM:JBPM4.4,框架(sinoframe)的服务器上SVN的地址是:11/SVN/kuangjia。航安系统(sms)的服务器上SVN的地址是:11/svn/sms。2、系统三层架构规范配置说明这章为大家说明系统的层次结构,并实现除WEB层的部分功能代码,详细代码请在源码中查看。系统一共分为:dao、entity、service、web四层。另外在这些层次下,还以业务功能再进行分包,这样做是为了方便在以后的功能扩展中,能更好的管理和维护代码。如果将所有类都直接集中在这4个包下面,随着类的增加,会越来越难以维护,而且查找起来也很费劲。2.1Dao先建立BaseHibernateDao,它是通过继承Spring提供的DaoSupport来实现持久层的基类,并且封装了一些基本操作方法。这是BaseHibernateDao的部分代码。大家在写Dao时,可以直接继承BasehibernateDao。持久层的Dao类是根据实体类定义,一般是一个实体类就会有一个对应的Dao类。当然这要跟业务需求来设计,不是绝对的。这些定义的方法是供service层调用,在业务层,将不会看到一行与持久层有关的代码,降低藕合性是这样做的目的。Repository注解的作用就是标注这个UserDao是一个持久层组件。component-scan它就是用来将标有Repository,Service这样的注解类扫描到Spring的容器里,并且同时对标有Resource注解的Bean启用了自动注入功能。使用注解的方法,可以告别繁琐的配置文件定义。2.2Entity关于实体的定义就是使用JPA注解。详见JPA规范说明。2.3ServiceService表示这是业务层组件。在业务层需要对调用的Dao类的Set方法加上Resource注解,这里将业务层的方法名与持久层的方法名定义大家可以按自己的想法来做。3、Spring规范配置说明3.1IOC配置说明根据base-package指定的路径,扫描其下所有包含注解的Bean,并自动注入。比如Repository,Service这些都是注解,前者表示持久层,后者表示业务层。有了它,将不用再去写那繁琐的。本系统的主旨就是全注解,就是为了告诉大家不用写配置文件(当然不是绝对不写)来怎样进行开发工作。3.2集成Hibernate配置说明这就是在Spring中定义Hibernate相关的配置,Spring已经集成了这部分功能。通过class里面定义的类名称我们很容易就能理解,这是使用注解的方式映射实体以及创建Hiberante SessionFactory。其中包含了hibernate.dialect、hibernate.show_sql等和数据源JNDI的配置,当applicationContext-common.xml定义好之后,就不用再对它进行修改。详细内容见Hibernate规范。另外在Spring2.5.6版中,加入了一个很有用的小功能,就是packagesToScan属性,它是根据value中定义的路径来扫描其下所有的注解实体类。大象对这个路径做了多种测试,另外又看了源代码,发现它只能匹配某一类型的路径,而不是所有路径。比如上面的value值表示,扫描entity包下面的所有包中的注解类,如果你将类直接放在entity包下,那么服务器启动和程序运行时都不会报错,但是当你的代码需要用到这个类的时候,就会出现异常,提示你找不到实体。 3.3AOP配置说明这是事务定义,而且是使用注解方式定义事务(Transactional)。上面这个就是使用配置式来定义事务,注解式只用写一句话,然后在业务类或方法中加入Transactional这个注解标记,就完成事务声明,不过对于每个业务类都需要在类或方法中加入这些标记。以下为事物传播与隔离机制的参考:事物传播行为介绍:Transactional(propagation=Propagation.REQUIRED) 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)Transactional(propagation=Propagation.NOT_SUPPORTED) 容器不为这个方法开启事务Transactional(propagation=Propagation.REQUIRES_NEW) 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务Transactional(propagation=Propagation.MANDATORY) 必须在一个已有的事务中执行,否则抛出异常Transactional(propagation=Propagation.NEVER) 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)Transactional(propagation=Propagation.SUPPORTS) 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.事物超时设置:Transactional(timeout=30) /默认是30秒事务隔离级别:Transactional(isolation = Isolation.READ_UNCOMMITTED)读取未提交数据(会出现脏读, 不可重复读) 基本不使用Transactional(isolation = Isolation.READ_COMMITTED)读取已提交数据(会出现不可重复读和幻读)Transactional(isolation = Isolation.REPEATABLE_READ)可重复读(会出现幻读)Transactional(isolation = Isolation.SERIALIZABLE)串行化4、Hibernate规范配置说明4.1Hiebernate的基本配置 Hibernate的数据库连接信息是从配置文件中加载的。Hibernate的配置文件有两种形式:一种是XML格式的文件,一种是properties属性文件。本系统是以XML格式的方式集成在Spring的配置文件中。Hibernate配置文件包含了一系列属性的配置(本系统目前是通过JNDI来连接数据库,作为框架搭建阶段,数据库自己选择):#指定数据库使用的驱动类hibernate.connection.driver_class = com.mysql.jdbc.Driver#指定数据库连接串hibernate.connection.url = jdbc:mysql:/localhost:3306/db#指定数据库连接的用户名hibernate.connection.username = user#指定数据库连接的密码hibernate.connection.password = password#指定数据库使用的方言hibernate.dialect = net.sf.hibernate.dialect.MySQLDialect#指定是否打印SQL语句hibernate.show_sql=true #数据库连接池的大小hibernate.connection.pool.size=20#指定Hibernate每次从数据库中取出并放到JDBC的Statement中的记录条数。(Fetch #Size设的越大,读数据库的次数越少,速度越快,Fetch Size越小,读数据库的次数#越多,速度越慢)jdbc.fetch_size=50#指定Hibernate批量插入,删除和更新时每次操作的记录数。(Batch Size越大,批量#操作的向数据库发送Sql的次数越少,速度就越快,同样耗用内存就越大)jdbc.batch_size=23#是否允许Hibernate用JDBC的可滚动的结果集。jdbc.use_scrollable_resultset=false#连接数据库时是否使用Unicode编码Connection.useUnicode=true#连接数据库时数据的传输字符集编码方式,最好设置为gbk,用gb2312有的字符不全connection.characterEncoding=gbk在XML格式的配置文件中,除了基本的Hibernate配置信息,还可以指定具体的持久化类的映射文件,这可以避免将持久化类的配置文件硬编码在程序中。4.2对象标识符号 在关系数据库表中,主键(Primary Key)用来识别记录,并保证每条记录的唯一性。在Java语言中,通过比较两个变量所引用对象的内存地址是否相同,或者比较两个变量引用的对象值是否相同来判断两对象是否相等。Hibernate为了解决两者之间的不同,使用对象标识符(OID)来标识对象的唯一性。OID是关系数据库中主键在Java对象模型中的等价物。在运行时,Hibernate根据OID来维持Java对象和数据库表中记录的对应关系。标识的生成可以使用不同的策略,表1为Hibernate内置的标识生成策略。表1:Hibernate标识生成策略标识符生成器描述increment适用于代理主键。由Hibernate自动以递增方式生成。identity适用于代理主键。由底层数据库生成标识符。sequence适用于代理主键。Hibernate根据底层数据库的序列生成标识符,这要求底层数据库支持序列。hilo适用于代理主键。Hibernate分局high/low算法生成标识符。seqhilo适用于代理主键。使用一个高/低位算法来高效的生成long,short或者int类型的标识符。native适用于代理主键。根据底层数据库对自动生成标识符的方式,自动选择identity、sequence或hilo。uuid.hex适用于代理主键。Hibernate采用128位的UUID算法生成标识符。uuid.string适用于代理主键。UUID被编码成一个16字符长的字符串。assigned适用于自然主键。由Java应用程序负责生成标识符。foreign适用于代理主键。使用另外一个相关联的对象的标识符。4.3Hibernate映射类型 在对象/关系映射文件中,Hibernate采用映射类型作为Java类型和SQL类型的桥梁。Hibernate映射类型分为2种:内置映射类型和自定义映射类型。1、内置映射类型Hibernate对所有的Java原生类型、常用的Java类型如String、Date等都定义了内置的映射类型。表2列出了Hibernate映射类型、对应的Java类型以及对应的标准SQL类型。表2:Hibernate内置映射类型Hibernate映射类型Java类型标准SQL类型大小integer/intjava.lang.Integer/intINTEGER4字节longjava.lang.Long/longBIGINT8字节shortjava.lang.Short/shortSMALLINT2字节bytejava.lang.Byte/byteTINYINT1字节floatjava.lang.Float/floatFLOAT4字节doublejava.lang.Double/doubleDOUBLE8字节big_decimaljava.math.BigDecimalNUMERICcharacterjava.lang.Character/java.lang.String/charCHAR(1)定长字符stringjava.lang.StringVARCHAR变长字符boolean/ yes_no/true_falsejava.lang.Boolean/BooleanBIT布尔类型datejava.util.Date/java.sql.DateDATE日期timestampjava.util.Date/java.util.TimestampTIMESTAMP日期calendarjava.util.CalendarTIMESTAMP日期calendar_datejava.util.CalendarDATE日期binarybyteBLOBBLOBtextjava.lang.StringTEXTCLOBserializable实现java.io.Serializablej接口的任意Java类BLOBBLOBclobjava.sql.ClobCLOBCLOBblobjava.sql.BlobBLOBBLOBclassjava.lang.ClassVARCHAR定长字符localejava.util.LocaleVARCHAR定长字符timezonejava.util.TimeZoneVARCHAR定长字符currencyjava.util.CurrencyVARCHAR定长字符2、自定义映射类型Hibernate提供了自定义映射类型接口,允许用户以编程的方式创建自定义的映射类型。用户自定义的映射类型需要实现net.sf.hibernate.UserType或net.sf.hibernate.CompositeUserType接口。具体的创建自定义映射类型的方法请参考hibernate官方文档或相关资料,这里不再详细介绍。4.4Hibernate的HQL语言传统的SQL语言采用的是结构化的查询方法,而这种方法对于查询以对象形式存在的数据却无能为力。幸运的是,Hibernate为我们提供了一种语法类似于SQL的语言,Hibernate查询语言(HQL),和SQL不同的是,HQL是一种面向对象的查询语言,它可以查询以对象形式存在的数据。因此,本文就HQL如何工作以及如何使用HQL展开了深入的讨论。 SQL本身是非常强大的。当SQL的这种强大和处理面向对象数据的能力相结合时,就产生了HQL。和SQL一样,HQL提供了丰富的查询功能,如投影查询、聚合函数、分组和约束。任何复杂的SQL都可以映射成HQL。本文的第一部分将讨论HQL的简单用法。第二部分将讨论在HQL中如何根据上下文关系进行查询。在第三部分将以一个例子来说明如何在实际应用中使用HQL。一个ORM框架是建立在面向对象的基础上的。最好的例子是Hibernate如何提供类SQL查询。虽然HQL的语法类似于SQL,但实际上它的查询目标是对象。HQL拥有面向对象语言的所有的特性,这其中包括多态、继承和组合。这就相当于一个面向对象的SQL,为了提供更强大的功能,HQL还提供了很多的查询函数。这些函数可以被分为四类:1. 投影函数2. 约束函数3. 聚合函数4. 分组函数使用HQL可以建立简单的查询,也可以建立更复杂的查询。在本文中并不讨论那些非常复杂的查询,如含有子查询和很多连接的查询。本文只讨论连接两个表的查询。投影如谓投影,就是一个可以访问的对象或对象的属性。在HQL中,可以使用from和select子句来完成这个工作。from子句返回指定的类的所有实例。如from Order将返回Order类的所有实例。换句话说,以上的查询相当于以下的SQL语句:select * from orderfrom 是最简单的查询子句。from后面可以跟一个或多个类名(类名也可以带有别名)。为了得到Order和Product的所有实例,可以使用如下的查询:from Order, Product和类名一样,别名也可以在from后使用,如下代码如示:from Order as o, Product p当查询很复杂时,加入别名可以减少语句的长度。我们可以看看如下的SQL语句:select o.*, p.* from order o, product p where o.order_id = p.order_id我们可以很容易看出,上面的查询是一对多的关系。在HQL中相当于一个类中包含多个其它类的实例。因此,以上的SQL写成HQL就是:from Order as o inner join ducts as product现在让我们考虑另外一个从表中得到指定属性的情况。这就是最常用的select子句。这在HQL中的工作方式和SQL中一样。而在HQL中,如果只是想得到类的属性的话,select语句是最后的选择。以上的SQL可以使用select子句改成如下的HQL语句:select product from Order as o inner join ducts as product以上的HQL语句将返回Order中的所有Products实例。如果要得到对象的某一个属性,可以将HQL语句写成如下的形式:select from Order as o inner join ducts as product如果要得到多个对象的属性,可以将HQL语句写成如下形式:select o.id, from Order as o inner join ducts as product接下来,我们将进入下一个议题。假设我们需要根据某些条件得到数据。那么以上所述的HQL语句将无法满足需求。为了达到这一目的,我们就要用到下面将要讨论的约束子句。约束从以上可知,投影返回的是所有的数据。但在大多数时候我们并不需要这么多数据。这就需要对数据进行过滤。在HQL中过滤数据的子句和SQL一样,也是where。它的语法类似于SQL,通过where子句,可以对行进行过滤。我们可以看看下面的SQL语句:select * from orders where id = 1234这条查询语句返回了id等于1234的所有的字段。和这条SQL对等的是下面的HQL语句:select o from Order o where o.id=1234从以上两条语句可以看出,它们的where子句非常相似。而它们唯一的不同是SQL操作的是记录,而HQL操作的是对象。在HQL中,除了where子句可以过滤数据外,having子句也可以做到这一点(关于having子句的详细内容我将在分组部分讨论)。投影和约束是两个基本的操作,这两个操作再加上聚合函数的话,那HQL将变得更加强大。聚合上述的查询都是将每一个记录(对象)当做一个单位,而如果使用聚合,可以将一类记录(对象)当做一个单位。然后再对每一类的记录(对象)进行一系列地操作,如对某一列取平均值、求和、统计行数等等。HQL支持以下的聚合函数:1. avg(), sum()2. min(), max()3. count(*), count(), count(distinct), count(all)以上的聚合函数都返回数值类型。这些操作都可以在select子句中使用,如下所示:select max(o.priceTotal) + max(p.price) from Order o join ducts p group by o.id以上的HQL语句返回了两个值的和:orders表中的priceTotal的最大值和products表中的price的最大值之和。我们还可以使用having子句对分组进行过滤。如我们想按id统计priceTotal小于1000的数量可按如下的HQL语句去实现:select count(o) from Order o having o.priceTotal 1000 group by o.id我们还可以将聚合函数和having子句一起使用。如我们要按products表的id统计price小于amount的平均数的产品数量,HQL语句如下:select count(p) from Product p having p.price = 1200 and o.priceTotal = 3200 group by o.idHQL中的分组和SQL中的分组类似。总之,除了一些对SQL的特殊扩展外,其它所有的SQL功能都可以使用HQL描述。HQL并不区分字母的大小写,但在HQL中的Java类和属性名必须和实际的类和属性名一致。如SELECT和select之间可以互换,但Order和order却代表不同的含义。如果HQL中引用的类未被导入,在HQL中必须引用具体的包。5、Struts规范配置说明5.1struts2-convention插件概述Struts2做到用注解来代替配置文件,本系统struts2-convention插件完成这一功能。它是struts2提供的一个插件。官方文档 /WW/convention-plugin.html5.2struts2-convention具体配置及规范说明struts2-convention这个插件它会默认扫描所有包名为struts、struts2、action、actions下面的类。然后它会对实现了Action接口以及类名以Action结尾的这些类,作为Action来进行处理。也可以重新定义按哪种包名进行扫描。比如本例设定,只扫描action包下面的所有类,因为我们将Action类都放在这个包下面。那这个插件是怎么实现原来的配置信息的呢?它的映射规则是这样的,对于以Action结尾的的类,去掉Action,取剩下的部分,将所有的字母转换为小写,如果有驼峰式的写法,则用-连接符来连接不同的单词,这是此插件的默认方式。最终转换之后的就是请求地址,还是用例子说明。com.bolo.examples.web.base.UserAction 按照上面的规则,请求地址就应该是UserAction去掉Action后缀,将其余部分转换为小写,所以user就是我们的请求地址。不过,这还没有完,因为这里面还有一个命名空间的路径,在通常的配置文件中,一般会将不同的功能进行划分,在package标签里加上namespace属性。使用这个插件,它会为你自动配上命名空间,默认的就是前面说到的以那四种名称为根目录的命名空间,它们之后的都将成为命名空间的名称。com.bolo.examples.struts.UserAction映射为 /user.actioncom.bolo.examples.struts.base.UserAction映射为 /base/user.action要是我们不以struts或其它几种默认值为包名,又该怎么办呢?没关系,插件为我们提供了一种自定义根包的配置方式上面这段配置是写在struts.xml里面的,它指定web为根,作用就相当于那四种默认值。com.bolo.examples.web.base.UserAction映射为 /base/user.actioncom.bolo.examples.web.HelloAction映射为 /hello.actioncom.bolo.examples.web.HelloWorldAction映射为 /hello-world.action请一定注意驼峰写法的映射方式,假如这里不是HelloWorld,而是Helloworld,那就不会再是hello-world.action,而是helloworld.action了。既然已经知道了它的映射方式,接下来再看看这个插件是如何定义结果页面的。convention默认会到/WEB-INF/content文件夹下面查找对应的结果页面,这个文件夹的名字可以修改,需要在struts.xml中定义文件夹的名字改成了jsp,这样定义后,convention就会在这个文件夹下面查找结果页面。它的查找路径与映射的命名空间有关。默认规则是,在请求的命名空间下面,根据请求名称再结合方法返回的字符串生成最终的结果页面名称,再配以后缀名。convention支持以jsp、ftl、vm、html、htm等五种后缀格式的文件。这里有个比较特殊的是如果方法返回success,那么可以不用将它与请求名称拼接起来,直接使用请求名称作为返回页面的名称。还是举例子说明。比如上面这段代码,HelloAction处于我们定义的根包(web)下面,因此,它的action请求为hello.action。这时,会默认执行execute()方法,由于返回的是success字符串,所以页面的名称可以简写为hello.jsp,但是当执行welcome方法时,由于返回的字符串为welcome,这时的页面名称则为hello-welcome.jsp。convention就是遵循这样的规则来进行命名。更具体的例子大家可以查看SVN的源码例子(kuangjia)。根据实际使用情况,发现动态参数的传递在struts2.1.6存在BUG,如果需要使用这个功能,请将struts2升级到版。根据实际应用,建议大家统一在类名上面定义Results设置,这样做有利于开发与维护。5.3Struts.xml配置文件Struts.xml5.4Web目录规范说明Web对于web层,代码很简单,因为本例子主要是讲convention插件的知识,然后实现一部分功能用于演示它的效果。下面贴上web和WebRoot目录结构、几个Action的部分代码,以及jsp代码。请注意web包下面的层次结构,这与你的请求路径相关。content文件夹是插件默认指定的名字,你可以修改为别的名字。同样请注意在这个目录下面的文件与子文件夹的定义方式是和web层相同的。更具体的了解请结合源码例子(kuangjia)。6、JPA规范配置说明Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用的对象持久化的开发工作;其二,Sun希望整合对ORM技术,实现天下归一。目前,JPA(Java Persistence API)的使用范围越来越广,作为Java EE 5.0平台标准的ORM规范,得到了诸如:Hibernate、TopLink、OpenJpa等ORM框架的支持,同时还是EJB 3.0的重要组成部分。JPA的宗旨是为POJO提供持久化标准规范。它能够脱离容器独立运行,方便开发和测试。6.1Entity Identity 实体标识 一般采用单一值做为entity identity,采用compsite primary key时,必须单独建立一个表示主键的类primary key class主键类。这样在实体上compsite primary key就可以用一个属性(primary key class类型)表示持久化框架内部很多地方使用entity identity进行处理,因此primary key class要正确实现equals、hashCode方法,另外应用层需要注意,对persistence context中受管理的对象,不要修改主键值,否则持久化框架无法承诺带来的影响,因为persistence context只能基于entity identity标识实体身份。6.2Accessor of Persistent Fields and Properties 持久化值域和属性的访问器 Persistent state(即需要持久化的fields或properties)的存取分2种类型:field-based和property-based、field-based时,持久化框架直接存取instance variables,property-based时则通过getter、setter方法存取。使用property-based时,在setter、getter方法中可能包含业务逻辑,对于应用层而言,需要注意的是持久化框架从数据库加载数据,为实体属性赋值时,各属性的赋值顺序是无法承诺的,因此getter、setter中的业务逻辑需要注意这一点另外使用property-based时如果还将属性声明为lazy-fetching,则应用层不应当访问相应的instance variable,因为持久化框架可能对setter、getter进行注入以实现lazy-fetching,直接访问instance variable可能获取不到值,对于集合类型,JPA规定必须使用java.util下面的Collection、Set、Map、List这几个接口。6.3Persistence Context 持久化上下文 Persistence Context是持久化框架需要维护的一个中间容器,其中会存放受管理对象的副本,例如从数据库获取的实体对象,或者调用持久化框架保存过的对象等主要作用有:缓存(例如NHibernate的一级缓存概念)、支持Flush操作、辅助实现实体以及属性的Dirty检查等。JPA将persistence context分为2种类型:PersistenceContextType.TRANSACTION和 PersistenceContextType.EXTENDED。TRANSACTION类型(默认类型)的persistence context生命周期与transaction scope一致,例如事务开始时为生命周期的开始阶段,事务提交或回滚时生命周期结束。EXTENDED类型的生命周期基本与EntityManager 一致,在EntityManager创建时开始,在EntityManager关闭时结束。实现Extended类型的persistence context时需要注意其生命周期可能跨越多个事务以及不在事务范围内的情况,伴随的是这些情况下对persistence context中实例对象生命周期以及相关操作的影响,例如version控制等6.4Entity Instances Life Cycle 实例对象生命周期 实例对象的生命周期有4种状态:New: 新创建的实例对象,没有identity值Managed: 在持久化上下文中受管理的对象 Detached: 游离于持久化上下文之外的实例对象Removed: 被删除的实例对象JPA中详细定义了实例对象伴随着EntityManager的各种操作时,生命周期状态间的转换关系,JPA声明了entity instance life cycle的几个callback方法:PrePersist、PostPersist、PreRemove、PostRemove、 PreUpdate、PostUpdate、PostLoad,对其语义进行了比较详细的说明。6.5Entity Relationships 实体关系 JPA定义了one-to-one、one-to-many、many-to-one、many-to-many 4种关系。在关联关系的2方之中,关系的所有者一方为owning side,另一方为inverse side。关系的所有者可以这样来理解,将所有者一方的实例删除后,这个2方关系的任何信息都彻底消失。假如逻辑上表A有一个外键,引用自表B的主键(所谓逻辑上是指数据库中并没有建立这个外键关系),如果将表B中某条数据b1删除,A、B间相应实例对象的关联关系可能并不会彻底消除,因为表A中可能还存在某数据a1引用了b1的主键值,因此与B对应的实体类就不是owning side了。因此拥有外键的一方就是owning side了,这个在one-to-one的关系中比较清晰;one-to-many、many-to-one中,many的一方为owning side;many-to-many中任何一方都可以作为owning side,Owning side、inverse side将作为cascade相关操作的依据之一。JPA详细定义了默认情况下对以下一些映射的处理方式:双向one-to-one;双向one-to-many、many-to-one;单向single-valued(单向one-to-one、 many-to-one);双向many-to-many;单向multi-valued(单向one-to-many、many-to-many)。6.6Inheritance 继承 Inheritance Mapping Strategies包括:Single table per class hierarchy,使用一个discriminator column区别子类,优点是很好的支持多态关系、查询,缺点是子类独有的字段需要允许为null;Table per concrete entity class,缺点是不好支持多态关系,通常需要对各子类分别使用单独的SQL或者使用UNION语句。Joined subclass,与table per concrete entity class区别是,将公共属性的superclass使用一个表存储,这种策略也能较好的支持多态关系,缺点是需要多个JOIN关系。6.7Optimistic Locking and Concurrency 乐观锁及并发控制 JPA默认应用层将使用乐观锁机制,使用乐观锁时entity必须声明一个version属性,该字段的值由持久化框架自动维护,应用层不能修改。持久化框架可以引入其它机制实现乐观锁检查,或者实现更细粒度的乐观锁控制,JPA不做要求。JPA的乐观锁机制是基于数据行的,声明了Lock Mode,可以实现悲观锁效果,至于实现方式不作具体要求,只要确保不存在P1: dirty read、P2: non-repeatable read就行。LockModeType有READ和WRITE 2种,对于WRITE模式,在isolation level为read commited情况下数据库可以确保不会出现P1、P2两种状况;READ模式一般使用数据库的锁实现,用它实现悲观锁效果。实现JPA规范的查询语言时,需要重点处理的一个方面是多态查询,语句中的实体类名有可能是abstract的或者supperclass,查询解析器需要能够处理这种多态查询。例如NHibernate(目前版本不知是否改成了Antlr来解析)在分析查询语句时比较简化处理,每遇到实体类都搜索是否有子类存在,如果有则会为每个子类生成一个查询语句,使用JOIN、UNION或者单独执行每个语句再将结果合并(NHibernate不支持Union Subclass),只实现了部分多态能力。要实现完全的多态能力,面对的情况以及需要处理的东西都比较复杂。其它一些细节方面的东西也非常多,例如persistence context可能缓存了一些更新操作,等待Flush时回写数据库,但为了保证查询结果的一致性,执行查询前至少需要先将persistence context中相关实体的更新缓存运用到数据库中。6.8本系统JPA例子本系统在Hibernate中使用JPA。在com.fss.bean包下定义CmmUsernameTest类,这个就是POJO类下面是部分代码。这是其中几个属性的getter和setter方法,这里用到ejb3-persistence.jar,JPA的注解类就在这个包中,下面是上面使用到的注解。Entity:通过Entity注解将一个类声明为一个实体bean。Table:通过 Table注解可以为实体bean映射指定表,name属性表示实体所对应表的名称,如果没有定义 Table,那么系统自动使用默认值:实体的类名(不带包名)Id:用于标记属性的主键。Column:表示持久化属性所映射表中的字段,如果属性名与表中的字段名相同,则可以省略。Column注解,另外有两种方式标记,一是放在属性前,另一种是放在getter方法前,例如:如果属性名与字段名设成一样的,这样可以省掉Column注解。以下是JPA注解更详细说明。6.9JPA注解详细说明1、Entity(name=EntityName)必须,name为可选,对应数据库中一的个表。2、Table(name=,catalog=,schema=)可选,通常和Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息;name:可选,表示表的名称。默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名;catalog:可选,表示Catalog名称,默认为Catalog();schema:可选,表示Schema名称,默认为Schema()。3、id必须,id定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键。置于getXxxx()前。4、GeneratedValue(strategy=GenerationType,generator=)可选,strategy:表示主键生成策略,有AUTO,INDENTITY,SEQUENCE和TABLE 4种,分别表示让ORM框架自动选择,根据数据库的Identity字段生成,根据数据库表的Sequence字段生成,以有根据一个额外的表生成主键,默认为AUTO;generator:表示主键生成器的名称,这个属性通常和ORM框架相关,例如,Hibernate可以指定uuid等主键生成方式。示例:IdGeneratedValues(strategy=StrategyType.SEQUENCE)public int getPk() return pk;5、Basic(fetch=FetchType,optional=true)可选,Basic表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法,默认即为Basic;fetch:表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支抓取和延迟加载,默认为EAGER;optional:表示该属性是否允许为null,默认为true。示例:B

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论