Hibernate快速入门

来源:互联网 发布:淘宝店铺公告在哪里 编辑:程序博客网 时间:2024/05/22 18:22
转自:http://www.yiibai.com/hibernate/hibernate-quick-guide.html

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.LocalTimejava.time.OffsetTime
    • TIMESTAMP: java.time.Instantjava.time.LocalDateTime,java.time.OffsetDateTime 和 java.time.ZonedDateTime
  3. 字节码增强机制从头重新设计,Hibernate可支持Maven和Gradle插件。可以通过字节码仪器来增强三个主要方面:

    • 懒初始化:字段可以声明为LAZY,只有在第一次被访问时,它们才被提取。
    • 脏检查:实体被增强,使得它们可以跟踪在持久化上下文中加载之后变化的所有属性。
    • 双向关联:即使开发人员仅更新单侧,但也可以自动同步双向关联的双方。
  4. Hibernate的原生API(Session等)已更新为使用泛型类型化。无需在获取实体时转换。

  5. Hibernate 5.0将其扩展到更广泛的类型(例如UUID)。
  6. 引用二级缓存,使实体引用能够直接存储到第二级缓存中(用于不可变实体)。

2. 准备数据库

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

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

创建数据:

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

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

创建表语句:

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);
SQL

向上面创建的表中,分别插入一些测试数据,如下所示 -

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);
SQL

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 配置/声明如下所示 -

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.yiibai</groupId>    <artifactId>HibernateQuickStart</artifactId>    <version>0.0.1-SNAPSHOT</version>    <packaging>jar</packaging>    <name>HibernateQuickStart</name>    <url>http://maven.apache.org</url>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    </properties>    <dependencies>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>3.8.1</version>            <scope>test</scope>        </dependency>        <!-- Hibernate Core -->        <!-- http://mvnrepository.com/artifact/org.hibernate/hibernate-core -->        <dependency>            <groupId>org.hibernate</groupId>            <artifactId>hibernate-core</artifactId>            <version>5.2.2.Final</version>        </dependency>        <!-- MySQL JDBC driver -->        <!-- http://mvnrepository.com/artifact/mysql/mysql-connector-java -->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>5.1.34</version>        </dependency>        <!-- SQLServer JDBC driver (JTDS) -->        <!-- http://mvnrepository.com/artifact/net.sourceforge.jtds/jtds -->        <dependency>            <groupId>net.sourceforge.jtds</groupId>            <artifactId>jtds</artifactId>            <version>1.3.1</version>        </dependency>    </dependencies></project>
XML

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<Employee> employees = new HashSet<Employee>(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<Employee> getEmployees() {        return employees;    }    public void setEmployees(Set<Employee> employees) {        this.employees = employees;    }}
Java

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<Employee> employees = new HashSet<Employee>(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<Employee> getEmployees() {        return employees;    }    public void setEmployees(Set<Employee> employees) {        this.employees = employees;    }}
Java

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;    }}
Java

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;    }}
Java

5. 配置hibernate

配置hibernate目的是让Hibernate可以连接数据库并与数据库交互,并声明在前面的步骤中创建的实体列表。

src/main/java中创建一个名称为:hibernate.cfg.xml 的配置文件,当前项目结构如下图所示 -

hibernate.cfg.xml 配置文件的内容如下所示 -

<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration>  <session-factory>      <!-- Database connection settings -->      <property name="connection.driver_class">com.mysql.jdbc.Driver</property>      <property name="connection.url">jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC</property>      <property name="connection.username">root</property>      <property name="connection.password">123456</property>      <!-- JDBC connection pool (use the built-in) -->      <property name="connection.pool_size">1</property>      <!-- SQL dialect -->      <property name="dialect">org.hibernate.dialect.MySQLDialect</property>      <!-- Enable Hibernate's automatic session context management -->      <property name="current_session_context_class">thread</property>      <!-- Disable the second-level cache -->      <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>      <!-- Echo all executed SQL to stdout -->      <property name="show_sql">true</property>      <mapping class="com.yiibai.entities.Department" />      <mapping class="com.yiibai.entities.Employee" />      <mapping class="com.yiibai.entities.SalaryGrade" />      <mapping class="com.yiibai.entities.Timekeeper" />  </session-factory></hibernate-configuration>
XML

每种数据库都有一个单独的方言, 例如:

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类型OracleMySQLSQL ServerTypes.BITnumber(1,0)bitbitTypes.BIGINTnumber(19,0)biginbigintTypes.DATEdatedatedate…….………Types.CLOBcloblongtextvarchar(MAX)Types.BLOBbloblongblobvarbinary(MAX)

6. SessionFactory

创建一个文件: HibernateUtils.java , 其代码如下 -

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 ObjectSelect d from Department d;
SQL

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<Employee> query = session.createQuery(sql);           // Execute query.           List<Employee> 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();       }   }}
Java

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

查询对象示例-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<Employee> query = session.createQuery(sql);            query.setParameter("deptNo", "D10");            // Execute query.            List<Employee> 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();        }    }}
Java

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

......org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateServiceINFO: HHH000397: Using ASTQueryTranslatorFactoryHibernate: select employee0_.EMP_ID ..._NO=?Emp: E7839 : KINGEmp: 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<Object[]> query = session.createQuery(sql);            // Execute Query.            // Get the array of Object            List<Object[]> 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();        }    }}
Java

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

Hibernate: select employee0_.EMP_ID..._0_ from EMPLOYEE employee0_Emp Id: 7369    Emp No: E7369    Emp Name: SMITHEmp Id: 7499    Emp No: E7499    Emp Name: ALLENEmp Id: 7521    Emp No: E7521    Emp Name: WARDEmp Id: 7566    Emp No: E7566    Emp Name: JONESEmp Id: 7654    Emp No: E7654    Emp Name: MARTINEmp Id: 7698    Emp No: E7698    Emp Name: BLAKEEmp Id: 7782    Emp No: E7782    Emp Name: CLARKEmp Id: 7788    Emp No: E7788    Emp Name: SCOTTEmp Id: 7839    Emp No: E7839    Emp Name: KINGEmp Id: 7844    Emp No: E7844    Emp Name: TURNEREmp Id: 7876    Emp No: E7876    Emp Name: ADAMSEmp Id: 7900    Emp No: E7900    Emp Name: ADAMSEmp Id: 7902    Emp No: E7902    Emp Name: FORDEmp 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

创建一个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<ShortEmpInfo> query = session.createQuery(sql);            // Execute query.            // Get a List of ShortEmpInfo            List<ShortEmpInfo> 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();        }    }}
Java

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

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

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

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<Department> 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<Number> 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<Employee> query = session.createQuery(sql);       query.setParameter("empNo", empNo);       return query.getSingleResult();   }}
Java

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

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

10. Hibernate生命周期

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

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

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

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

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

  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)

当一个对像使用 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();       }   }}
Java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

执行上面代码,多几次运行示例错码,可以看到两种情况,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();       }   }}
Java

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

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

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