Java Web2.0项目开发进阶---Hibernate 对标注的支持,用EJB3注解进行映射

本文主要是介绍Java Web2.0项目开发进阶---Hibernate 对标注的支持,用EJB3注解进行映射,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

现在EJB3实体Bean是纯粹的POJO.实际上这表达了和Hibernate持久化实体对象同样的概念. 它们的映射都通过JDK5.0注解来定义(EJB3规范中的XML描述语法至今还没有最终定下来). 注解分为两个部分,分别是逻辑映射注解和物理映射注解, 通过逻辑映射注解可以描述对象模型,类之间的关系等等, 而物理映射注解则描述了物理的schema,,,索引等等. 下面我们在代码中将混合使用这两种类型的注解.

EJB3注解的API定义在javax.persistence.*包里面. 大部分和JDK5兼容的IDE(Eclipse, IntelliJ IDEA Netbeans等等)都提供了注解接口和属性的自动完成功能. (这些不需要IDE提供特别的EJB3支持模块,因为EJB3注解是标准的JDK5注解)

请阅读JBoss EJB 3.0指南或者直接阅读Hibernate Annotations测试代码以获取更多的可运行实例.Hibernate Annotations提供的大部分单元测试代码都演示了实际的例子,是一个获取灵感的好地方.

12.13.1  声明实体bean

每一个持久化POJO类都是一个实体bean,这可以通过在类的定义中使用@Entity注解来进行声明:

@Entity

public class Flight implements Serializable {

    Long id;

    @Id

    public Long getId() { return id; }

 

    public void setId(Long id) { this.id = id; }

}

通过@Entity注解将一个类声明为一个实体bean(即一个持久化POJO), @Id注解则声明了该实体bean的标识属性. 其他的映射定义是隐式的.这种以隐式映射为主体,以显式映射为例外的配置方式在新的EJ3规范中处于非常重要的位置, 和以前的版本相比有了质的飞跃. 在上面这段代码中:Flight类映射到Flight,并使用id列作为主键列.

在对一个类进行注解时,你可以选择对它的的属性或者方法进行注解,根据你的选择,Hibernate的访问类型分别为 fieldproperty. EJ3规范要求在需要访问的元素上进行注解声明,例如,如果访问类型为 property就要在getter方法上进行注解声明, 如果访问类型为 field就要在字段上进行注解声明.应该尽量避免混合使用这两种访问类型. Hibernate根据@Id @EmbeddedId的位置来判断访问类型.

12.13.2  定义表

@Table是类一级的注解, 通过@Table注解可以为实体bean映射指定表(table),目录(catalog)schema的名字. 如果没有定义@Table,那么系统自动使用默认值:实体的短类名(不附带包名).

@Entity

@Table(name="tbl_sky")

public class Sky implements Serializable {

...

@Table元素包括了一个schema 和一个 catalog属性,如果需要可以指定相应的值. 结合使用@UniqueConstraint注解可以定义表的唯一约束(unique constraint) (对于绑定到单列的唯一约束,请参考@Column注解)

@Table(name="tbl_sky",

            uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}

        )

上面这个例子中,monthday这两个字段上定义唯一约束. 注意columnNames数组中的值指的是逻辑列名.

HibernateNamingStrategy的实现中定义了逻辑列名. 默认的EJB3命名策略将物理字段名当作逻辑字段名来使用. 注意该字段名和它对应的属性名可能不同(如果字段名是显式指定的话). 除非你重写了NamingStrategy,否则不用担心这些区别..

12.13.3  乐观锁定版本控制

你可以在实体bean中使用@Version注解,通过这种方式可添加对乐观锁定的支持:

@Entity

public class Flight implements Serializable {

...

    @Version

    @Column(name="OPTLOCK")

    public Integer getVersion() { ... }

} 

上面这个例子中,version属性将映射到 OPTLOCK, entity manager使用该字段来检测更新冲突(防止更新丢失,请参考last-commit-wins策略).

根据EJB3规范,version列可以是numeric类型(推荐方式)也可以是timestamp类型. Hibernate支持任何自定义类型,只要该类型实现了UserVersionType.

12.13.4  属性映射

1.声明基本的属性映射

实体bean中所有的非statictransient的属性都可以被持久化, 除非你将其注解为@Transient.所有没有定义注解的属性等价于在其上面添加了@Basic注解. 通过 @Basic注解可以声明属性的获取策略(fetch strategy)

public transient int counter; //transient property

private String firstname; //persistent property

@Transient

String getLengthInMeter() { ... } //transient property

String getName() {... } // persistent property

@Basic

int getLength() { ... } // persistent property

@Basic(fetch = FetchType.LAZY)

String getDetailedComment() { ... } // persistent property

@Temporal(TemporalType.TIME)

java.util.Date getDepartureTime() { ... } // persistent property          

@Enumerated(EnumType.STRING)

Starred getNote() { ... } //enum persisted as String in database

上面这个例子中,counter是一个transient的字段, lengthInMetergetter方法被注解为@Transient, entity manager将忽略这些字段和属性. name,length,firstname 这几个属性则是被定义为可持久化和可获取的.对于简单属性来说,默认的获取方式是即时获取(early fetch). 当一个实体Bean的实例被创建时,Hibernate会将这些属性的值从数据库中提取出来,保存到Bean的属性里. 与即时获取相对应的是延迟获取(lazy fetch).如果一个属性的获取方式是延迟获取 (比如上面例子中的detailedComment属性), Hibernate在创建一个实体Bean的实例时,不会即时将这个属性的值从数据库中读出. 只有在该实体Bean的这个属性第一次被调用时,Hibernate才会去获取对应的值. 通常你不需要对简单属性设置延迟获取(lazy simple property),千万不要和延迟关联获取(lazy association fetch)混淆了 (译注:这里指不要把lazy simple propertylazy association fetch混淆了).

注意

为了启用属性级的延迟获取,你的类必须经过特殊处理(instrumented) 字节码将被织入原始类中来实现延迟获取功能, 详情参考Hibernate参考文档.如果不对类文件进行字节码特殊处理, 那么属性级的延迟获取将被忽略.

推荐的替代方案是使用EJB-QL或者Criteria查询的投影(projection)功能.

HibernateEJB3都支持所有基本类型的属性映射. 这些基本类型包括所有的Java基本类型,及其各自的wrapper类和serializable. Hibernate Annotations还支持将内置的枚举类型映射到一个顺序列(保存了相应的序列值) 或一个字符串类型的列(保存相应的字符串).默认是保存枚举的序列值, 但是你可以通过@Enumerated注解来进行调整(见上面例子中的note属性).

在核心的Java API中并没有定义时间精度(temporal precision). 因此处理时间类型数据时,你还需要定义将其存储在数据库中所预期的精度. 在数据库中,表示时间类型的数据有DATE, TIME, TIMESTAMP三种精度(即单纯的日期,时间,或者两者兼备). 可使用@Temporal注解来调整精度.

@Lob注解表示属性将被持久化为Blob或者Clob类型, 具体取决于属性的类型, java.sql.Clob, Character[], char[] java.lang.String这些类型的属性都被持久化为Clob类型, java.sql.Blob, Byte[], byte[] serializable类型则被持久化为Blob类型.

@Lob

public String getFullText() {

    return fullText;

}

@Lob

public byte[] getFullCode() {

    return fullCode;

}

如果某个属性实现了java.io.Serializable同时也不是基本类型, 并且没有在该属性上使用@Lob注解, 那么Hibernate将使用自带的serializable类型.

2.声明列属性

使用 @Column 注解可将属性映射到列. 使用该注解来覆盖默认值(关于默认值请参考EJB3规范). 在属性级使用该注解的方式如下:

不进行注解

@Basic一起使用

@Version一起使用

@Lob一起使用

@Temporal一起使用

@org.hibernate.annotations.CollectionOfElements一起使用 (只针对Hibernate )

@Entity

public class Flight implements Serializable {

...

@Column(updatable = false, name = "flight_name", nullable = false, length=50)

public String getName() { ... }

在上面这个例子中,name属性映射到flight_name. 该字段不允许为空,长度为50,并且是不可更新的(也就是属性值是不变的).

上面这些注解可以被应用到正规属性上例如@Id @Version属性.

@Column(

    name="columnName";                                (1)

    boolean unique() default false;                   (2)

    boolean nullable() default true;                  (3)

    boolean insertable() default true;                (4)

    boolean updatable() default true;                 (5)

    String columnDefinition() default "";             (6)

    String table() default "";                        (7)

    int length() default 255;                         (8)

    int precision() default 0; // decimal precision   (9)

    int scale() default 0; // decimal scale

(1) name 可选,列名(默认值是属性名)

 (2) unique 可选,是否在该列上设置唯一约束(默认值false)

 (3) nullable 可选,是否设置该列的值可以为空(默认值false)

 (4) insertable 可选,该列是否作为生成的insert语句中的一个列(默认值true)

 (5) updatable 可选,该列是否作为生成的update语句中的一个列(默认值true)

 (6) columnDefinition 可选: 为这个特定列覆盖SQL DDL片段 (这可能导致无法在不同数据库间移植)

 (7) table 可选,定义对应的表(默认为主表)

 (8) length 可选,列长度(默认值255)

 (8) precision 可选,列十进制精度(decimal precision)(默认值0)

 (10) scale 可选,如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)

3.嵌入式组件

在实体中可以定义一个嵌入式组件(embedded component), 甚至覆盖该实体中原有的列映射. 组件类必须在类一级定义@Embeddable注解. 在特定的实体的关联属性上使用@Embedded @AttributeOverride注解可以覆盖该属性对应的嵌入式对象的列映射:

 

@Entity

public class Person implements Serializable {

    // Persistent component using defaults

    Address homeAddress;

    @Embedded

    @AttributeOverrides( {

            @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),

            @AttributeOverride(name="name", column = @Column(name="bornCountryName") )

    } )

    Country bornIn;

    ...

}

 

@Embeddable

public class Address implements Serializable {

    String city;

    Country nationality; //no overriding here

}

 

@Embeddable

public class Country implements Serializable {

    private String iso2;

    @Column(name="countryName") private String name;

    public String getIso2() { return iso2; }

    public void setIso2(String iso2) { this.iso2 = iso2; }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    ...

}

嵌入式对象继承其所属实体中定义的访问类型 (注意:这可以通过使用Hibernate提供的@AccessType注解来覆盖原有值)(请参考 Hibernate Annotation Extensions).

 

在上面的例子中,实体bean Person 有两个组件属性, 分别是homeAddressbornIn. 我们可以看到homeAddress 属性并没有注解. 但是Hibernate自动检测其对应的Address类中的@Embeddable注解, 并将其看作一个持久化组件.对于Country中已映射的属性, 则使用@Embedded@AttributeOverride 注解来覆盖原来映射的列名. 正如你所看到的, Address对象中还内嵌了Country对象, 这里和homeAddress一样使用了HibernateEJB3自动检测机制. 目前EJB3规范还不支持覆盖多层嵌套(即嵌入式对象中还包括其他嵌入式对象)的列映射. 不过Hibernate通过在表达式中使用"."符号表达式提供了对此特征的支持.

@Embedded

    @AttributeOverrides( {

            @AttributeOverride(name="city", column = @Column(name="fld_city") ),

            @AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),

            @AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )

            //nationality columns in homeAddress are overridden

    } )

    Address homeAddress;

Hibernate注解支持很多EJB3规范中没有明确定义的特性. 例如,可以在嵌入式对象上添加 @MappedSuperclass注解, 这样可以将其父类的属性持久(详情请查阅@MappedSuperclass).

Hibernate现在支持在嵌入式对象中使用关联注解(@*ToOne@*ToMany). EJB3规范尚不支持这样的用法。你可以使用 @AssociationOverride注解来覆写关联列.

在同一个实体中使用两个同类型的嵌入对象, 其默认列名是无效的:至少要对其中一个进行明确声明. Hibernate在这方面走在了EJB3规范的前面, Hibernate提供了NamingStrategy, 在使用Hibernate, 通过NamingStrategy你可以对默认的机制进行扩展. DefaultComponentSafeNamingStrategy 在默认的EJB3NamingStrategy上进行了小小的提升, 允许在同一实体中使用两个同类型的嵌入对象而无须额外的声明.

如果某属性没有注解,该属性将遵守下面的规则:

 

如果属性为单一类型,则映射为@Basic

否则,如果属性对应的类型定义了@Embeddable注解,则映射为@Embedded

否则,如果属性对应的类型实现了Serializable, 则属性被映射为@Basic并在一个列中保存该对象的serialized版本

否则,如果该属性的类型为java.sql.Clob java.sql.Blob,则作为@Lob并映射到适当的LobType.

 

 

这篇关于Java Web2.0项目开发进阶---Hibernate 对标注的支持,用EJB3注解进行映射的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/849467

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD