在过去几年里,Hibernate不断发展,几乎成为Java数据库持久性的事实标准。它非常强大、灵活,而且具备了优异的性能。在本文中,我们将了解如何使用Java 5 注释来简化Hibernate代码,并使持久层的编码过程变得更为轻松。
传统上,Hibernate的配置依赖于外部 XML 文件:数据库映射被定义为一组 XML 映射文件,并且在启动时进行加载。
在最近发布的几个Hibernate版本中,出现了一种基于 Java 5 注释的更为巧妙的新方法。借助新的 Hibernate Annotation 库,即可一次性地分配所有旧映射文件--- 一切都会按照您的想法来定义——注释直接嵌入到您的Java 类中,并提供一种强大及灵活的方法来声明持久性映射。
目前,JPA(Java Persistence API)的使用范围越来越广,作为Java EE 5.0平台标准的ORM规范,得到了诸如:Hibernate、TopLink、OpenJpa等ORM框架的支持,同时还是EJB 3.0的重要组成部分。JPA的宗旨是为POJO提供持久化标准规范。它能够脱离容器独立运行,方便开发和测试。本文将通过一个小实例来说明如何在Hibernate中使用JPA,来达到简化编程的目的。
Hibernate Annotations核心注解
Java代码
@Entity 声明当前是一个持久化类
@Table 设置当前持久化类所映射的数据库表,如果当前类中没有使用@Table 注解,Hibernate会自动使用默认的持久化类的类名(不带包名)作为所映射的表名
@Id 设置当前持久化类的标示符属性
@GeneratedValue 设置当前标示符的生产策略。@GeneratedValue的name属性设置生成策略的名称是TABLE、INENTITY、SEQUENCE或者AUTO之一。
@Column 将持久化类的数学与数据库表中的字段进行映射,name属性值为映射的字段名,length属性值为字段的长度,unique属性表示该列上设置唯一的约束,nullable属性设置该列的值是否可以为空,precision实现设置该字段的精度,scale属性设置该字段的小数位数
@Transient 标注的属性进行持久化映射
@Temporal java中没有定义时间精度的api,因此处理时间类型数据时,需要设置存储在数据库中所预期的精度,使用@Temporal注释可以调整时间的精度为:DATE、TIME和TIMESTAMP三种
@ManyToOne 设置该当前持久化类类与其他持久化类之间的多对一关联,其中CascadeType值表示Hibernate将进行级联操作
@OneToMany 设置该当前持久化类与其他持久化类之间的一对多关联
@OneToOne 设置该当前持久化类与其他持久化类之间的一对一关联
@ManyToMany 设置该当前持久化类与其他持久化类之间的多对多关联
@NameQueries 在持久化类中设置命名查询,参考@NameQuery的使用
@NameQuery 在持久化类中设置命名查询,@NamedQuery 和@NamedQueries注释加在在类和包上。如下面的例子:
@NamedQueries({@NamedQuery(name="queryById",query="select p from Product p where id=:id")})
@Version 设置乐观锁定
@Cache 设置二级缓存
@Filters 设置使用过滤器
@FilterDef 声明过滤器
demo
比如有2个表 一个CATEGORY
Sql代码
-- Create table
create table CATEGORY
(
ID NUMBER(8) not null,
NAME NVARCHAR2(200),
DESCRIPTION VARCHAR2(1000)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table CATEGORY
add constraint CATEGORY_PK primary key (ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
一个PRODUCT
Sql代码
-- Create table
create table PRODUCT
(
ID NUMBER(8) not null,
NAME VARCHAR2(200),
PRICE NUMBER(6,2),
DESCRIPTION VARCHAR2(1000),
CREATE_TIME DATE,
CATEGORY_ID NUMBER(8)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table PRODUCT
add constraint PRODUCT_PK primary key (ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table PRODUCT
add constraint PRODUCT_FK foreign key (CATEGORY_ID)
references CATEGORY (ID);
可用MyEclipse 生成对应的持久化类,区别 平时的Hibernate 创建的都是*.hbm.xml而现在是
add Hibernate mapping annotations to POJO
Category.java
Java代码
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "CATEGORY", schema = "SCOTT")
public class Category implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String description;
private Set<Product> products = new HashSet<Product>(0);
public Category() {
}
// Property accessors
@GenericGenerator(name = "generator", strategy = "increment")
@Id
@GeneratedValue(generator = "generator")
@Column(name = "ID", unique = true, nullable = false, precision = 8, scale = 0)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "NAME", length = 400)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "DESCRIPTION", length = 1000)
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "category")
public Set<Product> getProducts() {
return this.products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
product.java
Java代码
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "PRODUCT", schema = "SCOTT")
public class Product implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Category category;
private String name;
private Double price;
private String description;
private Date createTime;
public Product() {
}
@GenericGenerator(name = "generator", strategy = "increment")
@Id
@GeneratedValue(generator = "generator")
@Column(name = "ID", unique = true, nullable = false, precision = 8, scale = 0)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CATEGORY_ID")
public Category getCategory() {
return this.category;
}
public void setCategory(Category category) {
this.category = category;
}
@Column(name = "NAME", length = 200)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "PRICE", precision = 6)
public Double getPrice() {
return this.price;
}
public void setPrice(Double price) {
this.price = price;
}
@Column(name = "DESCRIPTION", length = 1000)
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
@Temporal(TemporalType.DATE)
@Column(name = "CREATE_TIME", length = 7)
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
Java代码
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateAnnotationsTest {
public void testAnnotations() {
SessionFactory sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
Category category = new Category();
category.setName("demo");
category.setDescription("这是一个例子");
Product product = new Product();
product.setName("妮维雅");
product.setPrice(new Double(46.0));
product.setDescription("护肤品");
product.setCategory(category);
category.getProducts().add(product);
Transaction tx = session.beginTransaction();
session.save(category);
session.save(product);
tx.commit();
sessionFactory.close();
}
public static void main(String[] args) {
HibernateAnnotationsTest test = new HibernateAnnotationsTest();
test.testAnnotations();
}
}
注意: 回报这种错误 java.lang.NoSuchMethodError: org.hibernate.event.PreInsertEvent.getSource()Lorg/hibernate/engine/SessionImplementor;
解决方法 替换hibernate-annotation.jar 和hibernate-validator.jar 换成新点的 或者你把hibernate-validator.jar 移除也行
hibernate-annotation.jar 换成3.4.0的就好了,3.5.1-Final还会报一个缺少MetadataProvider的类具体没太注意解决的方法,validator我换的是4.0.2的其他的没测试应该也没什么问题...
@GeneratedValue注解生成策略
TABLE 借助数据库表,生成存标识符属性值,表中保存当前的标识符属性的最大值
IDENTITY 使用数据库表中的自动增长字段生成标识符属性值
SEQUENCE 使用数据库的序列生成标识符属性值
AUTO 可以是上面三种任意一种类型,取决于底层数据库的类型
Hibernate EntityManager
java Persistence API(JPA)
java persistence api 是ejb3.0规范之一,定义了对数据库数据进行持久化操作的接口,Hibernate使用 Hibernate annotations和Hibernate EntityManager实现了JPA
会使用到 Hibernate-EntityManager.jar和jboss-archive-browing.jar
和Annotation不同的是没有用到hibernate.cfg.xml 而是使用persistence.xml文件的实现填写信息而xml文件必须在META-INF文件夹下其余的基本相同
persistence.xml
Xml代码
<?xml version='1.0' encoding='UTF-8'?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.23.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/ns/persistence http://java.sun.com/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="entityManagerTest">
<provider>org.hibernate.ejb.HibernatePersistence
</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver" />
<property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:dbrbh" />
<property name="hibernate.connection.username" value="scott" />
<property name="hibernate.connection.password" value="tiger" />
</properties>
</persistence-unit>
</persistence>
Java代码
//EntityManagerFactory==SessionFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory("entityManagerTest");
//EntityManager == session
EntityManager entityManager = emf.createEntityManager();
//EntityTransaction == Transaction
EntityTransaction tx = entityManager.getTransaction();
//entityManager persist()=Session.save()
entityManager.persist(category);