Hibernate 简明教程

Hibernate - Annotations

到目前为止,你已经看到了 Hibernate 如何使用 XML 映射文件将数据从 POJO 转换为数据库表,反之亦然。Hibernate 注释是无需使用 XML 文件便可以定义映射的最新方式。你可以除了或替换 XML 映射元数据以外,还可以使用注释。

So far you have seen how Hibernate uses XML mapping file for the transformation of data from POJO to database tables and vice versa. Hibernate annotations are the newest way to define mappings without the use of XML file. You can use annotations in addition to or as a replacement of XML mapping metadata.

Hibernate 注释是以强大方式为对象和关系表映射提供元数据的方法。所有元数据与代码一起打包到 POJO Java 文件中,这有助于用户在开发期间同时了解表结构和 POJO。

Hibernate Annotations is the powerful way to provide the metadata for the Object and Relational Table mapping. All the metadata is clubbed into the POJO java file along with the code, this helps the user to understand the table structure and POJO simultaneously during the development.

如果你打算让应用程序可移植到其他 EJB 3 兼容的 ORM 应用程序,则必须使用注释来表示映射信息,但如果你仍然想要更大的灵活性,则应该选择基于 XML 的映射。

If you going to make your application portable to other EJB 3 compliant ORM applications, you must use annotations to represent the mapping information, but still if you want greater flexibility, then you should go with XML-based mappings.

Environment Setup for Hibernate Annotation

首先,你必须确保正在使用 JDK 5.0,否则需要将 JDK 升级到 JDK 5.0 以利用对注释的本机支持。

First of all you would have to make sure that you are using JDK 5.0 otherwise you need to upgrade your JDK to JDK 5.0 to take advantage of the native support for annotations.

其次,你需要安装 Hibernate 3.x 注释发行包,该包可从 Sourceforge 获得:( Download Hibernate Annotation ),并将 hibernate-annotations.jar, lib/hibernate-comons-annotations.jarlib/ejb3-persistence.jar 从 Hibernate 注释发行包复制到 CLASSPATH。

Second, you will need to install the Hibernate 3.x annotations distribution package, available from the sourceforge: (Download Hibernate Annotation) and copy hibernate-annotations.jar, lib/hibernate-comons-annotations.jar and lib/ejb3-persistence.jar from the Hibernate Annotations distribution to your CLASSPATH.

Annotated Class Example

如上所述,在使用 Hibernate 注释时,所有元数据与代码一起打包到 POJO Java 文件中,这有助于用户在开发期间同时了解表结构和 POJO。

As I mentioned above while working with Hibernate Annotation, all the metadata is clubbed into the POJO java file along with the code, this helps the user to understand the table structure and POJO simultaneously during the development.

考虑我们准备使用以下 EMPLOYEE 表来存储我们的对象 -

Consider we are going to use the following EMPLOYEE table to store our objects −

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

以下是 Employee 类的映射,带有注释,以将对象映射到定义的 EMPLOYEE 表中 -

Following is the mapping of Employee class with annotations to map objects with the defined EMPLOYEE table −

import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {
   @Id @GeneratedValue
   @Column(name = "id")
   private int id;

   @Column(name = "first_name")
   private String firstName;

   @Column(name = "last_name")
   private String lastName;

   @Column(name = "salary")
   private int salary;

   public Employee() {}

   public int getId() {
      return id;
   }

   public void setId( int id ) {
      this.id = id;
   }

   public String getFirstName() {
      return firstName;
   }

   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }

   public String getLastName() {
      return lastName;
   }

   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }

   public int getSalary() {
      return salary;
   }

   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Hibernate 检测到 @Id 注释位于一个字段上,并假设它应该在运行时直接通过字段访问对象的属性。如果将 @Id 注释放在 getId() 方法上,就会默认允许通过 getter 和 setter 方法访问属性。因此,根据所选策略,所有其他的注释也都会放在字段上或 getter 方法上。

Hibernate detects that the @Id annotation is on a field and assumes that it should access properties of an object directly through fields at runtime. If you placed the @Id annotation on the getId() method, you would enable access to properties through getter and setter methods by default. Hence, all other annotations are also placed on either fields or getter methods, following the selected strategy.

以下部分将解释在上述类中使用的注释。

Following section will explain the annotations used in the above class.

@Entity Annotation

EJB 3 标准注释包含在 javax.persistence 包中,因此我们将此包作为第一步导入。其次,我们在 Employee 类中使用了 @Entity 注释,它将此类标记为实体 bean,因此它必定有一个无参数构造函数,并且至少具有受保护的作用域可见性。

The EJB 3 standard annotations are contained in the javax.persistence package, so we import this package as the first step. Second, we used the @Entity annotation to the Employee class, which marks this class as an entity bean, so it must have a no-argument constructor that is visible with at least protected scope.

@Table Annotation

@Table 注释允许您指定表中的详细信息,这些信息将用于保留数据库中的实体。

The @Table annotation allows you to specify the details of the table that will be used to persist the entity in the database.

@Table 注释提供了四个属性,允许您覆盖表名称、其目录以及其架构,并强制执行表中列的唯一约束。目前,我们仅使用表名称,即 EMPLOYEE。

The @Table annotation provides four attributes, allowing you to override the name of the table, its catalogue, and its schema, and enforce unique constraints on columns in the table. For now, we are using just table name, which is EMPLOYEE.

@Id and @GeneratedValue Annotations

每个实体 bean 都将有一个主键,您使用 @Id 注释在类上为此进行注释。主键可以是单个字段或多个字段的组合,具体取决于您的表结构。

Each entity bean will have a primary key, which you annotate on the class with the @Id annotation. The primary key can be a single field or a combination of multiple fields depending on your table structure.

默认情况下,@Id 注释将自动确定要使用的最合适的主键生成策略,但是您可以通过应用 @GeneratedValue 注释来覆盖该策略,该注释采用两个参数 strategygenerator ,我将不会在这里讨论它们,因此让我们仅使用默认的主键生成策略。让 Hibernate 确定要使用哪种生成器类型,可以使您的代码在不同的数据库之间具有可移植性。

By default, the @Id annotation will automatically determine the most appropriate primary key generation strategy to be used but you can override this by applying the @GeneratedValue annotation, which takes two parameters strategy and generator that I’m not going to discuss here, so let us use only the default key generation strategy. Letting Hibernate determine which generator type to use makes your code portable between different databases.

@Column Annotation

@Column 注释用于指定字段或属性将映射到的列的详细信息。您可以将列注释与以下最常用的属性一起使用 -

The @Column annotation is used to specify the details of the column to which a field or property will be mapped. You can use column annotation with the following most commonly used attributes −

  1. name attribute permits the name of the column to be explicitly specified.

  2. length attribute permits the size of the column used to map a value particularly for a String value.

  3. nullable attribute permits the column to be marked NOT NULL when the schema is generated.

  4. unique attribute permits the column to be marked as containing only unique values.

Create Application Class

最后,我们将使用 main() 方法创建我们的应用程序类来运行应用程序。我们将使用此应用程序来保存一些 Employee 的记录,然后我们将对这些记录应用 CRUD 操作。

Finally, we will create our application class with the main() method to run the application. We will use this application to save few Employee’s records and then we will apply CRUD operations on those records.

import java.util.List;
import java.util.Date;
import java.util.Iterator;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory;
   public static void main(String[] args) {

      try {
         factory = new AnnotationConfiguration().
                   configure().
                   //addPackage("com.xyz") //add package if used.
                   addAnnotatedClass(Employee.class).
                   buildSessionFactory();
      } catch (Throwable ex) {
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex);
      }

      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 10000);

      /* List down all the employees */
      ME.listEmployees();

      /* Update employee's records */
      ME.updateEmployee(empID1, 5000);

      /* Delete an employee from the database */
      ME.deleteEmployee(empID2);

      /* List down new list of the employees */
      ME.listEmployees();
   }

   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;

      try {
         tx = session.beginTransaction();
         Employee employee = new Employee();
         employee.setFirstName(fname);
         employee.setLastName(lname);
         employee.setSalary(salary);
         employeeID = (Integer) session.save(employee);
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
      return employeeID;
   }

   /* Method to  READ all the employees */
   public void listEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;

      try {
         tx = session.beginTransaction();
         List employees = session.createQuery("FROM Employee").list();
         for (Iterator iterator = employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next();
            System.out.print("First Name: " + employee.getFirstName());
            System.out.print("  Last Name: " + employee.getLastName());
            System.out.println("  Salary: " + employee.getSalary());
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
   }

   /* Method to UPDATE salary for an employee */
   public void updateEmployee(Integer EmployeeID, int salary ){
      Session session = factory.openSession();
      Transaction tx = null;

      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID);
         employee.setSalary( salary );
		 session.update(employee);
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
   }

   /* Method to DELETE an employee from the records */
   public void deleteEmployee(Integer EmployeeID){
      Session session = factory.openSession();
      Transaction tx = null;

      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID);
         session.delete(employee);
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace();
      } finally {
         session.close();
      }
   }
}

Database Configuration

现在,让我们创建 hibernate.cfg.xml 配置文件来定义与数据库相关的参数。

Now let us create hibernate.cfg.xml configuration file to define database related parameters.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>

      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>

      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>

      <!-- Assume students is the database name -->

      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>

      <property name = "hibernate.connection.username">
         root
      </property>

      <property name = "hibernate.connection.password">
         cohondob
      </property>

   </session-factory>
</hibernate-configuration>

Compilation and Execution

以下是编译和运行上述应用程序的步骤。请确保在继续编译和执行之前,已适当地设置 PATH 和 CLASSPATH。

Here are the steps to compile and run the above mentioned application. Make sure, you have set PATH and CLASSPATH appropriately before proceeding for the compilation and execution.

  1. Delete Employee.hbm.xml mapping file from the path.

  2. Create Employee.java source file as shown above and compile it.

  3. Create ManageEmployee.java source file as shown above and compile it.

  4. Execute ManageEmployee binary to run the program.

您将获得以下结果,并且记录将被创建到 EMPLOYEE 表中。

You would get the following result, and records would be created in EMPLOYEE table.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000

如果检查您的 EMPLOYEE 表,它应包含以下记录 −

If you check your EMPLOYEE table, it should have the following records −

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>