• 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.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 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 , 其代码如下 -

    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;
    
    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 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<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: 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

    创建一个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

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

  • 相关阅读:
    [日本语]自动词和他动词区别的重要性
    [日本语]授受关系动词总结
    [日本语]至少すくなく(と)も
    python3: 文件与IO
    python3: 迭代器与生成器(1)
    python3: 数字日期和时间(2)
    python3: 数字日期和时间(1)
    python3: 字符串和文本(4)
    Python Frame
    python3: 字符串和文本(3)
  • 原文地址:https://www.cnblogs.com/borter/p/9522226.html
Copyright © 2020-2023  润新知