hibernate学习笔记

学会用20%时间和记忆去完成80%的工作!

Hibernate中实体对象的生命周期
l Transient-瞬间状态

当直接使用new创建出对象,例如用User类所衍生出的对象,在还没有使用save()方法之前都是暂存对象,这些对象还没有与数据库发生任何关系,不与数据库的任何记录对应。

l Persistent-持久状态

当对象与数据库中的数据有对应关系,与session实例(尚未关闭)有关联。如将对象用session.save()方法存储,或用session.get()/load()方法从数据库加载数据并封装为对象,此对象进入持久状态。

l Detached-分离状态

当Persistent状态的对象的事务执行commit()之后或一级缓存执行了flush()操作,数据库中的对应数据也会跟着更新。如果你将session实例关闭close(),则Persistent状态的对象会成为Detached状态;而当你使用session的实例的delete()方法删除数据,Persistent状态的对象由于失去了对应的数据,成为Transient状态。

Detached状态的对象可以使用update()方法使之与数据库中的对应数据再度发生关联,此时Detached状态的对象会变为Persistent状态。

简要的Hibernate体系结构的概要图


Hibernate核心接口
l SessionFactory(org.hibernate.SessionFactory)

针对单个数据库映射关系经过编译后的内存镜像,是线程安全的(不可变)。他是生成Sessinon的工厂,本身要用到ConnectionProvider。该对象可以在进程或集群的级别上,为那些事务之间可以重用的数据提供可循的二级缓存。

l Session(org.hibernate.Session)

表示应用程序与持久储存层之间交换操作的一个单线程对象,此对象生存期很短。其隐藏了JDBC连接,也是Transaction的工厂。其会吃用一个针对持久话对象的必选(第一级)缓存,在遍历对象图或跟据持久化标识查找对象时会用到。

l 持久对象及其集合

带有持久化状态的、具有业务功能的单线程对象,此对象生存期很短。这些对象可能是普通的JavaBean/POJO,唯一特殊的是他们正与(仅仅一个)Session相关联,一旦这个Session被关闭,这些对象就会脱离持久化状态,这样就可被应用程序的任何层自由使用(例如作表示层的数据传输对象)。

l 瞬态(Transient)和脱管(Detached)的对象及其集合

l 事务(Transaction(org.hibernate.Transaction))

(可选的)应用程序用来制定原子操作单元范围的对象,它是单线程的,生命周期很短。他通过抽象将用用从底层具体的JDBC、JTA以及CORBA事务隔离开。某些情况下,一个Session之内可能包含多个Transaction对象。尽管是否使用该对象是可选的,但无论是使用底层的API还是使用Transaction对象。事务边界的开启与关闭是必不可少的。

l ConnectionProvider(org.hibernate.connection.ConnectionProvider)

(可选的)申城JDBC连接的工厂(同时也起到连接池的作用)。它通过抽象将应用从底层的Datasource或DriverManager隔离开。仅供开发者扩张/实现用,并不暴露给应用程序使用。

l TransactionFactory(org.hibernate.TransactionFactory)

(可选的)生成Transaction对象实例的工厂。仅供开发者扩展/实现用,并不暴露给应用程序使用。


配置MyEclipse环境使用Hibernate
hibernate3.jar是必要的,而在lib目录中还包括了许多jar文件,您可以在 Hibernate 3.0官方的参考手册 上找到这些jar的相关说明,其中必要的是 antlr、dom4j、CGLIB、asm、Commons Collections、Commons Logging、 EHCache,Hibernate底层还需要Java Transaction API,所以您还需要jta.jar,到这边为止,总共需要以下的jar文件:



Hibernate可以运行于单机之上,也可以运行于Web应用程序之中,如果是运行于单机,则将所有用到的jar文件(包括JDBC驱动程序)设定至 CLASSPATH中,如果是运行于Web应用程序中,则将jar文件置放于WEB-INF/lib中。
如果您还需要额外的Library,再依需求加入,例如JUnit、Proxool等等,接下来可以将etc目录下的log4j.properties复制至Hibernate项目的Classpath下,并修改一下当中的log4j.logger.org.hibernate为error,也就是只在在错误发生时显示必要的信息。

接着设置基本的Hibernate配置文件,可以使用XML或Properties文件,这边先使用XML,文件名预设为 hibernate.cfg.xml:




说明:这边以一个简单的单机程序来示范Hibernate的配置与功能。

准备工作

l MyEclipse配置如前所述

l 建立持久化类

l 数据库的准备工作,在MySQL中新增一个demo数据库,并建立user表格:

CREATE TABLE user( id INT(11) NOT NULL auto_increment  PRIMARY KEY,name VARCHAR(100) NOT NULL default '',age INT);

l 建立持久化类

l 建立持久化类的映射文件

l 编写Java的测试应用程序


建立持久化类

public class User {
    private Integer id;
    private String name;
    private Integer age;
    // 必须要有一个预设的建构方法
    // 以使得Hibernate可以使用Constructor.newInstance()建立对象
    public User() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}

其中id是个特殊的属性,Hibernate会使用它来作为主键识别,您可以定义主键产生的方式,这是在XML映像文件中完成,为了告诉 Hibernate您所定义的User实例如何映射至数据库表格,您撰写一个XML映射文件名是User.hbm.xml,如下所示:

建立持久化类的映射文件User.hbm.xml;


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping
 PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="onlyfun.caterpillar.User" table="user">

        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native"/>
        </id>

        <property name="name" column="name" type="java.lang.String"/>

        <property name="age" column="age" type="java.lang.Integer"/>

    </class>

</hibernate-mapping>


<class>标签的name属性为所映像的对象,而table为所映像的表格;

<id>中 column属性指定了表格字段,而 type属性指定了User实例的中的id的类型,这边type中所设定的是直接指定Java中的对象类型,Hibernate也定义有自己的映射类型,作为Java对象与SQL型态的标准对应型态(因为语言所提供的类型并不一定与数据库的类型对应),这之后会再说明。

<id>中主键的产生方式在这边设定为"native",表示主键的生成方式由Hibernate根据数据库Dialect 的定义来决定,之后还会介绍其它主键的生成方式。


同样的,<property>标签中的column与type都各自指明了表格中字段与对象中属性的对应。


接着必须在Hibernate配置文件hibernate.cfg.xml中指明映射文件的位置,如下加入映射文件位置:

修改Hibernate的配置文件hibernate.cfg.xml;

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

    ....

    <!-- 对象与数据库表格映像文件 -->
    <mapping resource=“com/cstp/User.hbm.xml"/>

    </session-factory>

</hibernate-configuration>


接下来编写一个测试的程序,这个程序直接以Java程序设计人员熟悉的语法方式来操作对象,而实际上也直接完成对数据库的操作,程序将会将一条数据存入表格之中:

public class FirstHibernate {
    public static void main(String[] args) {
        // Configuration 负责管理 Hibernate 配置讯息
        Configuration config = new Configuration().configure();
        // 根据 config 建立 SessionFactory
        // SessionFactory 将用于建立 Session
        SessionFactory sessionFactory = config.buildSessionFactory();

        // 将持久化的对象
        User user = new User();
        user.setName(“hhp”);
        user.setAge(new Integer(30));

        // 开启Session,相当于开启JDBC的Connection
        Session session = sessionFactory.openSession();
        // Transaction表示一组会话操作
        Transaction tx= session.beginTransaction();
        // 将对象映像至数据库表格中储存
        session.save(user);
        tx.commit();
        session.close();
        sessionFactory.close();
 
        System.out.println(“新增记录OK!请先用MySQL观看结果!");
    }
}


持久性保存对象的一般步骤总结
l 打开到数据源的一个会话

Session snSession = factory.openSession();

l 开始一个事务

Transaction tTransaction = snSession.beginTransaction();

l 创建希望持久性保存的对象,并且使用数据填充它们

User user = new User();

user.setName("Michael");

user.setAge(40);

l 保存对象到会话

snSession.save(user);

l 提交修改到数据源并且关闭链接

tTransaction.commit();

snSession.close();


FirstHibernate.java测试程序

如您所看到的,程序中只需要直接操作User对象,并进行Session与Transaction的相关操作,Hibernate就会自动完成对数据库的操作,您看不到任何一行JDBC或SQL的声明产生,编写好以上的各个文件之后,各文件的放置位置如下:



着可以开始运行程序,结果如下:

Hibernate: insert into user (name, age) values (?, ?)
新增记录OK!请先用MySQL观看结果!


执行结果中显示了Hibernate所实际使用的SQL,由于这个程序还没有查询功能,所以要进入MySQL中看看新增的数据,如下:

mysql> select * from user;
+----+-------------+------+
| id    | name         | age  |
+----+-------------+------+
|  1    | caterpillar |   30   |
+----+-------------+------+
1 row in set (0.03 sec)


在 第一个 Hibernate 中介绍如何使用Hibernate在不使用SQL的情况下,以Java中操作对象的习惯来插入数据至数据库中,当然储存数据之后,更重要的是如何将记录读出,Hibernate中也可以让您不写一句SQL,而以Java中操作对象的习惯来查询数据。

Hibernate例子-条件查询

public class SecondHibernate {

    public static void main(String[] args) {
        Configuration config = new Configuration().configure();
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession();

        Criteria criteria = session.createCriteria(User.class);
        // 查询user所有字段
        List users = criteria.list();
        Iterator iterator = users.iterator();
        System.out.println("id \t name/age");
        while(iterator.hasNext()) {
            User user = (User) iterator.next();
            System.out.println(user.getId() +
                                " \t " + user.getName() +
                                "/" + user.getAge());
        }

// 查询user中符合条件的字段
        criteria.add(Expression.eq("name", “hhp"));
        users = criteria.list();
        iterator = users.iterator();
        System.out.println("id \t name/age");
        while(iterator.hasNext()) {
            User user = (User) iterator.next();
            System.out.println(user.getId() +
                " \t " + user.getName() +
                "/" + user.getAge());
        }
 
        session.close();
        sessionFactory.close();
    }
}

Criteria对SQL进行封装,对于不甚了解SQL的开发人员来说,使用Criteria也可以轻易的进行各种数据的检索

您也可以使用 Expression设定查询条件,并将之加入Criteria中对查询结果作限制,Expression.eq()表示设定符合条件的查询,

例如 Expression.eq("name", “hhp")表示设定查询条件为"name"字段中为"caterpillar"的数据。

先来看一下执行结果:

Hibernate: select this_.id as id0_, this_.name as name0_0_, this_.age as age0_0_ from user this_
id      name/age
1      hhp/30
3      tiantian/5
2     zhangy/26

Hibernate: select this_.id as id0_, this_.name as name0_0_, this_.age as age0_0_ from user this_ where this_.name=?
id      name/age
1       hhp/30


Criteria是对象导向式的查询方式,让不了解SQL的开发人员也可以轻易进行各项查询,但Criteria的API目前还不是很完善,而 Hibernate鼓励的查询方式,是透过HQL(Hibernate Query Language)来进行,直接来看个实例:

Hibernate例子-HQL查询

public class SecondHibernate {

    public static void main(String[] args) {
        Configuration config = new Configuration().configure();
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession();
 
        // 使用HQL建立查询
        Query query = session.createQuery("from User");
        List users = query.list();
        Iterator iterator = users.iterator();
        System.out.println("id \t name/age");
        while(iterator.hasNext()) {
            User user = (User) iterator.next();
            System.out.println(user.getId() +
                    " \t " + user.getName() +
                    "/" + user.getAge());
        }
 
        System.out.println();
// 使用HQL建立查询
        query = session.createQuery("from User user where user.name like ?");
        // 设定查询参数
        query.setParameter(0, “hhp");
        users = query.list();
        iterator = users.iterator();
        System.out.println("id \t name/age");
        while(iterator.hasNext()) {
            User user = (User) iterator.next();
            System.out.println(user.getId() +
                                " \t " + user.getName() +
                                "/" + user.getAge());
        }
 
        session.close();
        sessionFactory.close();
    }
}

通过Query接口,您可以先设定查询参数,之后通过setXXX()等方法,将指定的参数值填入,而不用每次都编写完整的HQL,Query的 setParameter()方法第一个参数是指定 ? 出现的位置,从 0 开始,第二个参数则是设定查询条件。


Hibernate.cfg.xml配置文件详解
Hibernate可以使用XML文件或properties文件来配置SessionFactory,预设的配置文件为 hibernate.cfg.xml或hibernate.properties,XML提供较好的结构与配置方式,Hibernate建议使用XML文件进行配置。

上节课所示范的为使用XML文件的方式,一个XML文件的例子如下:

<hibernate-configuration>

    <session-factory>
        <!-- 显示实际操作数据库时的SQL -->
        <property name="show_sql">true</property>
        <!-- SQL方言,这边设定的是MySQL -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- JDBC驱动程序 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
         <!-- JDBC URL -->
        <property name="connection.url">jdbc:mysql://localhost/demo</property>
        <!-- 数据库使用者 -->
        <property name="connection.username">hhp</property>
        <!-- 数据库密码 -->
        <property name="connection.password">123456</property>
        <!-- 对象与数据库表格映像文件 -->
        <mapping resource=“com/cstp/User.hbm.xml"/>
    </session-factory>


</hibernate-configuration>


使用XML文件进行配置时,可以在当中指定对象与数据库表格的映像文件位置,XML配置文件的位置必须在Classpath下,使用下面的方式来读入 XML文件以配置Hibernate:

Configuration config = new Configuration().configure();


Configuration的实例管理Hibernate的配置信息,通常用于建立SessionFactory,例如:

SessionFactory sessionFactory = config.buildSessionFactory();


SessionFactory一旦建立,就被赋予当时Configuration的配置信息,之后您改变Configuration并不会影响已建立的 SessionFactory实例,如果对Configuration改动后,则要建立一个新的SessionFactory实例,新的实例中会包括新的配置信息。

SessionFactory中包括了数据库配置及映射关系,它的建立相当复杂,所以使用时需考虑到重用已建立的SessionFactory实例, SessionFactory是被设计为「线程安全的」(Thread-safe)。


预设的XML配置文件名称是hibernate.cfg.xml,您也可以自行指定文件,即采用程序配置方式例如:

Configuration config = new Configuration().configure("db.cfg.xml");

SessionFactory sf = config.buildSessionFactory();


除了使用XML文件进行配置,您也可以使用属性文件进行配置,文件名称是hibernate.properties,一个例子如下:

hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.connection.url = jdbc:mysql://localhost/demo
hibernate.connection.username = hhp
hibernate.connection.password = 123456


hibernate.properties的位置必须在Classpath下,由于properties文件中不包括映射文件的名称,为了要取得对象至数据库表格的映射文件,您必须在程序中如下加载:

Configuration cfg = new Configuration()
    .addClass(com.cstp.User.class)
    .addClass(com.cstp.Item.class);

第一个addClass()加入位于Classpath根目录下的User.hbm.xml,第二个addClass()加入Item类别的映射文件,该文件必须位于与User类别同一个目录,也就是com/cstp/Item.hbm.xml。

注意:在Hibernate下载文件中的etc目录下,有hibernate.cfg.xml与hibernate.properties可供设定参考




Hibernate.cfg.xml配置文件——数据库连结配置
Hibernate的配置文件中有一部份是在设定数据库连结,例如使用XML文件进行配置:

数据库连接池配置

<hibernate-configuration>

 <session-factory>

 <!-- 显示实际操作数据库时的SQL -->
 <property name=“show_sql”>true</property>
 <!-- SQL方言,这边设定的是MySQL -->
 <property name=“dialect”>org.hibernate.dialect.MySQLDialect</property>
 <!-- JDBC驱动程序 -->
 <property name=“connection.driver_class”>com.mysql.jdbc.Driver</property>
 <!-- JDBC URL -->
 <property name=“connection.url”>jdbc:mysql://localhost/demo</property>
 <!-- 数据库使用者 -->
 <property name=“connection.username”>hhp</property>
 <!-- 数据库密码 -->
 <property name=“connection.password”>123456</property>

 <!设置数据库的连接池属性>
 <!-- Hibernate 预设的Connection pool -->
 <property name=“connection.pool_size”>2</property>

 <!-- 对象与数据库表格映射文件 -->
 <mapping resource=“com/cstp/User.hbm.xml"/>

 </session-factory>

</hibernate-configuration>


其中设定的connection.pool_size是Hibernate预设的连接池设定,通常只用于开发阶段测试之用。如果使用properties 文件的话则如下:

hibernate.properties


hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.connection.url = jdbc:mysql://localhost/demo
hibernate.connection.username = hhp
hibernate.connection.password = 123456
hibernate.connection.pool_size = 2


Hibernate在数据库连接池的使用上是可选的,您可以使用C3P0连接池,例如XML的配置方式如下:

<hibernate-configuration>

    <session-factory>

        <!-- 显示实际操作数据库时的SQL -->
        <property name="show_sql">true</property>
        <!-- SQL方言,这边设定的是MySQL -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- JDBC驱动程序 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- JDBC URL -->
        <property name="connection.url">jdbc:mysql://localhost/demo</property>
        <!-- 数据库使用者 -->
        <property name="connection.username">hhp</property>
        <!-- 数据库密码 -->
        <property name="connection.password">123456</property>

        <!-- C3P0 连接池设定 -->
        <property name="c3p0.min_size">5</property>
        <property name="c3p0.max_size">20</property>
        <property name="c3p0.timeout">1800</property>
        <property name="c3p0.max_statements">50</property>
 
        <!-- 对象与数据库表格映像文件 -->
        <mapping resource=“com/cstp/User.hbm.xml"/>

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


记得您的Classpath中必须包括c3p0-*.jar,属性文件hibernate.properties的配置范例如下:

hibernate.properties


hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.connection.url = jdbc:mysql://localhost/demo
hibernate.connection.username = hhp
hibernate.connection.password = 123456
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50


您也可以使用Proxool或DBCP连接池,只要在配置文件中配置hibernate.proxool.*或hibernate.dbcp.*等相关选项,这可以在hibernate的etc目录中找hibernate.properties中的配置例子来参考,当然要记得在Classpath中加入相关的jar文件。


如果您使用Tomcat的话,您也可以通过它提供的DBCP连接池来取得连接,您可以先参考 使用 DBCP 的文章来设定Tomcat的DBCP连接池。


设定好容器提供的DBCP连接池之后,您只要在配置文件中加入connection.datasource属性,例如在 hibernate.cfg.xml中加入:

<property name="connection.datasource">java:comp/env/jdbc/dbname</property>


如果是在hibernate.properties中的话,则加入:

hibernate.connection.datasource = java:comp/env/jdbc/dbname

Session管理和缓存
数据库每一次的查询都是一次不小的开销,例如连结的开启、执行查询指令,当数据库与应用服务器不在同一个服务器上时,还必须有远程调用、Socket的建立等开销,在Hibernate这样的ORM框架中,还有数据的封装等开销必须考虑进去


缓存(Cache)是数据库在内存中的临时容器,从数据库中读取的数据在缓存中会有一份临时拷贝,当您查询某个数据时,会先在缓存中寻找是否有相对应的拷贝,如果有的话就直接返回数据,而无需连接数据库进行查询,只有在缓存中找不到数据时,才从数据库中查询数据,藉由缓存,可以提升应用程序读取数据时的效能。(需要注意在一些状态中,缓存中的数据可能与数据库中的不一致!)


对于Hibernate这样的ORM框架来说,缓存的机制更为重要,在Hibernate中缓存分作两个层级:Session level与SessionFactory level(又称Second level缓存)。

Session Level缓存
这边先介绍Session level的缓存,在Hibernate中Session level缓存会在使用主键加载数据或是延迟初始(Lazy Initialization) 时作用,Session level的缓存随着Session建立时建立,而Session销毁时销毁。

Session会维护一个Map容器,并保留与目前Session发生关系的资料,当您透过主键来加载数据时,Session会先依据所要加载的类别与所给定的主键,看看Map中是否已有数据,如果有的话就返回,若没有就对数据库进行查询,并在加载数据后在Map中维护。


可以通过==来比较两个名称是否参考至同一个对象,以检验这个事实:

Session session = sessionFactory.openSession();
User user1 = (User) session.load(User.class, new Integer(1));
User user2 = (User) session.load(User.class, new Integer(1));
System.out.println(user1 == user2);
session.close();

第二次查询数据时,由于在缓存中找到数据对象,于是直接返回,这与第一次查询到的数据对象是同一个实例,所以会显示true的结果。

可以通过evict()将某个对象从缓存中移去,例如:


Session session = sessionFactory.openSession();


User user1 = (User) session.load(User.class, new Integer(1));
session.evict(user1);
User user2 = (User) session.load(User.class, new Integer(1));


System.out.println(user1 == user2);
session.close();

由于user1所参考的对象被从缓存中移去了,在下一次查询时,Session在Map容器中找不到对应的数据,于是重新查询数据库并再封装一个对象,所以user1与user2参考的是不同的对象,结果会显示false。


也可以使用clear()清除缓存中的所有对象,例如:


Session session = sessionFactory.openSession();


User user1 = (User) session.load(User.class, new Integer(1));
session.clear();
User user2 = (User) session.load(User.class, new Integer(1));
System.out.println(user1 == user2);
session.close();


同样的道理,这次也会显示false。


Session level的缓存随着Session建立与销毁,看看下面这个程序片段:

Session session1 = sessionFactory.openSession();


User user1 = (User) session1.load(User.class, new new Integer(1));
session1.close();

Session session2 = sessionFactory.openSession();
User user2 = (User)session2.load(User.class, new Integer(1));
session2.close();

System.out.println(user1 == user2);


第一个Session在关闭后,缓存也关闭了,在第二个Session的查询中并无法用到第一个Session的缓存,两个Session阶段所查询到的并不是同一个对象,结果会显示false。


在加载大量数据时,Session level 缓存的内容会太多,记得要自行执行clear()清除缓存或是用evict()移去不使用对象,以释放缓存所占据的资源。

Session在使用save()储存对象时,会将要储存的对象纳入Session level缓存管理,在进行大量数据储存时,缓存中的实例大量增加,最后会导致OutOfMemoryError,可以每隔一段时间使用Session的 flush()强制储存对象,并使用clear()清除缓存,

例如:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

while(....) { // 大量加载对象时的循环示意
    ....
    session.save(someObject);
    if(count % 100 == 0) { // 每100条记录
        session.flush(); // 送入数据库
        session.clear(); // 清除缓存
    }
}

tx.commit();
session.close();


在SQL Server、Oracle等数据库中,可以在Hibernate设定文件中设定属性hibernate.jdbc.batch_size来控制每多少条数据就送至数据库,例如:

....
<hibernate-configuration>
    <session-factory>
        ....
        <property name="hibernate.jdbc.batch_size">100</property>
        ....
    </session-factory>
<hibernate-configuration>

注意:在MySQL中则不支持这个功能


事务管理简单说明
事务是一组原子(Atomic)操作(一组SQL执行)的工作单元,这个工作单元中的所有原子操作在进行期间,与其它事务隔离,免于数据来源的交相更新而发生混乱,事务中的所有原子操作,要么全部执行成功,要么全部失败(即使只有一个失败,所有的原子操作也要全部撤消)。

JDBC中的事务管理方式

在JDBC中,可以用Connection来管理事务,可以将Connection的AutoCommit设定为false,在下达一连串的SQL语句后,自行调用Connection的commit()来送出变更,如果中间发生错误,则撤消所有的执行,例如:

JDBC中的事务管理方式举例


try {
    .....
    connection.setAutoCommit(false);
    .....

    // 一连串SQL操作

    connection.commit();
} catch(Exception) {
    // 发生错误,撤消所有变更
    connection.rollback();
}

Hibernate本身没有事务管理功能,它依赖于JDBC或JTA的事务管理功能,预设是使用JDBC事务管理,可以在配置文件中加上 hibernate.transaction.factory_class属性来指定Transaction的工厂类别,例如:

<hibernate-configuration>


    <session-factory>
        ....
        <!-- 设定事务管理的工厂类 -->
        <property name="hibernate.transaction.factory_class">
            org.hibernate.transaction.JDBCTransactionFactory
        </property>
 
        <!-- 对象与数据库表格映像文件 -->
        <mapping resource=“com/cstp/User.hbm.xml"/>

    </session-factory>

</hibernate-configuration>


基于JDBC的事务管理是最简单的方式,事实上,Hibernate基于JDBC的事务管理只是对JDBC作了个简单的封装:


try {
    session = sessionFactory.openSession();  
    Transaction tx = session.beginTransaction();
    ....

    tx.commit();  // 必须commit才会更新数据库
} catch(HibernateException e) {
    tx.rollback();
}

在一开始的openSession()取得Session时,JDBC的Connection实例之AutoCommit就被设定为false,在 beginTransaction()时,会再度检查Connection实例的AutoCommit为false,在操作过程中,最后要commit (),否则的话对数据库的操作不会有作用,如果操作过程中因发生例外,则最后commit()不会被执行,之前的操作取消,执行rollback()可撤消之前的操作,一个实际的程序如下所示:

public class FirstHibernate {
    public static void main(String[] args) {
        Configuration config = new Configuration().configure();
        SessionFactory sessionFactory = config.buildSessionFactory();

        User user = new User();
        user.setName(“zhangy");
        user.setAge(new Integer(24));

        Session session = null;
        Transaction tx= null;
 
        try {
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            session.save(user);
            tx.commit();
        }
        catch(Exception e) {
            e.printStackTrace();
            if(tx != null) {
                try {
                    tx.rollback();
                }
                catch(HibernateException ee) {
                    ee.printStackTrace();
                }
            }
        }

finally {
            if(session != null) {
                try {
                    session.close();
                }
                catch(HibernateException e) {
                    e.printStackTrace();
                }
            }
        }
 
        sessionFactory.close();
    }
}

注意: 要使用MySQL中的事务处理,必须建立事务表类型的表格,例如InnoDB的表格:


CREATE TABLE user (
.....
....
) TYPE = InnoDB;


Hibernate映射文件
Hibernate 中将对象与数据库表格映射关系连接起来的是映射文件,通常以*.hbm.xml作为文件名称,映射文件可以手工编写,或是通过工具程序从数据库表格自动生成,或是通过工具程序从Java类别自动生成。

 <hibernate-mapping>


    <!--类别名称与表格名称映像-->
    <class name=“com.cstp.User" table="user">


        <!--id与主键映射-->
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native"/>
        </id>


        <!--类别属性与表格字段的映像-->
        <property name="name" column="name" type="java.lang.String"/>
        <property name="age" column="age" type="java.lang.Integer"/>


    </class>
</hibernate-mapping>




映射文件中主要包括三个部份:

类别名称与表格名称的映射、

id属性与主键的映射、

类别属性与表格字段的映射。

这份映像文件对应于以下的类别与表格:

User.java

public class User {
    private Integer id;
    private String name;
    private Integer age;
 
    // 必须要有一个预设的建构方法
    // 以使得Hibernate可以使用Constructor.newInstance()建立对象
    public User() {}

    public Integer getId() {
        return id;
    }


        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
 
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

在<id>的设定上,name设定类别上的属性名,而column对应至表格字段,在type上可以设定Java类别的数据类型,但由于 Java的数据类型与数据库的数据类型并不是一对一对应的,为此Hibernate提供它自己的数据类型,作为Java数据类型与数据库数据类型的连接类型,下面的表格列出类型之间的对应:

Java的数据类型与Hibernate的数据类型对应问题






Hibernate的主键(标识符)生成方法
l Hibernate自动生成主键

l Generator生成策略说明

l Hibernate复合主键

*.hbm.xml中需要说明主键生成方式

<generator>设定主键的生成方式,

可以设定“native”表示由Hibernate自动根据Dialect选择采用 identity、hilo、sequence等作为主键生成方式,

也可以考虑采用uuid由Hibernate根据128位UUID算法(128- bit UUID algorithm)生成16进位制数值,并编码为32位长度的字符串,

还有其它的主键生成方式,可以参考官方手册的 Generator 说明

数据库提供的主键生成机制

identity-采用数据库提供的主键生成机制

如DB2,SQL Server,MySQL,返回的是long,short,或int类型

sequence-采用数据库提供的sequence生成机制

如Oracle的sequence

外部程序提供的主键生成机制

increment-递增

hilo-高低位算法实现的

seqhilo

uuid.hex-用一个128位的UUID算法生成字符串类型的主键,UUID被编码为一个32位16进制数字的字符串

uuid.string-用一个128位的UUID算法生成字符串类型的主键,UUID被编码为一个32位16个字符长的任意ASCII字符组成的字符串

其它主键生成机制

native-根据底层数据库的能力选择identity,sequence,hilo任意一种

assigned-由程序在save()之前自己分配主键

foreign-外部引用,使用另外一个相关联的对象的标识符,和<one-to-one>一起联合使用


Generator生成器模板

<id

name = "propertyName"

type = "typeName"

column = "columnName"

unsaved-value="any|none|null|id_value"

access = "field"|property|ClassName">


<generator class = "generateClass">

</generator>

</id>


Generator生成器-Hilo举例

<id name = "id" type = "long" column = "uid" unsaved-value="0">

<generator class = "net.sf.hibernate.id.TableHiLoGenerator">

<param name="table"> uid_table </param>

<param name="column"> next_hi_value_column </param>

</generator>

</id>


<property

name=“propertyName”

column=“columnName”

type=“typeName”

>



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/welcomejzh/archive/2008/12/29/3638976.aspx

你可能感兴趣的:(Hibernate)