Hibernate是一个开源,轻量级的ORM(对象关系映射)工具。Hibernate框架简化了java应用程序与数据库交互的开发。
ORM工具简化了数据创建,数据处理和数据访问。它是将对象映射到数据库中存储的数据(表)的编程技术。
注:为什么会有这篇教程文章?答:只是想写一篇最NB的Hibernate教程入门文章。NB代表人见人爱,花见花开,车见爆胎,飞鸟落地...,最后,需要注意的是:这篇文章包教不包会!除非你从头到尾认真看完并运行所有示例代码。
1. Hibernate快速入门简介
本教程文章基于以下工具(软件):
- Hibernate 5.2.2.Final
- Eclipse 4.6 (MARS)
Hibernate.x ~ Hibernate.5 更新功能:
从Hibernate 5.0开始Hibernate Spatial是Hibernate项目的一部分,因此我们也可以处理GIS数据了。
域模型映射支持Java 8日期和时间类型。 标准SQL日期/时间类型以及支持的Java 8
Date
/Time
类类型之间的映射,如下所示:
- DATE:
java.time.LocalDate
- TIME:
java.time.LocalTime
,java.time.OffsetTime
- TIMESTAMP:
java.time.Instant
,java.time.LocalDateTime
,java.time.OffsetDateTime
和java.time.ZonedDateTime
- 字节码增强机制从头重新设计,Hibernate可支持Maven和Gradle插件。可以通过字节码仪器来增强三个主要方面:
- 懒初始化:字段可以声明为
LAZY
,只有在第一次被访问时,它们才被提取。 - 脏检查:实体被增强,使得它们可以跟踪在持久化上下文中加载之后变化的所有属性。
- 双向关联:即使开发人员仅更新单侧,但也可以自动同步双向关联的双方。
- Hibernate的原生API(Session等)已更新为使用泛型类型化。无需在获取实体时转换。
-
Hibernate 5.0
将其扩展到更广泛的类型(例如UUID
)。 - 引用二级缓存,使实体引用能够直接存储到第二级缓存中(用于不可变实体)。
2. 准备数据库
Hibernate是一个库,为了处理所有类型的数据库,它不依赖于应用程序选择的任何类型的数据库,如果Java是“一次写入到处运行”的语言,Hibernate则是“写一次就可运行在所有类型的数据库“中的框架。
在这篇文章中,使用的是MySQL数据(你可使用其它的数据库,如:Oracle,MySQL或SQL Server),并创建一个简单的数据库:mydb
,完整的数据库创建语句如下所示:
创建数据:
CREATE DATABASE IF NOT EXISTS mydb default charset utf8 COLLATE utf8_general_ci;
需要创建以下几张表,它们的关系图如下所示 -
创建表语句:
create table DEPARTMENT (
DEPT_ID integer not null,
DEPT_NAME varchar(255) not null,
DEPT_NO varchar(20) not null,
LOCATION varchar(255),
primary key (DEPT_ID),
unique (DEPT_NO)
);
create table EMPLOYEE (
EMP_ID bigint not null,
EMP_NAME varchar(50) not null,
EMP_NO varchar(20) not null,
HIRE_DATE date not null,
IMAGE longblob,
JOB varchar(30) not null,
SALARY float not null,
DEPT_ID integer not null,
MNG_ID bigint,
primary key (EMP_ID),
unique (EMP_NO)
);
create table SALARY_GRADE (
GRADE integer not null,
HIGH_SALARY float not null,
LOW_SALARY float not null,
primary key (GRADE)
);
create table TIMEKEEPER (
Timekeeper_Id varchar(36) not null,
Date_Time datetime not null,
In_Out char(1) not null,
EMP_ID bigint not null,
primary key (Timekeeper_Id)
);
alter table EMPLOYEE
add index FK75C8D6AE269A3C9 (DEPT_ID),
add constraint FK75C8D6AE269A3C9
foreign key (DEPT_ID)
references DEPARTMENT (DEPT_ID);
alter table EMPLOYEE
add index FK75C8D6AE6106A42 (EMP_ID),
add constraint FK75C8D6AE6106A42
foreign key (EMP_ID)
references EMPLOYEE (EMP_ID);
alter table EMPLOYEE
add index FK75C8D6AE13C12F64 (MNG_ID),
add constraint FK75C8D6AE13C12F64
foreign key (MNG_ID)
references EMPLOYEE (EMP_ID);
alter table TIMEKEEPER
add index FK744D9BFF6106A42 (EMP_ID),
add constraint FK744D9BFF6106A42
foreign key (EMP_ID)
references EMPLOYEE (EMP_ID);
向上面创建的表中,分别插入一些测试数据,如下所示 -
insert into Department (DEPT_ID, DEPT_NAME, DEPT_NO, LOCATION)
values (10, 'ACCOUNTING', 'D10', 'NEW YORK');
insert into Department (DEPT_ID, DEPT_NAME, DEPT_NO, LOCATION)
values (20, 'RESEARCH', 'D20', 'DALLAS');
insert into Department (DEPT_ID, DEPT_NAME, DEPT_NO, LOCATION)
values (30, 'SALES', 'D30', 'CHICAGO');
insert into Department (DEPT_ID, DEPT_NAME, DEPT_NO, LOCATION)
values (40, 'OPERATIONS', 'D40', 'BOSTON');
-------------------------------------------------------------------------------------------------
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7839, 'KING', 'E7839', Str_To_Date('17-11-1981', '%d-%m-%Y'), 'PRESIDENT', 5000, 10, null);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7566, 'JONES', 'E7566', Str_To_Date('02-04-1981', '%d-%m-%Y'), 'MANAGER', 2975, 20, 7839);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7902, 'FORD', 'E7902', Str_To_Date('03-12-1981', '%d-%m-%Y'), 'ANALYST', 3000, 20, 7566);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7369, 'SMITH', 'E7369', Str_To_Date('17-12-1980', '%d-%m-%Y'), 'CLERK', 800, 20, 7902);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7698, 'BLAKE', 'E7698', Str_To_Date('01-05-1981', '%d-%m-%Y'), 'MANAGER', 2850, 30, 7839);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7499, 'ALLEN', 'E7499', Str_To_Date('20-02-1981', '%d-%m-%Y'), 'SALESMAN', 1600, 30, 7698);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7521, 'WARD', 'E7521', Str_To_Date('22-02-1981', '%d-%m-%Y'), 'SALESMAN', 1250, 30, 7698);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7654, 'MARTIN', 'E7654', Str_To_Date('28-09-1981', '%d-%m-%Y'), 'SALESMAN', 1250, 30, 7698);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7782, 'CLARK', 'E7782', Str_To_Date('09-06-1981', '%d-%m-%Y'), 'MANAGER', 2450, 30, 7839);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7788, 'SCOTT', 'E7788', Str_To_Date('19-04-1987', '%d-%m-%Y'), 'ANALYST', 3000, 20, 7566);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7844, 'TURNER', 'E7844', Str_To_Date('08-09-1981', '%d-%m-%Y'), 'SALESMAN', 1500, 30, 7698);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7876, 'ADAMS', 'E7876', Str_To_Date('23-05-1987', '%d-%m-%Y'), 'CLERK', 1100, 20, 7698);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7900, 'ADAMS', 'E7900', Str_To_Date('03-12-1981', '%d-%m-%Y'), 'CLERK', 950, 30, 7698);
insert into Employee (EMP_ID, EMP_NAME, EMP_NO, HIRE_DATE, JOB, SALARY, DEPT_ID, MNG_ID)
values (7934, 'MILLER', 'E7934', Str_To_Date('23-01-1982', '%d-%m-%Y'), 'CLERK', 1300, 10, 7698);
-------------------------------------------------------------------------------------------------
insert into Salary_Grade (GRADE, HIGH_SALARY, LOW_SALARY)
values (1, 9999, 3001);
3. 创建Maven项目和声明库
在这里,创建一个Maven项目并在pom.xml
中声明使用的Hibernate
库。打开 Eclipse,选择菜单 File -> New -> Other...,在弹出框中选择 Maven,如下所示 -
下一步选择工作目录,如下图所示 -
下一步,选择模板类型,如下图所示 -
下一步,写入工程名称:HibernateQuickStart,以及输入包信息:com.yiibai
等信息。
项目(HibernateQuickStart)创建完成后,如下图所示 -
在pom.xml
中,需要声明使用Hibernate 5
库,以及用于各种数据库类型(如Oracle,MySQL和SQL Server)的JDBC库,这里使用 MySQL JDBC。
完整的 pom.xml 配置/声明如下所示 -
4.0.0
com.yiibai
HibernateQuickStart
0.0.1-SNAPSHOT
jar
HibernateQuickStart
http://maven.apache.org
UTF-8
junit
junit
3.8.1
test
org.hibernate
hibernate-core
5.2.2.Final
mysql
mysql-connector-java
5.1.34
net.sourceforge.jtds
jtds
1.3.1
4. 实体类
在这一步中,我们来创建实体类。每个实体描述一个数据库中的表。这里先不说明每个类是做什么用的。一共要创建如下几个实体类(对应上面创建的四张表),如下 -
- Department.java
- Employee.java
- SalaryGrade.java
- Timekeeper.java
所有创建的类如下图所示 -
这几个类的代码,分别如下所示 -
Department.java 类代码 -
package com.yiibai.entities;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "DEPARTMENT", uniqueConstraints = { @UniqueConstraint(columnNames = { "DEPT_NO" }) })
public class Department {
private Integer deptId;
private String deptNo;
private String deptName;
private String location;
private Set employees = new HashSet(0);
public Department() {
}
public Department(Integer deptId, String deptName, String location) {
this.deptId = deptId;
this.deptNo = "D" + this.deptId;
this.deptName = deptName;
this.location = location;
}
@Id
@Column(name = "DEPT_ID")
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
@Column(name = "DEPT_NO", length = 20, nullable = false)
public String getDeptNo() {
return deptNo;
}
public void setDeptNo(String deptNo) {
this.deptNo = deptNo;
}
@Column(name = "DEPT_NAME", nullable = false)
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Column(name = "LOCATION")
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
public Set getEmployees() {
return employees;
}
public void setEmployees(Set employees) {
this.employees = employees;
}
}
Employee.java 类代码 -
package com.yiibai.entities;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "EMPLOYEE", uniqueConstraints = { @UniqueConstraint(columnNames = { "EMP_NO" }) })
public class Employee {
private Long empId;
private String empNo;
private String empName;
private String job;
private Employee manager;
private Date hideDate;
private Float salary;
private byte[] image;
private Department department;
private Set employees = new HashSet(0);
public Employee() {
}
public Employee(Long empId, String empName, String job, Employee manager, Date hideDate, Float salary, Float comm,
Department department) {
this.empId = empId;
this.empNo = "E" + this.empId;
this.empName = empName;
this.job = job;
this.manager = manager;
this.hideDate = hideDate;
this.salary = salary;
this.department = department;
}
@Id
@Column(name = "EMP_ID")
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
@Column(name = "EMP_NO", length = 20, nullable = false)
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
@Column(name = "EMP_NAME", length = 50, nullable = false)
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Column(name = "JOB", length = 30, nullable = false)
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MNG_ID")
public Employee getManager() {
return manager;
}
public void setManager(Employee manager) {
this.manager = manager;
}
@Column(name = "HIRE_DATE", nullable = false)
@Temporal(TemporalType.DATE)
public Date getHideDate() {
return hideDate;
}
public void setHideDate(Date hideDate) {
this.hideDate = hideDate;
}
@Column(name = "SALARY", nullable = false)
public Float getSalary() {
return salary;
}
public void setSalary(Float salary) {
this.salary = salary;
}
@Column(name = "IMAGE", length = 1111111, nullable = true)
@Lob
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DEPT_ID", nullable = false)
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "empId")
public Set getEmployees() {
return employees;
}
public void setEmployees(Set employees) {
this.employees = employees;
}
}
SalaryGrade.java 类代码 -
package com.yiibai.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "SALARY_GRADE")
public class SalaryGrade {
private Integer grade;
private Float lowSalary;
private Float highSalary;
public SalaryGrade() {
}
public SalaryGrade(Integer grade, Float lowSalary, Float highSalary) {
this.grade = grade;
this.lowSalary = lowSalary;
this.highSalary = highSalary;
}
@Id
@Column(name = "GRADE")
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
@Column(name = "LOW_SALARY", nullable = false)
public Float getLowSalary() {
return lowSalary;
}
public void setLowSalary(Float lowSalary) {
this.lowSalary = lowSalary;
}
@Column(name = "HIGH_SALARY", nullable = false)
public Float getHighSalary() {
return highSalary;
}
public void setHighSalary(Float highSalary) {
this.highSalary = highSalary;
}
}
Timekeeper.java 类代码 -
package com.yiibai.entities;
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 = "TIMEKEEPER")
public class Timekeeper {
public static final char IN = 'I';
public static final char OUT = 'O';
private String timekeeperId;
private Date dateTime;
private Employee employee;
// 'I' or 'O'
private char inOut;
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(name = "Timekeeper_Id", length = 36)
public String getTimekeeperId() {
return timekeeperId;
}
public void setTimekeeperId(String timekeeperId) {
this.timekeeperId = timekeeperId;
}
@Column(name = "Date_Time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date dateTime) {
this.dateTime = dateTime;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EMP_ID", nullable = false)
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
@Column(name = "In_Out", nullable = false, length = 1)
public char getInOut() {
return inOut;
}
public void setInOut(char inOut) {
this.inOut = inOut;
}
}
5. 配置hibernate
配置hibernate目的是让Hibernate可以连接数据库并与数据库交互,并声明在前面的步骤中创建的实体列表。
在src/main/java中创建一个名称为:hibernate.cfg.xml 的配置文件,当前项目结构如下图所示 -
hibernate.cfg.xml 配置文件的内容如下所示 -
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC
root
123456
1
org.hibernate.dialect.MySQLDialect
thread
org.hibernate.cache.internal.NoCacheProvider
true
每种数据库都有一个单独的方言, 例如:
Oracle方言:
- org.hibernate.dialect.Oracle10gDialect(Dùngcho 10g&11g)
- org.hibernate.dialect.Oracle12cDialect
SQL Server方言:
- org.hibernate.dialect.SQLServerDialect并
- org.hibernate.dialect.SQLServer2012Dialect
- org.hibernate.dialect.SQLServer2008Dialect
MySQL方言
- org.hibernate.dialect.MySQLDialect
- org.hibernate.dialect.MySQL5Dialect
什么是方言?
Dialect
是一个使用Hibernate的方式将数据库的数据类型转换为Java的数据类型,反之亦然。此外,它用于定义将HSQL(Hibernate SQL)的函数转换为数据中的函数的方式,如下列出的一部分 -
Java SQL类型 | Oracle | MySQL | SQL Server |
---|---|---|---|
Types.BIT | number(1,0) | bit | bit |
Types.BIGINT | number(19,0) | bigin | bigint |
Types.DATE | date | date | date |
....... | ... | ... | ... |
Types.CLOB | clob | longtext | varchar(MAX) |
Types.BLOB | blob | longblob | varbinary(MAX) |
6. SessionFactory
创建一个文件: HibernateUtils.java , 其代码如下 -
7. Hibernate查询语言(HQL)
Hibernate使用Hibernate查询语言(HQL)查询数据。 HQL与我们所了解的数据库SQL语句有点不同。
SQL:
- 在表中查询数据
HQL:
- 在实体类中查询对象数据
参考比较以下用法 -
-- SQL
-- This is a SQL query in table DEPARTMENT.
Select d.DEPT_NO, d.DEPT_NAME from DEPARTMENT d;
-- HQL
-- This is a HQL query in Entity Department.
Select d.deptNo, d.deptName from Department d;
-- Query Object
Select d from Department d;
Hibernate的操作规则:
应用程序编写的HQL在操作过程中,Hibernate本身就意识到它使用的数据库类型(如:MySQL),它会自动将HQL转换为等价的数据库类型的SQL形式。 事实上,各种类型的数据库之间的SQL语法有一些差异,比如:返回记录的行数的限制就不同(MySQL中使用 limit
子句)。
可以参考HQL语法: http://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/queryhql.html
8. 使用Hibernate查询数据
在Hibernate中有很多方法可以用来查询数据。在这部分中,将介绍一些查询数据的典型方法。
8.1 - 使用HQL的查询对象
查询对象示例-1
第一个例子,使用HQL查询对象(Entity),创建一个Java类文件:QueryObjectDemo.java,其代码如下 -
package com.yiibai;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class QueryObjectDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
// All the action with DB via Hibernate
// must be located in one transaction.
// Start Transaction.
session.getTransaction().begin();
// Create an HQL statement, query the object.
// Equivalent to the SQL statement:
// Select e.* from EMPLOYEE e order by e.EMP_NAME, e.EMP_NO
String sql = "Select e from " + Employee.class.getName() + " e "
+ " order by e.empName, e.empNo ";
// Create Query object.
Query query = session.createQuery(sql);
// Execute query.
List employees = query.getResultList();
for (Employee emp : employees) {
System.out.println("Emp: " + emp.getEmpNo() + " : "
+ emp.getEmpName());
}
// Commit data.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
运行上面代码,得到以下结果 -
查询对象示例-2
创建一个Java类文件:QueryObjectDemo2.java,其代码如下 -
package com.yiibai;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class QueryObjectDemo2 {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
// All the action with DB via Hibernate
// must be located in one transaction
// Start Transaction.
session.getTransaction().begin();
// Create an HQL statement, query the object.
// HQL with parameters.
// Equivalent to the SQL statement:
// Select e.* from EMPLOYEE e cross join DEPARTMENT d
// where e.DEPT_ID = d.DEPT_ID and d.DEPT_NO = :deptNo;
String sql = "Select e from " + Employee.class.getName() + " e " + " where e.department.deptNo=:deptNo ";
// Create query object.
Query query = session.createQuery(sql);
query.setParameter("deptNo", "D10");
// Execute query.
List employees = query.getResultList();
for (Employee emp : employees) {
System.out.println("Emp: " + emp.getEmpNo() + " : " + emp.getEmpName());
}
// Commit data
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
运行上面代码,得到以下结果 -
......
org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateService
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select employee0_.EMP_ID ..._NO=?
Emp: E7839 : KING
Emp: E7934 : MILLER
8.2 - 使用HQL查询读取多列数据
创建一个Java类文件:QuerySomeColumnDemo.java,其代码如下 -
package com.yiibai;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class QuerySomeColumnDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
session.getTransaction().begin();
// Query some columns.
String sql = "Select e.empId, e.empNo, e.empName from "
+ Employee.class.getName() + " e ";
Query
运行上面代码,得到以下结果 -
Hibernate: select employee0_.EMP_ID..._0_ from EMPLOYEE employee0_
Emp Id: 7369
Emp No: E7369
Emp Name: SMITH
Emp Id: 7499
Emp No: E7499
Emp Name: ALLEN
Emp Id: 7521
Emp No: E7521
Emp Name: WARD
Emp Id: 7566
Emp No: E7566
Emp Name: JONES
Emp Id: 7654
Emp No: E7654
Emp Name: MARTIN
Emp Id: 7698
Emp No: E7698
Emp Name: BLAKE
Emp Id: 7782
Emp No: E7782
Emp Name: CLARK
Emp Id: 7788
Emp No: E7788
Emp Name: SCOTT
Emp Id: 7839
Emp No: E7839
Emp Name: KING
Emp Id: 7844
Emp No: E7844
Emp Name: TURNER
Emp Id: 7876
Emp No: E7876
Emp Name: ADAMS
Emp Id: 7900
Emp No: E7900
Emp Name: ADAMS
Emp Id: 7902
Emp No: E7902
Emp Name: FORD
Emp Id: 7934
Emp No: E7934
Emp Name: MILLER
8.3 - 使用HQL和JavaBean查询多列数据
在这种情况下,如果需要在某些表中提取某些列的数据,最好的方法是使用Java bean。使用Java bean的构造函数来为不同的字段设置值。在此构造函数加入HQL查询。
创建一个Java类文件:ShortEmpInfo.java,其代码如下 -
package com.yiibai;
public class ShortEmpInfo {
private Long empId;
private String empNo;
private String empName;
//
// Constructor have 3 parameters, will be used in the Hibernate Query.
//
public ShortEmpInfo(Long empId, String empNo, String empName) {
this.empId = empId;
this.empNo = empNo;
this.empName = empName;
}
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
}
创建一个Java类文件:ShortEmpInfoQueryDemo.java,其代码如下 -
package com.yiibai;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class ShortEmpInfoQueryDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
session.getTransaction().begin();
// Using constructor of ShortEmpInfo
String sql = "Select new " + ShortEmpInfo.class.getName()
+ "(e.empId, e.empNo, e.empName)" + " from "
+ Employee.class.getName() + " e ";
Query query = session.createQuery(sql);
// Execute query.
// Get a List of ShortEmpInfo
List employees = query.getResultList();
for (ShortEmpInfo emp : employees) {
System.out.println("Emp: " + emp.getEmpNo() + " : "
+ emp.getEmpName());
}
// Commit data.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
运行上面代码,得到以下结果 -
8.4 - 查询检索唯一结果
创建一个Java类文件:UniqueResultDemo.java,其代码如下 -
package com.yiibai;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import com.yiibai.entities.Department;
import com.yiibai.entities.Employee;
public class UniqueResultDemo {
public static Department getDepartment(Session session, String deptNo) {
String sql = "Select d from " + Department.class.getName() + " d "//
+ " where d.deptNo= :deptNo ";
Query query = session.createQuery(sql);
query.setParameter("deptNo", deptNo);
return (Department) query.getSingleResult();
}
public static Employee getEmployee(Session session, Long empId) {
String sql = "Select e from " + Employee.class.getName() + " e "//
+ " where e.empId= :empId ";
Query query = session.createQuery(sql);
query.setParameter("empId", empId);
return (Employee) query.getSingleResult();
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
session.getTransaction().begin();
Department dept = getDepartment(session, "D10");
Set emps = dept.getEmployees();
System.out.println("Dept Name: " + dept.getDeptName());
for (Employee emp : emps) {
System.out.println(" Emp name: " + emp.getEmpName());
}
Employee emp = getEmployee(session, 7839L);
System.out.println("Emp Name: " + emp.getEmpName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
运行上面代码,得到以下结果 -
9. Hibernate瞬态,持久和分离
在这部分中,使用Session.persist(Object)
将瞬态对象插入数据库的简单示例。本例中将介绍对象瞬态(Transitent),持久(Persistent)和分离(Detached)的概念。
创建一个Java类文件:DataUtils.java,其代码如下 -
package com.yiibai;
import org.hibernate.Session;
import org.hibernate.query.Query;
import com.yiibai.entities.Department;
import com.yiibai.entities.Employee;
public class DataUtils {
public static Department findDepartment(Session session, String deptNo) {
String sql = "Select d from " + Department.class.getName() + " d "//
+ " Where d.deptNo = :deptNo";
Query query = session.createQuery(sql);
query.setParameter("deptNo", deptNo);
return query.getSingleResult();
}
public static Long getMaxEmpId(Session session) {
String sql = "Select max(e.empId) from " + Employee.class.getName() + " e ";
Query query = session.createQuery(sql);
Number value = query.getSingleResult();
if (value == null) {
return 0L;
}
return value.longValue();
}
public static Employee findEmployee(Session session, String empNo) {
String sql = "Select e from " + Employee.class.getName() + " e "//
+ " Where e.empNo = :empNo";
Query query = session.createQuery(sql);
query.setParameter("empNo", empNo);
return query.getSingleResult();
}
}
创建一个Java类文件:PersistDemo.java,其代码如下 -
package com.yiibai;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.entities.Department;
import com.yiibai.entities.Employee;
public class PersistDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Department department = null;
Employee emp = null;
try {
session.getTransaction().begin();
Long maxEmpId = DataUtils.getMaxEmpId(session);
Long empId = maxEmpId + 1;
// Get Persistent object.
department = DataUtils.findDepartment(session, "D10");
// Create transient object
emp = new Employee();
emp.setEmpId(empId);
emp.setEmpNo("E" + empId);
emp.setEmpName("Name " + empId);
emp.setJob("Coder");
emp.setSalary(1000f);
emp.setManager(null);
emp.setHideDate(new Date());
emp.setDepartment(department);
// Using persist(..)
// Now 'emp' is managed by Hibernate.
// it has Persistent status.
// No action at this time with DB.
session.persist(emp);
// At this step the data is pushed to the DB.
// Execute Insert statement.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
// After the session is closed (commit, rollback, close)
// Objects 'emp', 'dept' became the Detached objects.
// It is no longer in the control of the session.
System.out.println("Emp No: " + emp.getEmpNo());
}
}
运行上面代码,得到以下结果 -
10. Hibernate生命周期
Hibernate的Session类的有一些/几组的重要方法,如下图所示:
Hibernate中的一个对象存在于以下四个状态之中的一种:
- 短暂(Transient)
- 持久(Persistent)
- Removed
- Detached
以上几个状态在下面图中解释:
下面来看这几个状态的流转说明 -
当从一个实体创建一个新的Java对象时,该对象处于“短暂”状态。 Hibernate不知道它的存在,因为它独立于Hibernate的管理。
如果使用方法:
get
,load
或find
获取实体对象,则将获得一个等同于数据库中的1
条记录的对象。 此对象处于Persistent状态。 它由Hibernate管理。会话调用方法:
save
,saveOrUpdate
和persist
。 合并将短暂(Transient)对象置于Hibernate的管理之下,此对象转为持久化(Persistent)状态。 在使用的具体情况下,它向数据库插入或更新数据。Session
调用evict(..)
或clear()
,以便从处于Hibernate管理状态的对象处于关闭状态,并且这些对象处于分离(Detached
)的状态。使用
update(..)
,saveOrUpdate(..)
,merge(..)
将有助于重新连接分离对象。 在具体情况下,它会向数据库中创建更新或插入数据。 对象转回持久化(Persistent)状态。Session
调用方法:remove(..)
,delete(..)
删除除记录并持久化对象。
11. 用Hibernate插入,更新,删除
11.1 - 持久化(Persistent)
当一个对像使用 Session
的get()
,load()
,find()
方法获取关联数据时,它处于持久化(Persistent)状态。
创建一个JAVA类文件:PersistentDemo.java,用于演示对象的持久化(Persistent)状态。
package com.yiibai;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.entities.Department;
import com.yiibai.entities.Employee;
public class PersistentDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Department department = null;
try {
session.getTransaction().begin();
System.out.println("- Finding Department deptNo = D10...");
// Persistent object.
department = DataUtils.findDepartment(session, "D10");
System.out.println("- First change Location");
// Changing something on Persistent object.
department.setLocation("Chicago " + System.currentTimeMillis());
System.out.println("- Location = " + department.getLocation());
System.out.println("- Calling flush...");
// Use session.flush () to actively push the changes to the DB.
// It works for all changed Persistent objects.
session.flush();
System.out.println("- Flush OK");
System.out.println("- Second change Location");
// Change something on Persistent object
department.setLocation("Chicago " + System.currentTimeMillis());
// Print out location
System.out.println("- Location = " + department.getLocation());
System.out.println("- Calling commit...");
// Commit
session.getTransaction().commit();
System.out.println("- Commit OK");
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
// Create the session after it had been closed earlier
// (Cause by commit or update)
session = factory.getCurrentSession();
try {
session.getTransaction().begin();
System.out.println("- Finding Department deptNo = D10...");
// Query lại Department D10.
department = DataUtils.findDepartment(session, "D10");
// Print out location
System.out.println("- D10 Location = " + department.getLocation());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.2 - 瞬态转为持久化状态
11.3 - 瞬态转为持久化状态:使用persist(Object)
创建一个JAVA类文件:PersistTransientDemo.java,用于演示对象的持久化(Persistent)状态。
package com.yiibai;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
import com.yiibai.entities.Timekeeper;
public class PersistTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper persist_Transient(Session session, Employee emp) {
// Note:
// Configuring of timekeeperId
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
Timekeeper tk1 = new Timekeeper();
tk1.setEmployee(emp);
tk1.setInOut(Timekeeper.IN);
tk1.setDateTime(new Date());
// Now, 'tk1' is transient object
System.out.println("- tk1 Persistent? " + session.contains(tk1));
System.out.println("====== CALL persist(tk).... ===========");
// Hibernate assign value to Id of 'tk1'
// No action to DB.
session.persist(tk1);
System.out
.println("- tk1.getTimekeeperId() = " + tk1.getTimekeeperId());
// Now 'tk1' is Persistent object.
// But no action with DB.
// ==> true
System.out.println("- tk1 Persistent? " + session.contains(tk1));
System.out.println("- Call flush..");
// Flush data to DB.
// Hibernate execute insert statement.
session.flush();
String timekeeperId = tk1.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk1.getInOut());
System.out.println("- dateTime = " + df.format(tk1.getDateTime()));
System.out.println();
return tk1;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
persist_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.4 - 瞬态转为持久化状态:使用save(Object)
创建一个JAVA类文件:SaveTransientDemo.java,用于演示对象的持久化(Persistent)状态。
package com.yiibai;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
import com.yiibai.entities.Timekeeper;
public class SaveTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper persist_Transient(Session session, Employee emp) {
// See configuration of timekeeperId:
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
// Create an Object, Transitent state.
Timekeeper tk2 = new Timekeeper();
tk2.setEmployee(emp);
tk2.setInOut(Timekeeper.IN);
tk2.setDateTime(new Date());
// Now 'tk3' are state Transient.
System.out.println("- tk2 Persistent? " + session.contains(tk2));
System.out.println("====== CALL save(tk).... ===========");
// save() very similar to persist()
// save() return ID, persist() return void.
// Hibernate assign ID value to 'tk2', no action with DB
// And return ID of 'tk2'.
Serializable id = session.save(tk2);
System.out.println("- id = " + id);
//
System.out
.println("- tk2.getTimekeeperId() = " + tk2.getTimekeeperId());
// Now, 'tk2' has Persistent state
// It has been managed in Session.
// ==> true
System.out.println("- tk2 Persistent? " + session.contains(tk2));
System.out.println("- Call flush..");
// To push data into the DB, call flush().
// If not call flush() data will be pushed to the DB when calling commit().
// Will execute insert statement.
session.flush();
String timekeeperId = tk2.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk2.getInOut());
System.out.println("- dateTime = " + df.format(tk2.getDateTime()));
System.out.println();
return tk2;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
persist_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.5 - 瞬态转为持久化状态:使用saveOrUpdate(Object)
创建一个JAVA类文件:SaveOrUpdateTransientDemo.java,用于演示对象的持久化(Persistent)状态。
package com.yiibai;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
import com.yiibai.entities.Timekeeper;
public class SaveOrUpdateTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper saveOrUpdate_Transient(Session session,
Employee emp) {
// See configuration of timekeeperId:
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
// Create an Object, Transitent state.
Timekeeper tk3 = new Timekeeper();
tk3.setEmployee(emp);
tk3.setInOut(Timekeeper.IN);
tk3.setDateTime(new Date());
// Now 'tk3' are state Transient.
System.out.println("- tk3 Persistent? " + session.contains(tk3));
System.out.println("====== CALL saveOrUpdate(tk).... ===========");
// Here Hibernate checks, 'tk3' have ID or not (timekeeperId)
// If no, it will be assigned automatically
session.saveOrUpdate(tk3);
System.out
.println("- tk3.getTimekeeperId() = " + tk3.getTimekeeperId());
// Now 'tk3' has Persistent state
// It has been managed in Session.
// But no action insert, or update to DB.
// ==> true
System.out.println("- tk3 Persistent? " + session.contains(tk3));
System.out.println("- Call flush..");
// To push data into the DB, call flush().
// If not call flush() data will be pushed to the DB when calling commit().
// Now possible to Insert or Update DB. (!!!)
// Depending on the ID of 'tk3' exists in the DB or not
session.flush();
String timekeeperId = tk3.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk3.getInOut());
System.out.println("- dateTime = " + df.format(tk3.getDateTime()));
System.out.println();
return tk3;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
saveOrUpdate_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.6 - 瞬态转为持久化状态:使用merge(Object)
创建一个JAVA类文件:MergeTransientDemo.java,用于演示对象的持久化(Persistent)状态。
package com.yiibai;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
import com.yiibai.entities.Timekeeper;
public class MergeTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper saveOrUpdate_Transient(Session session,
Employee emp) {
// Note:
// Configuring of timekeeperId
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
Timekeeper tk4 = new Timekeeper();
tk4.setEmployee(emp);
tk4.setInOut(Timekeeper.IN);
tk4.setDateTime(new Date());
// Now 'tk4' Transient status.
System.out.println("- tk4 Persistent? " + session.contains(tk4));
System.out.println("====== CALL merge(tk).... ===========");
// Hibernate2 has method saveOrUpdateCopy
// Hibernate3 change saveOrUpdateCopy to merge
// So there will be similarities between the two methods merge and copyOrUpdate
// Here Hibernate check tk4 has ID or not
// If not, Hibernate assign value to ID of tk4
// Return copy of tk4.
Timekeeper tk4Copy = (Timekeeper) session.merge(tk4);
System.out
.println("- tk4.getTimekeeperId() = " + tk4.getTimekeeperId());
// Now 'tk4' still Transient state.
// and 'tk4Copy' has Persistent status
// No action with DB (insert or update).
System.out.println("- tk4 Persistent? " + session.contains(tk4));
// 'tk4Copy' has Persistent status
// ==> true
System.out
.println("- tk4Copy Persistent? " + session.contains(tk4Copy));
System.out.println("- Call flush..");
// This time have Insert or Update to DB. (!!!)
session.flush();
// 'tk4' still Transitent, after flush().
// merge(..) safer than saveOrUpdate().
System.out.println("- tk4 Persistent? " + session.contains(tk4));
//
String timekeeperId = tk4.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk4.getInOut());
System.out.println("- dateTime = " + df.format(tk4.getDateTime()));
System.out.println();
return tk4;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
saveOrUpdate_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.7 - 持久化转变为分离状态
由Hibernate管理的持久化(Persistent)条件中的一个对象可以通过以下两个Session
的方法转换为Detached
(独立于Hibernate的管理)状态:
evict (Object)
- 从Hibernate管理中删除一个对象clear()
- 从Hibernate管理的对象中删除所有对象。
当然,当Session
调用顺序为:commit()
,close()
或rollback()
时,当前会话已经完成。 此会话的所有Persistence
对象将从新打开的会话中分离。
创建一个JAVA类文件:EvictDemo.java,用于演示对象持久化转变为分离状态。
package com.yiibai;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class EvictDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
// This is object has Persistent status
emp = DataUtils.findEmployee(session, "E7499");
// ==> true
System.out.println("- emp Persistent? " + session.contains(emp));
// using evict() to evicts a single object from the session
session.evict(emp);
// Now 'emp' has Detached status
// ==> false
System.out.println("- emp Persistent? " + session.contains(emp));
// All change on the 'emp' will not update
// if not reatach 'emp' to session
emp.setEmpNo("NEW");
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
创建一个JAVA类文件:ClearDemo.java,用于演示将所有对象持久化转变为分离状态。
package com.yiibai;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Department;
import com.yiibai.entities.Employee;
public class ClearDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
Department dept = null;
try {
session.getTransaction().begin();
// It is an object has Persistent status.
emp = DataUtils.findEmployee(session, "E7499");
dept = DataUtils.findDepartment(session, "D10");
// clear() evicts all the objects in the session.
session.clear();
// Now 'emp' & 'dept' has Detached status
// ==> false
System.out.println("- emp Persistent? " + session.contains(emp));
System.out.println("- dept Persistent? " + session.contains(dept));
// All change on the 'emp' will not update
// if not reatach 'emp' to session
emp.setEmpNo("NEW");
dept = DataUtils.findDepartment(session, "D20");
System.out.println("Dept Name = "+ dept.getDeptName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.8 - 分离状态转变为持久化状态
Hibernate管理分离的对象可以通过以下Session
的一些方法重新附加:
- update(Object)
- saveOrUpdate(Object)
- merge(Object)
- refresh(Object)
- lock(Object)
可以在以下示例中看到这些方法的区别:
11.9-分离转变为持久性状态:使用update(Object)
创建一个JAVA类文件:UpdateDetachedDemo.java,用于演示将对象分离转变为持久性状态。
package com.yiibai;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Department;
import com.yiibai.entities.Employee;
public class UpdateDetachedDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
// This is a Persistent object.
emp = DataUtils.findEmployee(session1, "E7499");
// session1 was closed after a commit is called.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// Open other session
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
// Check state of 'emp'
// ==> false
System.out.println("- emp Persistent? " + session2.contains(emp));
System.out.println("Emp salary: " + emp.getSalary());
emp.setSalary(emp.getSalary() + 100);
// update (..) is only used for Detached object.
// (Not for Transient object).
// Use the update (emp) to bring back emp Persistent state.
session2.update(emp);
// Call flush
// Update statement will be called.
session2.flush();
System.out.println("Emp salary after update: " + emp.getSalary());
// session2 was closed after a commit is called.
session2.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
}
}
}
执行上面代码,得到以下结果 -
11.10 - 分离转变为持久性状态:使用saveOrUpdate(Object)
创建一个JAVA类文件:SaveOrUpdateDetachedDemo.java,用于演示将对象分离转变为持久性状态。
package com.yiibai;
import java.util.Random;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class SaveOrUpdateDetachedDemo {
public static void main(String[] args) {
// An object Detached state.
Employee emp = getEmployee_Detached();
System.out.println(" - GET EMP " + emp.getEmpId());
// Random delete or not delete Employee
boolean delete = deleteOrNotDelete(emp.getEmpId());
System.out.println(" - DELETE? " + delete);
// Call saveOrUpdate for detached object.
saveOrUpdate_test(emp);
// After call saveOrUpdate()
System.out.println(" - EMP ID " + emp.getEmpId());
}
// Return Employee object has Detached state
private static Employee getEmployee_Detached() {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
Long maxEmpId = DataUtils.getMaxEmpId(session1);
System.out.println(" - Max Emp ID " + maxEmpId);
Employee emp2 = DataUtils.findEmployee(session1, "E7839");
Long empId = maxEmpId + 1;
emp = new Employee();
emp.setEmpId(empId);
emp.setEmpNo("E" + empId);
emp.setDepartment(emp2.getDepartment());
emp.setEmpName(emp2.getEmpName());
emp.setHideDate(emp2.getHideDate());
emp.setJob("Test");
emp.setSalary(1000F);
// emp has been managed by Hibernate
session1.persist(emp);
// session1 was closed after a commit is called.
// An Employee record are insert into DB.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// Session1 closed 'emp' switch to Detached state.
return emp;
}
// Random: delete or not delete.
private static boolean deleteOrNotDelete(Long empId) {
// A random number 0-9
int random = new Random().nextInt(10);
if (random < 5) {
return false;
}
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
String sql = "Delete " + Employee.class.getName() + " e "
+ " where e.empId =:empId ";
Query query = session2.createQuery(sql);
query.setParameter("empId", empId);
query.executeUpdate();
session2.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
return false;
}
}
private static void saveOrUpdate_test(Employee emp) {
SessionFactory factory = HibernateUtils.getSessionFactory();
// Open other session
Session session3 = factory.getCurrentSession();
try {
session3.getTransaction().begin();
// Check state of emp
// ==> false
System.out.println(" - emp Persistent? " + session3.contains(emp));
System.out.println(" - Emp salary before update: "
+ emp.getSalary());
// Set new salary for Detached emp object.
emp.setSalary(emp.getSalary() + 100);
// Using saveOrUpdate(emp) to switch emp to Persistent state
// Note: If exists object same ID in session, this method raise Exception
//
// Now, no action with DB.
session3.saveOrUpdate(emp);
// By pushing data into the DB.
// It will call a Insert or update statement.
// If the record is deleted before ==> insert
// Else ==> update.
session3.flush();
System.out
.println(" - Emp salary after update: " + emp.getSalary());
// session3 was closed after a commit is called.
session3.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session3.getTransaction().rollback();
}
}
}
执行上面代码,多几次运行示例错码,可以看到两种情况,saveOrUpdate()
方法调用在数据上插入或更新。得到以下结果 -
11.11-分离转变为持久性状态:使用merge(Object)
Hibernate 2
版本有saveOrUpdateCopy(Object)
方法。从Hibernate 3
起,它被重命名为merge(Object)
。 因此与saveOrUpdate()
相比,merge()
方法有一些相似性和差异。
merge(Object)
不会将对象置于Hibernate的管理下,而是创建一个对象的副本,而不是管理该对象。
如果调用saveOrUpdate(aObject)
则aObject
由Hibernate管理,并且与aObject
具有相同的ID将会抛出异常,但是使用merge(aObject)
时不会得到此异常。
创建一个JAVA类文件:MergeDetachedDemo.java,用于演示将对象分离转变为持久性状态。
package com.yiibai;
import java.util.Random;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class MergeDetachedDemo {
public static void main(String[] args) {
// An object has Detached status
Employee emp = getEmployee_Detached();
System.out.println(" - GET EMP " + emp.getEmpId());
// Random: delete or not delete the Employee by ID.
boolean delete = deleteOrNotDelete(emp.getEmpId());
System.out.println(" - DELETE? " + delete);
// Call saveOrUpdate Detached object
saveOrUpdate_test(emp);
// After call saveOrUpdate
// ...
System.out.println(" - EMP ID " + emp.getEmpId());
}
// Method return Employee object
// and has Detached status.
private static Employee getEmployee_Detached() {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
Long maxEmpId = DataUtils.getMaxEmpId(session1);
System.out.println(" - Max Emp ID " + maxEmpId);
Employee emp2 = DataUtils.findEmployee(session1, "E7839");
Long empId = maxEmpId + 1;
emp = new Employee();
emp.setEmpId(empId);
emp.setEmpNo("E" + empId);
emp.setDepartment(emp2.getDepartment());
emp.setEmpName(emp2.getEmpName());
emp.setHideDate(emp2.getHideDate());
emp.setJob("Test");
emp.setSalary(1000F);
// 'emp' has Persistant state
session1.persist(emp);
// session1 was closed after a commit is called.
// An Employee record are insert into DB.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// session1 closed, 'emp' switched Detached state.
return emp;
}
// Delete Employee by ID
// Random: delete or not delete
private static boolean deleteOrNotDelete(Long empId) {
// A random number 0-9
int random = new Random().nextInt(10);
if (random < 5) {
return false;
}
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
String sql = "Delete " + Employee.class.getName() + " e "
+ " where e.empId =:empId ";
Query query = session2.createQuery(sql);
query.setParameter("empId", empId);
query.executeUpdate();
session2.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
return false;
}
}
private static void saveOrUpdate_test(Employee emp) {
SessionFactory factory = HibernateUtils.getSessionFactory();
// Open other session
Session session3 = factory.getCurrentSession();
try {
session3.getTransaction().begin();
// The fact, 'emp' has Detached state
// It is not managed by Hibernate.
// Check the status of emp:
// ==> false
System.out.println(" - emp Persistent? " + session3.contains(emp));
System.out.println(" - Emp salary before update: "
+ emp.getSalary());
// Set new salary for Detached object 'emp'
emp.setSalary(emp.getSalary() + 100);
// merge(emp) return empMerge, a copy of 'emp',
// empMerge managed by Hibernate
// 'emp' still in Detached state
//
// At this time there is no action regarding DB.
Employee empMerge = (Employee) session3.merge(emp);
// ==> false
System.out.println(" - emp Persistent? " + session3.contains(emp));
// ==> true
System.out.println(" - empMerge Persistent? "
+ session3.contains(empMerge));
// Push data into the DB.
// Here it is possible to create the Insert or Update on DB.
// If the corresponding record has been deleted by someone, it insert
// else it update
session3.flush();
System.out
.println(" - Emp salary after update: " + emp.getSalary());
// session3 closed after a commit is called.
session3.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session3.getTransaction().rollback();
}
}
}
执行上面代码,多几次运行示例错码,可以看到两种情况,得到以下结果 -
11.12 - 分离转变为持久性状态:使用refresh(Object)
创建一个JAVA类文件:RefreshDetachedDemo.java,用于演示将对象分离转变为持久性状态。
package com.yiibai;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.yiibai.DataUtils;
import com.yiibai.HibernateUtils;
import com.yiibai.entities.Employee;
public class RefreshDetachedDemo {
public static void main(String[] args) {
// an Object with Detached status
Employee emp = getEmployee_Detached();
System.out.println(" - GET EMP " + emp.getEmpId());
// Refresh Object
refresh_test(emp);
}
// Return Employee object has Detached state
private static Employee getEmployee_Detached() {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
emp = DataUtils.findEmployee(session1, "E7839");
// session1 was closed after a commit is called.
// An Employee record are insert into DB.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// Session1 closed 'emp' switch to Detached state.
return emp;
}
private static void refresh_test(Employee emp) {
SessionFactory factory = HibernateUtils.getSessionFactory();
// Open other session
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
// Check the status of 'emp' (Detached)
// ==> false
System.out.println(" - emp Persistent? " + session2.contains(emp));
System.out.println(" - Emp salary before update: "
+ emp.getSalary());
// Set new salary for 'emp'.
emp.setSalary(emp.getSalary() + 100);
// refresh: make a query statement
// and switch 'emp' to Persistent state
// The changes are ignored
session2.refresh(emp);
// ==> true
System.out.println(" - emp Persistent? " + session2.contains(emp));
System.out.println(" - Emp salary after refresh: "
+ emp.getSalary());
session2.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
}
}
}
执行上面代码,多几次运行示例错码,可以看到两种情况,得到以下结果 -