Hibernate 第一个Hibernate应用程序

Table of Contents   目录

1.1. Part 1 - The first Hibernate Application   第一节 第一个Hibernate应用程序
1.1.1. Setup   设置开发环境 1.1.2. The first class  创建第一个类 1.1.3. The mapping file  创建类与数据库表的映射文件 1.1.4. Hibernate configuration  Hibernate与数据库连接 配置文件 1.1.5. Building with Maven  用Maven构建项目 1.1.6. Startup and helpers   启动和助手 1.1.7. Loading and storing objects   Hibernate加载与存储数据对象

Intended for new users, this chapter provides an step-by-step introduction to Hibernate, starting with a simple application using an in-memory database. The tutorial is based on an earlier tutorial developed by Michael Gloegl. All code is contained in the tutorials/web directory of the project source.

针对初学的使用者, 本章提供一个循序渐进的的介绍Hibernate, 从一个简单的应用开始,这个应用使用内存数据库。这个使用说明书是基于早先由Michael Gloegl写的辅导材料。 所有的代码都被包含在这个项目源码的tutorials/web目录。(这个项目源码我没有找到,只找到个hibernate-tutorials不是web项目,所以自己写了一个。)

Important  重要

This tutorial expects the user have knowledge of both Java and SQL. If you have a limited knowledge of JAVA or SQL, it is advised that you start with a good introduction to that technology prior to attempting to learn Hibernate.

这个辅导材料要求用户需要有java和SQL方面的知识。如果你java和SQL方面的知识还不熟悉,建议你尝试学习Hibernate之前,请优先学习相关的java和SQL基础知识。

Note  备注

The distribution contains another example application under the tutorial/eg project source directory.

这个教程包含另一个应用范例,它在项目源码的 tutorial/eg 目录。

For this example, we will set up a small database application that can store events we want to attend and information about the host(s) of these events.

对于这个例子,我们将建立一个小的数据库应用程序,可以存储我们想参加的事件和这些事件的参与者信息。

Note 备注

Although you can use whatever database you feel comfortable using, we will use HSQLDB (an in-memory, Java database) to avoid describing installation/setup of any particular database servers.

虽然你可以使用任何你觉得舒服的数据库,我们将使用HSQLDB(一个内存数据库,java 数据库)避免描述任何特定的数据库服务器的安装/配置。

The first thing we need to do is to set up the development environment. We will be using the "standard layout" advocated by alot of build tools such as Maven. Maven, in particular, has a good resource describing this layout. As this tutorial is to be a web application, we will be creating and making use of src/main/java,src/main/resources and src/main/webapp directories.

我们需要做的第一件事是配置开发环境。我们将使用“标准布局” ,这种标准布局被很多构建工具支持,如Maven。特别是,Maven有一个很好的资源描述这种布局。因为本教程是一个Web应用程序,所以我们将创造和使用src/main/javasrc/main/resources 和 src/main/webap 目录。

We will be using Maven in this tutorial, taking advantage of its transitive dependency management capabilities as well as the ability of many IDEs to automatically set up a project for us based on the maven descriptor.

在本教程中,我们将使用Maven,利用其传递依赖管理能力以及许多IDE能够基于maven描述文件为我们自动创建一个项目。(描述文件中的依赖配置没有指明版本,编译时会报错。)

<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>org.hibernate.tutorials</groupId>
    <artifactId>hibernate-tutorial</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>First Hibernate Tutorial</name>

    <build>
         <!-- we dont want the version to be part of the generated war file name -->
         <finalName>${artifactId}</finalName>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

        <!-- Because this is a web app, we also have a dependency on the servlet api. -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </dependency>

        <!-- Hibernate uses slf4j for logging, for our purposes here use the simple backend -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
        </dependency>

        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
        </dependency>
    </dependencies>

</project>

Tip  提示

It is not a requirement to use Maven. If you wish to use something else to build this tutorial (such as Ant), the layout will remain the same. The only change is that you will need to manually account for all the needed dependencies. If you use something like Ivy providing transitive dependency management you would still use the dependencies mentioned below. Otherwise, you'd need to grab all dependencies, both explicit and transitive, and add them to the project's classpath. If working from the Hibernate distribution bundle, this would mean hibernate3.jar, all artifacts in thelib/required directory and all files from either the lib/bytecode/cglib orlib/bytecode/javassist directory; additionally you will need both the servlet-api jar and one of the slf4j logging backends.

不要求必须使用Maven。如果您希望使用其他的东西来构建本教程(如Ant),布局将保持不变。唯一的变化是,你将需要手动解释所有所需的依赖关系。如果你使用像 Ivy 提供传递的依赖管理之类的东西,你仍然会使用下面提到的依赖关系。否则,你需要抓取所有的依赖性(包括明确的和传递的依赖的jar),并将它们添加到项目的classpath路径。如果从Hibernate分布束工作,这就意味着hibernate3.jar,在 lib/required 目录下的所有jar和在lib/bytecode/cglib orlib/bytecode/javassist 目录下的所有文件;此外,您将需要将servlet-api jar 和 slf4j jar放入后台(后面那句有点别扭,并且slf4j和javassist的依赖其实不写也不会报错的

Save this file as pom.xml in the project root directory.

在项目的根目录保存这个文件为  pom.xml 

Next, we create a class that represents the event we want to store in the database; it is a simple JavaBean class with some properties:

接下来,我们创建一个类来表示我们要在数据库中存储的事件;这是一个带有一些属性的简单的JavaBean类:

package org.hibernate.tutorial.domain;

import java.util.Date;

public class Event {
    private Long id;

    private String title;
    private Date date;

    public Event() {}

    public Long getId() {
        return id;
    }

    private void setId(Long id) {
        this.id = id;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

This class uses standard JavaBean naming conventions for property getter and setter methods, as well as private visibility for the fields. Although this is the recommended design, it is not required. Hibernate can also access fields directly, the benefit of accessor methods is robustness for refactoring.

这类使用标准的JavaBean命名规范定义属性的getter和setter方法,使得私有的属性可见。虽然这是推荐的设计,但不是必须的。Hibernate也可以直接访问字段,访问器方法的好处是重构的健壮性。

The id property holds a unique identifier value for a particular event. All persistent entity classes (there are less important dependent classes as well) will need such an identifier property if we want to use the full feature set of Hibernate. In fact, most applications, especially web applications, need to distinguish objects by identifier, so you should consider this a feature rather than a limitation. However, we usually do not manipulate the identity of an object, hence the setter method should be private. Only Hibernate will assign identifiers when an object is saved. Hibernate can access public, private, and protected accessor methods, as well as public, private and protected fields directly. The choice is up to you and you can match it to fit your application design.

id属性保存了一个特别的事件中唯一标示符值。如果我们想要使用Hibernate的所有功能,所有的持久化实体类(以及一些不重要的类)将会需要这样一个标示符属性.事实上,大部分的应用,特别是web应用,需要需要通过唯一的标示符来区分对象,因此你应该把它看做一个特性,而不是限制。然而,我们通常不会操作对象的唯一标示符,因此,setter方法应该是私有的。仅当一个对象被保存时,Hibernate才会分配这个唯一标示的值。Hibernate可以访问公有、私有、受保护的变量和方法。选择权在你,你可以为了适合你的应用设计而做出调整。

The no-argument constructor is a requirement for all persistent classes; Hibernate has to create objects for you, using Java Reflection. The constructor can be private, however package or public visibility is required for runtime proxy generation and efficient data retrieval without bytecode instrumentation.

无参的构造函数对所有的持久的类来说是必须的; Hibernate是使用JAVA 反射来创建对象。构造函数可以是私有的,但是包和公有可见性对于动态代理生成而言是必须的。在没有字节码的情况下可以高效的数据检索。

Save this file to the src/main/java/org/hibernate/tutorial/domain directory.

在 src/main/java/org/hibernate/tutorial/domain 目录保存文件为Event.java。

Hibernate needs to know how to load and store objects of the persistent class. This is where the Hibernate mapping file comes into play. The mapping file tells Hibernate what table in the database it has to access, and what columns in that table it should use.

Hibernate需要知道如何加载和保存持久类的对象。这是Hibernate映射文件需要的地址。映射文件告诉Hibernate已经访问在数据库中的哪张表,并且表中的哪行在使用。

The basic structure of a mapping file looks like this:

映射文件的基本结构如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="org.hibernate.tutorial.domain">
[...]
</hibernate-mapping>

Hibernate DTD is sophisticated. You can use it for auto-completion of XML mapping elements and attributes in your editor or IDE. Opening up the DTD file in your text editor is the easiest way to get an overview of all elements and attributes, and to view the defaults, as well as some comments. Hibernate will not load the DTD file from the web, but first look it up from the classpath of the application. The DTD file is included inhibernate-core.jar (it is also included in the hibernate3.jar, if using the distribution bundle).

Hibernate DTD是复杂的。你可以在你的编辑器或者IDE中使用它,以便于自动完成XML的属性和元素的映射。在你的文本编辑器中打开DTD文件是获得一个所有元素和属性该来的最简单的方式,还有查看默认的内容。Hibernate不会从站点加载DTD文件,但是会先从classpath查看。DTD文件包含在hibernate-core.jar 这个jar包中(如果使用分布式的话,也包含在hibernate3.jar中)。

Important 重要

We will omit the DTD declaration in future examples to shorten the code. It is, of course, not optional.

为了缩短代码的长度我们将会省略DTD的声明。在实际使用中当然是必须的。

Between the two hibernate-mapping tags, include a class element. All persistent entity classes (again, there might be dependent classes later on, which are not first-class entities) need a mapping to a table in the SQL database:

在两个hibernate-mapping 标签之间包括了一个类元素。所有持久化实体类需要映射到数据库中的表:

<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">

    </class>

</hibernate-mapping>

So far we have told Hibernate how to persist and load object of class Event to the table EVENTS. Each instance is now represented by a row in that table. Now we can continue by mapping the unique identifier property to the tables primary key. As we do not want to care about handling this identifier, we configure Hibernate's identifier generation strategy for a surrogate primary key column:

到目前为止,我们已经告诉Hibernate如何取持久和加载Event类到EVENTS表中。每个实例现在代表着表中的一行。现在我们可以继续通过映射唯一标示符属性到表中的主键中。因此我们不想关心怎么产生这个标示符,我们配置Hibernate的标示符产生策略对应着一个代理的主键行:

<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">
        <id name="id" column="EVENT_ID">
            <generator class="native"/>
        </id>
    </class>

</hibernate-mapping>

The id element is the declaration of the identifier property. The name="id" mapping attribute declares the name of the JavaBean property and tells Hibernate to use the getId() and setId() methods to access the property. The column attribute tells Hibernate which column of the EVENTS table holds the primary key value.

这个id元素是唯一标示符属性的描述。name="id"映射属性定义JavaBean属性的名字和告诉Hibernate去使用getId()和setId()方法来访问属性。行属性告诉Hibernate,EVENTS表的哪行保持了主键的值。

The nested generator element specifies the identifier generation strategy (aka how are identifier values generated?). In this case we choose native, which offers a level of portability depending on the configured database dialect. Hibernate supports database generated, globally unique, as well as application assigned, identifiers. Identifier value generation is also one of Hibernate's many extension points and you can plugin in your own strategy.

嵌套的generator元素指定了标示符产生的策略(又叫做标示符的值怎么产生的)。在这个例子中,我们选择native,native提供了一个依赖于配置数据库的方言的可移植性的水平。Hibernate提供数据库生成标示符全局唯一性还有应用分配。标示符值产生的方式是Hibernate的许多扩展点中的其中一个,并且你可以在你自己的策略中进行插入。

Tip 提示

native is no longer consider the best strategy in terms of portability. for further discussion, see Section 27.4, “Identifier generation”

native 不再是根据可移植性来考虑的最佳策略。更多的讨论,详见连接。

Lastly, we need to tell Hibernate about the remaining entity class properties. By default, no properties of the class are considered persistent:

最后,我们需要告诉Hibernate关于仍旧保持实体类的属性。通过默认的方式,没有类中的属性是持久化的:

<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">
        <id name="id" column="EVENT_ID">
            <generator class="native"/>
        </id>
        <property name="date" type="timestamp" column="EVENT_DATE"/>
        <property name="title"/>
    </class>

</hibernate-mapping>

Similar to the id element, the name attribute of the property element tells Hibernate which getter and setter methods to use. In this case, Hibernate will search for getDate()setDate()getTitle() and setTitle() methods.

类似于id元素,property元素的name属性告诉Hibernate使用哪个getter和setter方法。在这个例子中,Hibernate将会搜索getDate(),setDate(),getTitle()和setTitle()方法。

Note 提示

Why does the date property mapping include the column attribute, but the titledoes not? Without the column attribute, Hibernate by default uses the property name as the column name. This works for title, however, date is a reserved keyword in most databases so you will need to map it to a different name.

为什么date属性映射的时候包括了column属性,而title并没有呢?在没有column属性的情况下,Hibernate通过默认使用属性名称作为column名字。这对title是管用的,然而,date在大多数数据库中是一个保留关键字,因此你需要将它映射为一个不同的名字。

The title mapping also lacks a type attribute. The types declared and used in the mapping files are not Java data types; they are not SQL database types either. These types are called Hibernate mapping types, converters which can translate from Java to SQL data types and vice versa. Again, Hibernate will try to determine the correct conversion and mapping type itself if the type attribute is not present in the mapping. In some cases this automatic detection using Reflection on the Java class might not have the default you expect or need. This is the case with the date property. Hibernate cannot know if the property, which is ofjava.util.Date, should map to a SQL datetimestamp, or time column. Full date and time information is preserved by mapping the property with a timestamp converter.

title映射也缺少一个type属性。在映射文件中类型的定义和使用并不是Java数据的类型;他们也不是SQL数据库的类型。这些类型称为Hibernate映射类型,翻译器可以从Java转换为SQL数据类型,反之亦然。再一次,Hibernate将会尝试去决定正确的转换并且映射类型自己如果type属性没有出现在映射中。在一些例子中,这些使用Java反射检查也许并不是你所需要和期望的。这个例子中带有date属性。如果是java.util.Date这个类的属性,Hibernate不能知道到底是映射为SQL中的date,timestamp还是time。所有的时间和日期信息会通过带有timestamp转换器的映射属性保存。

Tip 提示

Hibernate makes this mapping type determination using reflection when the mapping files are processed. This can take time and resources, so if startup performance is important you should consider explicitly defining the type to use.

当访问映射文件的时候Hibernate去使用反射来确定这些映射的类型。这些需要消耗时间和资源,如果启动的时候性能是重要的话,你应该考虑使用明确的定义类型。

Save this mapping file as src/main/resources/org/hibernate/tutorial/domain/Event.hbm.xml.

保存文件问Event.hbm.xml。

At this point, you should have the persistent class and its mapping file in place. It is now time to configure Hibernate. First let's set up HSQLDB to run in "server mode"

在这一节中,你应该已经拥有了一个持久化的类和它的映射文件在一起。是时候配置Hibernate了。首先让我们在“server mode”下建立HSQLDB。

Note 备注

We do this so that the data remains between runs.

我们这样做是为了让数据在两者之间持久运行。

We will utilize the Maven exec plugin to launch the HSQLDB server by running: mvn exec:java -Dexec.mainClass="org.hsqldb.Server" -Dexec.args="-database.0 file:target/data/tutorial" You will see it start up and bind to a TCP/IP socket; this is where our application will connect later. If you want to start with a fresh database during this tutorial, shutdown HSQLDB, delete all files in the target/datadirectory, and start HSQLDB again.

我们将会利用Maven exec插件运行HSQLDB服务器:mvn exec:java -Dexec.mainClass="org.hsqldb.server" -Dexec.args="-database.0file:target/data/tutorial" 。你会看到它启动和绑定到一个TCP/IP套接字中;这是我们的应用不久将会连接到的地方。如果你想要在这个教程中开始一个新的数据库,关闭HSQLDB,删除所有在target/data文件夹下的文件,并且再一次开始HSQLDB。

Hibernate will be connecting to the database on behalf of your application, so it needs to know how to obtain connections. For this tutorial we will be using a standalone connection pool (as opposed to ajavax.sql.DataSource). Hibernate comes with support for two third-party open source JDBC connection pools:c3p0 and proxool. However, we will be using the Hibernate built-in connection pool for this tutorial.

Hibernate将会为你的应用连接到数据库,因此,它需要知道如何获得连接。对于这个教程来说,我们将会使用一个独立的连接池(和javax.sql.DataSource相反的)。Hibernate支持两个第三方的开源JDBC连接池:c3p0和proxool。然而,在这个教程中,我们将会使用Hibernate内置的连接池。

Caution  小心

The built-in Hibernate connection pool is in no way intended for production use. It lacks several features found on any decent connection pool.

内置的Hibernate连接池不能在产品中使用。它缺少一些连接池的几个属性。

For Hibernate's configuration, we can use a simple hibernate.properties file, a more sophisticatedhibernate.cfg.xml file, or even complete programmatic setup. Most users prefer the XML configuration file:

对于Hibernate的配置来说,我们可以使用一个简单的hibernate.properties文件,或者是更复杂一些的hibernate.cfg.xml文件,甚至完全可以用程序来安装。大多数的用户更强相遇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">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.HSQLDialect</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>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>

        <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

Note 备注

Notice that this configuration file specifies a different DTD

注意这个配置文件指定了一个不同的DTD文件。

You configure Hibernate's SessionFactory. SessionFactory is a global factory responsible for a particular database. If you have several databases, for easier startup you should use several <session-factory>configurations in several configuration files.

你配置Hibernate的SessionFactory。对一个特定的数据库来说,SessionFactory是一个全局的工厂仓库。如果你有几个数据库,更简单的开始方式是你在几个配置文件中使用几个<session-factory>配置。

The first four property elements contain the necessary configuration for the JDBC connection. The dialectproperty element specifies the particular SQL variant Hibernate generates.

首先的4个property元素包含了JDBC连接必要的配置。方言的property元素指定了通过不一样的Hibernate生成的一个特定的SQL。

Tip 提示

In most cases, Hibernate is able to properly determine which dialect to use. See Section 27.3, “Dialect resolution” for more information.

在大多数情况下,Hibernate能够做出合适的决定来使用哪种方言。点击连接。

Hibernate's automatic session management for persistence contexts is particularly useful in this context. The hbm2ddl.auto option turns on automatic generation of database schemas directly into the database. This can also be turned off by removing the configuration option, or redirected to a file with the help of theSchemaExport Ant task. Finally, add the mapping file(s) for persistent classes to the configuration.

Hibernate对持久化文本的自动会话管理在这个文本中是非常有用的。打开hbm2ddl.auto选项自动生成的数据库模式-直接加入数据库中。也可以关闭他来移出配置项目或者直接直接Ant 任务SchemaExport的帮助文件。最后,增加映射文件到持久化类的配合中。

Save this file as hibernate.cfg.xml into the src/main/resources directory.

保存这个文件为hibernate.cfg.xml到src/main/resources 文件夹中。

We will now build the tutorial with Maven. You will need to have Maven installed; it is available from theMaven download page. Maven will read the /pom.xml file we created earlier and know how to perform some basic project tasks. First, lets run the compile goal to make sure we can compile everything so far:

现在我们将会使用Maven来构建这个教程。你将会需要安装Maven。从这里可以下载到。Maven将会读取我们之前创建的pom.xml文件并且知道如何来执行一些基本的项目任务。首先,让我们运行compile命令来确保我们可以编译到目前为止的任何事情:

[hibernateTutorial]$ mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building First Hibernate Tutorial
[INFO]    task-segment: [compile]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to /home/steve/projects/sandbox/hibernateTutorial/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Tue Jun 09 12:25:25 CDT 2009
[INFO] Final Memory: 5M/547M
[INFO] ------------------------------------------------------------------------

It is time to load and store some Event objects, but first you have to complete the setup with some infrastructure code. You have to startup Hibernate by building a global org.hibernate.SessionFactory object and storing it somewhere for easy access in application code. A org.hibernate.SessionFactory is used to obtainorg.hibernate.Session instances. A org.hibernate.Session represents a single-threaded unit of work. Theorg.hibernate.SessionFactory is a thread-safe global object that is instantiated once.

是时候加载和存储一些Event对象了,但是首先你不得不完成建立一些基础的代码。你不得不通过构建一个全局的org.hibernate.SessionFactory对象来启动Hibernate ,并且可以在任何地方更容易的用应用代码来存储。org.hibernate.SessionFactory是用来获取org.hibernate.Session初始化的。一个org.hibernate.Session代表一个单线程单元工作。org.hibernate.SessionFactory是一个线程安全的只需要初始化一次的全局对象。

We will create a HibernateUtil helper class that takes care of startup and makes accessing theorg.hibernate.SessionFactory more convenient.

我们将会创建一个HibernateUtil帮助类来负责管理启动和更方便的操作org.hibernate.SessionFactory。

package org.hibernate.tutorial.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory(
			    new StandardServiceRegistryBuilder().build() );
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}

Save this code as src/main/java/org/hibernate/tutorial/util/HibernateUtil.java

将这段代码保存为 src/main/java/org/hibernate/tutorial/util/HibernateUtil.java

This class not only produces the global org.hibernate.SessionFactory reference in its static initializer; it also hides the fact that it uses a static singleton. We might just as well have looked up theorg.hibernate.SessionFactory reference from JNDI in an application server or any other location for that matter.

这个类不仅在静态初始化类中产生全局org.hibernate.SessionFactory的引用,还隐藏它使用一个静态的单例模式的事实。我们也可能在应用服务器中从JNDI中查找org.hibernate.SessionFactory的引用或者其他本地的事件。

If you give the org.hibernate.SessionFactory a name in your configuration, Hibernate will try to bind it to JNDI under that name after it has been built. Another, better option is to use a JMX deployment and let the JMX-capable container instantiate and bind a HibernateService to JNDI. Such advanced options are discussed later.

如果你在你的配置中给org.hibernate.SessionFactory一个名字。在它创建之后,Hibernate将他的名字绑定到JNDI下。另外,更好的选项是使用JMX部署和让JMX能力的容器初始和绑定一个HibernateService到JNDI。更高级的选项在之后讨论。

You now need to configure a logging system. Hibernate uses commons logging and provides two choices: Log4j and JDK 1.4 logging. Most developers prefer Log4j: copy log4j.properties from the Hibernate distribution in the etc/ directory to your src directory, next to hibernate.cfg.xml. If you prefer to have more verbose output than that provided in the example configuration, you can change the settings. By default, only the Hibernate startup message is shown on stdout.

现在你需要配置一个日志系统。Hibernate使用公共日志和提供两个选择:Log4j和JDK1.4日志。大部分的开发者倾向于Log4j:从Hibernate目录下的etc中拷贝log4j.properties文件到你的src目录下,和hibernate.cfg.xml一起。如果你想要修改提供的示例配置中的输出,你可以改变设置。默认的,只有hibernate启动信息显示。

The tutorial infrastructure is complete and you are now ready to do some real work with Hibernate.

这个教程的基础部分已经完成了,你现在可以用Hibernate准备做一些真正的工作了。

We are now ready to start doing some real work with Hibernate. Let's start by writing an EventManager class with a main() method:

我们现在已经准备使用Hibernate来开始做一些真正的工作了。让我们通过写一个EventManager类中的main()方法来开始:

package org.hibernate.tutorial;

import org.hibernate.Session;

import java.util.*;

import org.hibernate.tutorial.domain.Event;
import org.hibernate.tutorial.util.HibernateUtil;

public class EventManager {

    public static void main(String[] args) {
        EventManager mgr = new EventManager();

        if (args[0].equals("store")) {
            mgr.createAndStoreEvent("My Event", new Date());
        }

        HibernateUtil.getSessionFactory().close();
    }

    private void createAndStoreEvent(String title, Date theDate) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);
        session.save(theEvent);

        session.getTransaction().commit();
    }

}

In createAndStoreEvent() we created a new Event object and handed it over to Hibernate. At that point, Hibernate takes care of the SQL and executes an INSERT on the database.

在createAndStoreEvent()方法中我们创建了一个新的Event对象并且持有到Hibernate。在这时,Hibernate管理SQL和执行一个在数据库上的INSERT操作。  

org.hibernate.Session is designed to represent a single unit of work (a single atomic piece of work to be performed). For now we will keep things simple and assume a one-to-one granularity between a Hibernateorg.hibernate.Session and a database transaction. To shield our code from the actual underlying transaction system we use the Hibernate org.hibernate.Transaction API. In this particular case we are using JDBC-based transactional semantics, but it could also run with JTA.

org.hibernate.session被设计为代表一个单一的工作单元(单原子块执行工作)。现在我们将让事情保持简单,假设一个hibernateorg.hibernate.Session和数据库事务之间一对一的粒度。为了保护我们的代码从实际交易系统采用hibernate org.hibernate.transaction API。在这种特殊情况下,我们使用基于JDBC事务语义,但它也可以运行JTA。

What does sessionFactory.getCurrentSession() do? First, you can call it as many times and anywhere you like once you get hold of your org.hibernate.SessionFactory. The getCurrentSession() method always returns the "current" unit of work. Remember that we switched the configuration option for this mechanism to "thread" in our src/main/resources/hibernate.cfg.xml? Due to that setting, the context of a current unit of work is bound to the current Java thread that executes the application.

SessionFactory.getcurrentsession()是用来做什么?首先,你可以调用它多少次,在你喜欢的任何地方,一旦你获取了你的org.hibernate.sessionfactory。getcurrentsession()方法总是返回工作单元的“当前的会话”。还记得我们交换的配置选项,这一机制的“线”在我们src/main/resources / hibernate.cfg.xml?由于这一设置,一个工作单元的当前上下文绑定到当前线程执行java应用程序。

Important 重要

Hibernate offers three methods of current session tracking. The "thread" based method is not intended for production use; it is merely useful for prototyping and tutorials such as this one. Current session tracking is discussed in more detail later on.

Hibernate提供了三种方法的当前会话跟踪。“线程”为基础的方法不是用于生产使用,它只是有用的原型设计和教程,如这一个。当前会话跟踪在以后有更详细的讨论。

org.hibernate.Session begins when the first call to getCurrentSession() is made for the current thread. It is then bound by Hibernate to the current thread. When the transaction ends, either through commit or rollback, Hibernate automatically unbinds the org.hibernate.Session from the thread and closes it for you. If you callgetCurrentSession() again, you get a new org.hibernate.Session and can start a new unit of work.

当前线程首次调用getcurrentsession()方法时,org.hibernate.session被创建(使用连接池除外)然后session被Hibernate将其与当前线程绑定。当事务结束,要么通过提交,要么回滚,Hibernate自动帮助你从当前线程解绑org.hibernate.session并关闭。如果你再次调用getcurrentsession(),你将得到一个新的org.hibernate.session,可以开始一个新的工作单元。

Related to the unit of work scope, should the Hibernate org.hibernate.Session be used to execute one or several database operations? The above example uses one org.hibernate.Session for one operation. However this is pure coincidence; the example is just not complex enough to show any other approach. The scope of a Hibernate org.hibernate.Session is flexible but you should never design your application to use a new Hibernate org.hibernate.Session for every database operation. Even though it is used in the following examples, consider session-per-operation an anti-pattern. A real web application is shown later in the tutorial which will help illustrate this.

对工作范围的单元,要Hibernate的org.hibernate.session被用来执行一个或多个数据库的操作?上面的例子使用一个操作org.hibernate.session。然而,这是纯粹的巧合,这个例子是不复杂的,不足以显示其他方法。一个Hibernate的org.hibernate.session的作用域是灵活的。但是你决不应该设计你的应用为每个数据库操作都创建一个新的 org.hibernate.Session 。即使在下面的例子是这么使用的,也认为每一个操作对应一个session是反面模式。一个真正的Web应用程序将在后面的教程展示,这将有助于说明这个问题。(意思是说现在这个例子只是简单的举例,后面的教程会教大家使用数据库连接池,不会每个数据库操作都创建一个新得session)

See Chapter 13, Transactions and Concurrency for more information about transaction handling and demarcation. The previous example also skipped any error handling and rollback.

请参见第13章,事务和并发性,以了解有关事务处理和划分的更多信息。前面的示例也跳过了任何错误处理和回滚。

To run this, we will make use of the Maven exec plugin to call our class with the necessary classpath setup:mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="store"

运行这个,我们将使用Maven的exec插件调用我们的类,带上必须的classpath路径:mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="store" 

Note 备注

You may need to perform mvn compile first.

你可能需先要执行mvn compile。

You should see Hibernate starting up and, depending on your configuration, lots of log output. Towards the end, the following line will be displayed:

你应该看到Hibernate的启动,根据你的配置,大量的日志输出显示。接近结束时,将显示以下行:

[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)

This is the INSERT executed by Hibernate.

这个插入语句是有Hibernate执行的。

To list stored events an option is added to the main method:

要将获取存储的事件列表方法添加到主方法中:

        if (args[0].equals("store")) {
            mgr.createAndStoreEvent("My Event", new Date());
        }
        else if (args[0].equals("list")) {
            List events = mgr.listEvents();
            for (int i = 0; i < events.size(); i++) {
                Event theEvent = (Event) events.get(i);
                System.out.println(
                        "Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate()
                );
            }
        }

A new listEvents() method is also added:

一个新的listEvents()方法也被添加:

    private List listEvents() {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        List result = session.createQuery("from Event").list();
        session.getTransaction().commit();
        return result;
    }

Here, we are using a Hibernate Query Language (HQL) query to load all existing Event objects from the database. Hibernate will generate the appropriate SQL, send it to the database and populate Event objects with the data. You can create more complex queries with HQL. See Chapter 16, HQL: The Hibernate Query Language for more information.

这里,我们正在试用一个Hibenate Query Language(HQL)查询去加载所有数据库中已经存在的Event对象。Hibernate将会生成合适的SQL,发送它到数据库并装入带有Event对象的数据。你可以创建更复杂的HQL。详见链接获得更多的信息。

Now we can call our new functionality, again using the Maven exec plugin: mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="list"

现在我们可以调用我们的新方法了,再一次使用Maven执行插件:mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="list"


附上我的源码:git@code.csdn.net:xiaozaq/hibernatewebdemo.git



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值