一 简介
Hibernate提供了Hibernate Annotations扩展包,它可以替换复杂的hbm.xml文件,使得Hibernate程序的开发大大简化。即利用注解后,可不用定义持久化类对应的*.hbm.xml文件,而直接以注解方式写入持久化类的实现中。
使用Hibernate注解,首先需要在Hibcrnate官方网站获取Annotation扩展包。使用Hibernate3.3.2需要获取的Annotations扩展包是hibernate-annotations-3.4.0.GA.zip。解压该扩展包,在目录Hibernate-annotations-3.4.0.GA\doc\reference\zh_cn\html下可以查阅关于注解的中文帮助文档。
使用Hibernate注解的步骤如下。
(1)添加jar包。
①Hibernate-annotations-3.4.O.GA根目录下的hibernate-annotations.jar。
②hibernate-annotations-3.4.O.GA\lib
目录下的Hibernate-commons-annotationsar.ejb3-persistence.jar。
(2)使用注解配置持久化类及对象关联关系。
(3)使用AnnotationConfiguration建立会话工厂。
sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory();
(4)在Hibernate配置文件(hibernate.cfg.xml)中声明持久化类。
<mapping class="持久化类完整限定名"/>
二 注解配置持久类
通过表1所示注解可以完成持久化类的常用配置。
注解 | 含义和作用 |
@Entity | 将一个类声明为一个持久化类 |
@Id | 声明了持久化类的标识属性(相当于数据表的主键) |
@GeneratedValue | 定义标识属性值的生成策略 |
@Table | 为持久化类映射指定表(table)、目录(catalog)和schema的名称。默认值:持久化类名,不带包名 |
@UniqueConstraint | 定义表的唯一约束 |
@Lob | 表示属性将被持久化为Blob或者Clob类型 |
@Column | 将属性映射到列 |
@Transient | 忽略这些字段和属性,不用持久化到数据库 |
使用Hibernate注解,需要导人javax.persistence这个包,常用注解都存放在这个包中。javax.persistence包是JPA ORM规范的组成部分。JPA全称Java Persistence API,它通过JDK5.0注解或XML描述对象_关系表的映射关系,并将运行期的对象持久化到数据库中。Hibernate提供了对JPA的实现。
@Table可以省略,默认值为持久化类名。
@GeneratedValue指定了标识符的生成策略。JPA提供了4种标准用法。
(1) AUTO:根据不同的数据库选择不同的策略。
(2) TABLE:使用表保存id值。
(3) INDENITY:使用数据库自动生成主键(主要是自动增长型,如MySql、SQL Server)。
(4) SEQUENCE:使用序列创建主键(如Oracle)。
Hibernate还提供了更多的ID生成器,可以通过相关资料查询。
下面举例说明注解的使用,添加学生信息,如示例1所示。
示例1
StudentEntity.java
import java.util.Date;
import javax.persistence.*;
@Entity
@Table(name="Student")
public class StudentEntity implementsjava.io.Serializable{
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="seq_stu")
@SequenceGenerator(name="seq_ stu",sequenceName="seq_stu_id",
allocationSize=1,initialValue=1)
private Short stuId;
@Column(name="StuName")
private String studentName;
@Column(name="SchoolStartDate")
private Date schoolStartDate
@Transient
private DepartEntity dept;
@Transient
private String nation;
@Transient
private int age;
public StudentEntity(){
}
//省略getter和setter方法
}
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<!--省略property配置-->
<mappingclass="com.hopetech.hibernate.entity.StudentEntity" />
</session-factory>
</hibernate-configuration>
测试类代码:
SessionFactorysf=new AnnotationConfiguration().configure()
.buildSessionFactory();
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
StudentEntity student=new StudentEntity();
student.setStuName("xiaoming");
student.setSchoolStartDate(new Date());
session.save(student);
tx.commit();
运行示例1,Hibernate执行以下SQL语句,Student表中成功添加了一条记录:
select seq_stu_id.nextval from dual
insert intoStudent(stuName,schoolStartDate,stuId) values(?,?,?)
示例1中,StudentEntity类映射到Student表,stuId为主键,主键采用序列生成,需在数据库中创建序列Sequence,名为seq_stu_id。注解都放置在属性定义的上方。
使用@GeneratedValue设置主键生成策略,strategy=GenerationType.SEQUENCE描述了主键生成策略为Sequence,generator="seq_stu"指定了生成器为seq_stu。
使用@SequenceGenerator设置了序列生成器,name="seq_stu"定义了序列生成器的名称为seq_stu;sequenceName="seq_stu_id"指定了序列Sequence的名称为seq_stu_id,数据库中需创建序列Sequence,名称为seq_stu_id; initialValue=l设置了主键初始值,默认为O;allocationSize=表示预分配多少个主键值,如设置为l,表示不预分配主键值,默认为50。
使用@Column把studentName属性映射到Student表中的StuName列。
使用@Column把schoolStartDate属性映射到Student表中的SchoolStartDate列。
使用@Transient把其他属性忽略,不持久化到数据库中。
在Hibernate.cfg.xml中,使用mapping元素声明持久化类。
三 注解配置对象管理关系
通过表2所示注解可以完成对象关联关系的常用配置。
注解 | 含义和作用 |
@OneToOne | 建立持久化类之闻的一对一关联关系 |
@OneToMany | 建立持久化类之问的一对多关联关系 |
@ManyToOne | 建立持久化类之间的多对一关联关系 |
@ManyToMany | 建立持久化类之间的多对多关联关系 |
对象关联关系中使用频率最高的是一对多(多对一)关联关系,以此为例讲解注解的配置,其他关联关系的注解配置与此类似。下面举例说明,按主键查询学生,并使用@ManyToOne加载系部,如示例2所示。
示例2
StudentEntity.java
import java.util.Date;
import javax.persistence.*;
@Entity
@Table(name="Student")
public class StudentEntity implementsjava.io.Serializable{
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="seq_stu")
@SequenceGenerator(name="seq_ stu",sequenceName="seq_stu_id",
allocationSize=10,initialValue=1)
private Short stuId;
@Column(name="StuName")
private String studentName;
@Column(name="SchoolStartDate")
private Date schoolStartDate
@ManyToOne
@JoinColumn(name="departId")
private DepartEntity dept;
public StudentEntity(){
}
//省略getter和setter方法
}
DepartEntity.java
@Entity
@Table(name="Depart")
public class DepartEntity implementsjava.io.Serializable{
@Id
private Integer deptId
@Column(name="DepartName")
private String deptName;
//省略getter和setter方法
public DepartEntity(){
}
}
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<!--省略property配置-->
<mappingclass="com.hopetech.hibernate.entity.StudentEntity" />
<mappingclass="com.hopetech.hibernate.entity.DepartEntity" />
</session-factory>
</hibernate-configuration>
测试类代码:
SessionFactorysf=new AnnotationConfiguration().configure()
.buildSessionFactory();
Session session=sf.openSession();
StudentEntity student=(StudentEntity)session.load(StudentEntity.class,3);
System.out.println(student.getStuName()+","
+student.getDept().getDeptName());
运行示例2,Hibernate执行以下SQL语句,输出学生姓名和系部名称:
selects.*,d.* from Student s left outer join Depart d
ons.deptId=d.deptId where s.stuId=?
maike,汉语研究系
示例2中使用@ManyToOne配置了StudentEntity和DepartEntity类之间的多对一关联;使用@JoinColunm(name="DepartId")指定了维系关系的外键字段是Student表中的DepartId。Hibernate生成的SQL语句使用了左外连接关键字。
下面举例说明级联的配置,添加系部的同时添加学生,如示例3所示。
示例3
StudentEntity.java和示例2相同。
DepartEntity.java
@Entity
@Table(name="Depart")
public class DepartEntity implementsjava.io.Serializable{
@Id
private Integer deptId
@Column(name="DepartName")
private String deptName;
@Transient
private String address;
@OneToMany(mappedBy="dept",cascade={CascadeType.ALL})
//省略getter和setter方法
public DepartEntity(){
}
}
hibernate.cfg.xml和示例2相同。
测试类代码:
SessionFactory sf=newAnnotationConfiguration().configure()
.buildSessionFactory();
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
DepartEntity dept=new DepartEntity(103, "汉语研究系")
StudentEntity student=new StudentEntity();
student.setStuName("xiaoming");
student.setSchoolStartDate(new Date());
dept.getStudents().add(student);
student.setDept(dept);
session.save(student);
tx.commit();
运行示例3,Hibernate执行以下SQL语句,保存DepartEntity对象,级联保存StudentEntity对象:
select seq_stu_id.nextval from dual
insert into Depart(DeptName,DeptId)values(?,?)
insertinto Student(DeptId,StuName,SchoolStartDate,StuId) values(?,?,?,?)
示例3使用@OneToMany(mappedBy="dept",cascade={CascadeType.ALL})配置了DepartEntity类和StudentEntity类之间的一对多的关系;通过cascade=(CascadeType.ALL}设置了级联;通过mappedBy="dept"设置维系关系的控制权交给StudentEntity类这一方,相当于Depart.hbm.xml中配置的inverse="true",mappedBy的属性值dept是StudentEntity类中的属性名。
cascade属性指定级联操作:
(1) CascadeType.REMOVE:级联删除。
(2) CascadeType.PERSIST:persist()方法级联。
(3) CascadeType.MERGE:级联更新。
(4) CascadeType.REFRESH:级联刷新。
(5) CascadeType.ALL:包含所有级联操作。
四 注解配置命名查询
使用注解可以配置命名查询。配置命名查询的注解为@NamedQuery。下面举例说明,查询姓名包含“小”字的学生,如示例4所示。
示例4
StudentEntity.java
@Entity
@Table(name="Student")
@NamedQuery(name="selectStu",query="fromStudentEntity
where stuName like :sname")
public class StudentEntity implementsjava.io.Serializable{
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="seq_stu")
@SequenceGenerator(name="seq_ stu",sequenceName="seq_stu_id",
allocationSize=10,initialValue=1)
private Short stuId;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="departId")
private DepartEntity dept;
@Column(name="StuName")
private String studentName;
public StudentEntity(){
}
//省略getter和setter方法
}
hibernate.cfg.xml和示例2相同。
测试类代码:
List<StudentEntity>list=session.getNamedQuery("selectStu")
.setString("sname","%r%").list();
for(StudentEntity student:list){
System.out.println(student.getStuName());
}
运行示例4,Hibernate执行以下SQL语句,输出了姓名包含“小”字的学生:
select* from Student where StuName like ?
张小军
刘小丽
示例4使用@NamedQuery配置了命名查询;使用@ManyToOne(fetcl=FetchType.LAZY)配置了延迟加载。查询StudentEntity对象时,不会立即加载DepartEntity对象。