Hibernate快速入门

Hibernate是一个开源,轻量级的ORM(对象关系映射)工具。Hibernate框架简化了java应用程序与数据库交互的开发。

ORM工具简化了数据创建,数据处理和数据访问。它是将对象映射到数据库中存储的数据(表)的编程技术。

注:为什么会有这篇教程文章?答:只是想写一篇最NB的Hibernate教程入门文章。NB代表人见人爱,花见花开,车见爆胎,飞鸟落地...,最后,需要注意的是:这篇文章包教不包会!除非你从头到尾认真看完并运行所有示例代码。

1. Hibernate快速入门简介

本教程文章基于以下工具(软件):

  • Hibernate 5.2.2.Final
  • Eclipse 4.6 (MARS)

Hibernate.x ~ Hibernate.5 更新功能:

  1. Hibernate 5.0开始Hibernate Spatial是Hibernate项目的一部分,因此我们也可以处理GIS数据了。

  2. 域模型映射支持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.OffsetDateTimejava.time.ZonedDateTime
  1. 字节码增强机制从头重新设计,Hibernate可支持Maven和Gradle插件。可以通过字节码仪器来增强三个主要方面:
  • 懒初始化:字段可以声明为LAZY,只有在第一次被访问时,它们才被提取。
  • 脏检查:实体被增强,使得它们可以跟踪在持久化上下文中加载之后变化的所有属性。
  • 双向关联:即使开发人员仅更新单侧,但也可以自动同步双向关联的双方。
  1. Hibernate的原生API(Session等)已更新为使用泛型类型化。无需在获取实体时转换。
  2. Hibernate 5.0将其扩展到更广泛的类型(例如UUID)。
  3. 引用二级缓存,使实体引用能够直接存储到第二级缓存中(用于不可变实体)。

2. 准备数据库

Hibernate是一个库,为了处理所有类型的数据库,它不依赖于应用程序选择的任何类型的数据库,如果Java是“一次写入到处运行”的语言,Hibernate则是“写一次就可运行在所有类型的数据库“中的框架。

在这篇文章中,使用的是MySQL数据(你可使用其它的数据库,如:Oracle,MySQL或SQL Server),并创建一个简单的数据库:mydb,完整的数据库创建语句如下所示:

创建数据:

CREATE DATABASE IF NOT EXISTS mydb default charset utf8 COLLATE utf8_general_ci; 

需要创建以下几张表,它们的关系图如下所示 -

Hibernate快速入门_第1张图片

创建表语句:

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,如下所示 -

Hibernate快速入门_第2张图片

下一步选择工作目录,如下图所示 -

Hibernate快速入门_第3张图片

下一步,选择模板类型,如下图所示 -

Hibernate快速入门_第4张图片

下一步,写入工程名称:HibernateQuickStart,以及输入包信息:com.yiibai 等信息。

Hibernate快速入门_第5张图片

项目(HibernateQuickStart)创建完成后,如下图所示 -

Hibernate快速入门_第6张图片

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

所有创建的类如下图所示 -

Hibernate快速入门_第7张图片

这几个类的代码,分别如下所示 -

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();
       }
   }
    
}

运行上面代码,得到以下结果 -

Hibernate快速入门_第8张图片

查询对象示例-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 query = session.createQuery(sql);
  
            // Execute Query.
            // Get the array of Object
            List datas = query.getResultList();
 
            for (Object[] emp : datas) {
                System.out.println("Emp Id: " + emp[0]);
                System.out.println("    Emp No: " + emp[1]);
                System.out.println("    Emp Name: " + emp[2]);
            }
  
            // Commit data.
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            // Rollback in case of an error occurred.
            session.getTransaction().rollback();
        }
  
    }
}

运行上面代码,得到以下结果 -

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();
        }
    }
     
}

运行上面代码,得到以下结果 -

Hibernate快速入门_第9张图片

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();
        }
    }
     
}

运行上面代码,得到以下结果 -

Hibernate快速入门_第10张图片

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());
        
   }
    
}

运行上面代码,得到以下结果 -

Hibernate快速入门_第11张图片

10. Hibernate生命周期

Hibernate的Session类的有一些/几组的重要方法,如下图所示:

Hibernate快速入门_第12张图片

Hibernate中的一个对象存在于以下四个状态之中的一种:

  • 短暂(Transient)
  • 持久(Persistent)
  • Removed
  • Detached

以上几个状态在下面图中解释:

Hibernate快速入门_第13张图片

下面来看这几个状态的流转说明 -

  1. 当从一个实体创建一个新的Java对象时,该对象处于“短暂”状态。 Hibernate不知道它的存在,因为它独立于Hibernate的管理。

  2. 如果使用方法:getloadfind获取实体对象,则将获得一个等同于数据库中的1条记录的对象。 此对象处于Persistent状态。 它由Hibernate管理。

  3. 会话调用方法:savesaveOrUpdatepersist。 合并将短暂(Transient)对象置于Hibernate的管理之下,此对象转为持久化(Persistent)状态。 在使用的具体情况下,它向数据库插入或更新数据。

  4. Session调用evict(..)clear(),以便从处于Hibernate管理状态的对象处于关闭状态,并且这些对象处于分离(Detached)的状态。

  5. 使用update(..)saveOrUpdate(..)merge(..)将有助于重新连接分离对象。 在具体情况下,它会向数据库中创建更新或插入数据。 对象转回持久化(Persistent)状态。

  6. Session调用方法:remove(..)delete(..)删除除记录并持久化对象。

11. 用Hibernate插入,更新,删除

11.1 - 持久化(Persistent)

当一个对像使用 Sessionget(),load(),find()方法获取关联数据时,它处于持久化(Persistent)状态。

Hibernate快速入门_第14张图片

创建一个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();
       }
   }
    
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第15张图片

11.2 - 瞬态转为持久化状态

Hibernate快速入门_第16张图片

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();
       }
   }
    
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第17张图片

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();
       }
   }
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第18张图片

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();
       }
   }
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第19张图片

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();
       }
   }
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第20张图片

11.7 - 持久化转变为分离状态

由Hibernate管理的持久化(Persistent)条件中的一个对象可以通过以下两个Session的方法转换为Detached(独立于Hibernate的管理)状态:

  • evict (Object) - 从Hibernate管理中删除一个对象

  • clear() - 从Hibernate管理的对象中删除所有对象。

当然,当Session调用顺序为:commit()close()rollback()时,当前会话已经完成。 此会话的所有Persistence对象将从新打开的会话中分离。

Hibernate快速入门_第21张图片

创建一个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();
       }
   }
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第22张图片

创建一个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();
       }
   }
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第23张图片

11.8 - 分离状态转变为持久化状态

Hibernate管理分离的对象可以通过以下Session的一些方法重新附加:

  • update(Object)
  • saveOrUpdate(Object)
  • merge(Object)
  • refresh(Object)
  • lock(Object)

可以在以下示例中看到这些方法的区别:

Hibernate快速入门_第24张图片

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();
        }

    }
}

执行上面代码,得到以下结果 -

Hibernate快速入门_第25张图片

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()方法调用在数据上插入或更新。得到以下结果 -

Hibernate快速入门_第26张图片

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();
       }
 
   }
 
}

执行上面代码,多几次运行示例错码,可以看到两种情况,得到以下结果 -

Hibernate快速入门_第27张图片

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();
       }
 
   }
 
}

执行上面代码,多几次运行示例错码,可以看到两种情况,得到以下结果 -

Hibernate快速入门_第28张图片

你可能感兴趣的:(Hibernate快速入门)