Hibernate的核心接口与类
在实际的Hibernate应用中,使用到的Hibernate核心接口与类并不多,熟悉和掌握这些接口和类的基本用法之后,即可开发Hibernate。如果要更深入地使用Hibernate,还需要学习Hibernate的延迟加载和缓存处理等高级的内容。在Hibernate应用中常用的Hibernate接口与类如图2 1所示。
2.1 Configuration类
Configuration类的主要作用是解析Hibernate的配置文件和持久化映射文件中的信息,然后通过Configuration对象的buildSessionFactory()方法创建SessionFactory对象,所以Configuration对象一般只有在获取SessionFactory对象时需要使用。当获取了SessionFactory对象之后,由于配置信息已经由Hibernate 维护并绑定在返回的SessionFactory中,因此该Configuration已无使用价值。
2.1.1 Hibernate配置文件
为了能够在底层上适应不同的数据库及应用开发环境,Hibernate采用大量的选项。这些选项通过XML格式或者properties格式的文件配置,也可以通过编码方式配置。
如果Hibernate配置文件为XML格式,文件名一般默认为"hibernate.cfg.xml";如果为properties格式,则默认为"hibernate.properties"。
(1)使用hibernate.cfg.xml格式
这是推荐使用的一种配置Hibernate的方法,因为XML格式的配置文件具有结构性强、易读和配置灵活等特点。并且用其可以直接配置映射文件,而使用properties格式则不可。
使用hibernate.cfg.xml作为配置文件,需要将其保存到当前项目或者应用的CLASSPATH路径下。这样当Configuration对象调用configure()方法加载Hibernate配置选项时会自动加载该文件,其内容可以参考SRC 1 3文件。
如果Hibernate的配置文件没有使用默认文件名或者保存在CLASSPATH路径下,则需要在Configuration对象的configure()方法中指定文件路径与文件名,示例代码如下:
- File file = new File("c:\\ workspace\\chapter02_first\\src\\example.xml");
- Configuration config = new Configuration();
- config.configure(file);
- SessionFactory sessionFactory = config.buildSessionFactory();
(2)使用hibernate.properties格式
hibernate.properties配置文件,该文件需要放置在当前项目的CLASSPATH路径中,其内容如下:
- SRC 2 1 hibernate.properties
- hibernate.dialect=org.hibernate.dialect.Oracle9iDialect
- hibernate.connection.driver_class= oracle.jdbc.driver.OracleDriver
- hibernate.connection.url= jdbc:oracle:thin:@localhost:1521:ora9
- hibernate.connection.username=scott
- hibernate.connection.password=tiger
- hibernate.current_session_context_class=thread
- hibernate.show_sql=true
- hibernate.format_sql=true
对比SRC 1 3 Hibernate.cfg.xml和SRC 2 1 hibernate.properties的内容会发现配置文件的格式不同,但是所配置的内容相同,即均配置Hibernate连接数据库所需要的参数及运行的基本参数等。
由于hibernate.properties文件中没有配置映射文件的名称,所以要通过编写代码的方式加载映射文件,然后才能创建SessionFactory对象,示例代码如下:
- Configuration config = new Configuration();
- config.addResource("com/v512/examples/Guestbook.hbm.xml");
- SessionFactory sessionFactory = config.buildSessionFactory();
其中的Guestbook.hbm.xml文件需要保存在当前项目或者应用的CLASSPATH的路径中。
Hibernate还可以通过指定被映射的持久化类,使其自动查找并加载映射文件,示例代码如下:
- Configuration config = new Configuration();
- config.addClass(com.v512.examples.Guestbook.class);
- SessionFactory sessionFactory = config.buildSessionFactory();
Hibernate配置文件中有多个选项,Hibernate为大多数选项设置了一个合理的默认值,所以只需要修改需要定制的一部分选项即可。
2.1.2 在应用程序中设置新的属性值
使用XML或properties格式的配置文件,都可以在获得Configuration对象后通过编写代码的方式来设置新的属性值或加载另外的映射文件,示例代码如下:
- Configuration config = new Configuration();
- config.configure();
- config.setProperty(Environment.FORMAT_SQL, "true");
- SessionFactory sessionFactory = config.buildSessionFactory();
所有的属性设置在Hibernate中均对应Environment类中的一个静态成员,如format_sql对应Enviromnent.FORMAT_SQL。
2.1.3 Hibernate的核心配置信息
表2 1所示为hibernate.cfg.xml文件中可配置的核心信息。
表2 1 hibernate.cfg.xml文件中的核心配置信息
属性名 | 用途 | 数值 |
hibernate.connection.driver_class | 设置数据库的驱动类 | 驱动类名 |
hibernate.connection.url | 设置连接数据库的URL | URL |
hibernate.connection.username | 设置连接数据库的用户名 | 用户名 |
hibernate.connection.password | 设置连接数据库的密码 | 密码 |
hibernate.connection.pool_size | 设置连接池的最大容量 | 一个整数 |
hibernate.connection.datasource | 设置数据源的JNDI名字 | JNDI名 |
hibernate.dialect | 针对不同的数据库提供的方言类,允许Hibernate针对特定的数据库生成优化的SQL语句 | 方言类名 |
hibernate.show_sql | 是否输出Hibernate操作数据库使用的SQL语句 | true或者false(默认) |
hibernate.format_sql | 是否格式化输出的SQL语句 | true或者false(默认) |
hibernate.connection.isolation | 设置JDBC事务隔离级别,不是所有的数据库都支持所有的隔离级别 | 取值为1(默认)、2、3或者4, |
hibernate.connection.auotocommit | 设置是否启用数据库事务的自动提交 | true或者false(默认) |
hibernate.max_fetch_depth | 为单向关联的一对一和多对一的外连接抓取(outer join fetch)设置最大深度,数值为0将关闭默认的外连接抓取 | 建议数值为0~3 |
hibernate.default_batch_fetch_size | 设置关联的批量抓取数量 | 建议取值为4、8或16 |
hibernate.default_entity_mode | 指定默认的持久化实体表现形式 | dynamic-map、pojo(默认)或dom4j, |
续表
属性名 | 用途 | 数值 |
hibernate.default_entity_mode | 指定默认的持久化实体表现形式 | dynamic-map、pojo(默认)或dom4j, |
hibernate.order_updates | 强制Hibernate按照被更新数据的主键,为SQL更新排序,可以减少在高并发系统中事务的死锁几率 | true或者false(默认) |
hibernate.generate_statistics | 是否激活收集性能调节的统计数据 | true或者false(默认) |
hibernate.use_sql_comments | 是否生成有助于调试的注释信息 | true或者false,(默认) |
在MS SQLServer及Oracle等数据库中可以在Hibernate配置文件中设置属性hibernate.jdbc.batch_size来控制达到多少数据后送至数据库处理。如果在插入或者删除大量记录时使用这个属性,可以提高系统的性能。具体设置参考下面的代码:
- <property name="hibernate.jdbc.batch_size">100</property>
MySQL数据库不支持这个功能。
2.1.4 数据库方言类
Hibernate可以连接不同的数据库,但是需要使用不同的数据库方言类。这是因为多数关系数据库都支持标准的SQL,均有各自的SQL方言,hibernate.dialect属性用于指定被访问数据库使用的方言类(DB Dialect Class)。当Hibernate生成SQL查询语句,或者使用native作为标识符属性生成策略时都会参考数据库的方言类。表2 2所示不同数据库对应的方言类。
表2 2 不同数据库对应的方言类
数据库 | 方言类 |
DB2 | org.hibernate.dialect.DB2Dialect |
HypersonicSQL | org.hibernate.dialect.HSQLDialect |
Informix | org.hibernate.dialect.InformixDialect |
Interbase | org.hibernate.dialect.InterbaseDialect |
Pointbase | org.hibernate.dialect.PointbaseDialect |
PostgreSQL | org.hibernate.dialect.PostgreSQLDialect |
Microsoft SQL Server | org.hibernate.dialect.SQLServerDialect |
MySQL | org.hibernate.dialect.MySQLDialect |
Oracle 9i/10g/11g | org.hibernate.dialect.Oracle9iDialect |
Oracle 9i/10g/11g | org.hibernate.dialect.Oracle9iDialect |
FrontBase | org.hibernate.dialect.FrontbaseDialect |
SAP DB | org.hibernate.dialect.SAPDBDialect |
Sybase | org.hibernate.dialect.SybaseDialect |
Sybase Anywhere | org.hibernate.dialect.SybaseAnywhereDialect |
2.2 SessionFactory接口
SessionFactory 接口使用了工厂设计模式。通过SessionFactory对象可以获取Session对象。SessionFactory对象不是轻量级,Hibernate设计者的意图是让它能在整个应用中共享使用,即如果只使用一个数据库,则只需要使用一个SessionFactory对象;如果同时操作多个数据库,为每个数据库都生成一个SessionFactory对象。SessionFactory对象在Hibernate中还作为一级缓存(Cache),缓存了Hibernate自动生成的SQL语句和一些其他映射数据,同时还缓存了一些将来有可能重复使用的持久化对象。生成SessionFactory对象的示例代码如下所示。
Configuration对象会根据当前的配置信息创建SessionFactory对象,创建完成后该对象即被赋予特定的配置信息。也就是说,创建SessionFactory对象之后,Configuration对象的任何变化都不会影响到已经创建的该对象。
- Configuration config = new Configuration();
- config.configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
2.3 Session接口
Session接口是Hibernate中的核心接口,它不是Java Web应用中的HttpSession接口,虽然我们都可以将其翻译为"会话"。本书中除非特别说明,否则均指Hibernate中的Session对象。
Session对象是Hibernate技术的核心,持久化化对象的生命周期、事务的管理和持久化对象的查询、更新和删除都是通过Session对象来完成的。Hibernate在操作数据库之前必须先取得Session对象,相当于JDBC在操作数据库之前必须先取得Connection对象一样。Session对象不是线程安全的(Thread Safe),一个Session对象最好只由一个单一线程来使用。同时该对象的生命周期要比SessionFactory要短,一个应用系统中可以自始至终只使用一个SessionFactory对象,其生命通常在完成数据库的一个短暂的系列操作之后结束。Session对象通过SessionFactory对象的getCurrentSession()或者openSession()方法获取,示例代码如下:
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
获取Session对象后,Hibernate内部并不会获取操作数据库的java.sql.Connection对象,而是等待Session对象真正需要对数据库进行CRUD等操作时,才会从数据库连接池中获取java.sql.Connection对象。而关闭Session对象时,则是将java.sql.Connection对象返回到连接池中,而不是直接关闭java.sql.Connection对象。
SessionFactory对象是线程安全的,允许多个线程同时存取该对象而不存在数据共享冲突的问题。然而Session对象不是线程安全的,如果试图让多个线程共享一个Session对象,将会发生数据共享混乱的问题。在Hibernate 3.1版本之后,可以通过在hibernate.cfg.xml文件中配置以下内容:
- <property name="current_session_context_class">thread</property>
配置后表明Hibernate使用ThreadLocal对象来管理Session对象,ThreadLocal对象应用了Thread-Specific Storage设计模式。这种模式可以有效隔离线程所使用的数据,所以避开了Session对象在多线程情况下的数据共享问题。使用这个配置信息之后,Session对象只能通过SessionFactory对象的getCurrentSession()方法获取。
2.3.1 save()方法
通过Session对象可以实现对数据库中的数据进行CRUD操作,save()方法是用来保存持久化对象,进而在数据库中新增一条数据的方法。使用该方法的示例代码如下:
- Guestbook gb = new Guestbook();
- gb.setName("刘伟");
- gb.setPhone("0108262285");
- gb.setEmail("liuwei8809@163.com");
- gb.setTitle("大家好");
- gb.setContent("欢迎大家学习Hibernate技术。");
- gb.setCreatedTime(new Date());
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- session.save(gb);
- tx.commit();
执行save()方法之后不会立即操作数据库保存数据,而是在Transaction对象的commit()方法执行之后才会保存数据。
2.3.2 get()方法
可以通过Session对象的get()方法获取数据库中的一条数据,使用该方法的示例代码如下:
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Guestbook gb= (Guestbook) session.get(Guestbook.class,
- new Integer(1));
- tx.commit();
get()方法的第1个参数是持久化对象的类型,第2个参数是要查找的持久化对象的标识符属性值。如果Hibernate在数据库中找到这个标识符属性值所对应的一条数据,会把这条数据封装成持久化对象后返回。如果get()方法未能发现符合要求的数据,则会返回null。
运行上面的代码后,Hibernate输出的操作数据库的SQL语句如下:
- select
- guestbook0_.ID as ID0_0_,
- guestbook0_.NAME as NAME0_0_,
- guestbook0_.PHONE as PHONE0_0_,
- guestbook0_.EMAIL as EMAIL0_0_,
- guestbook0_.TITLE as TITLE0_0_,
- guestbook0_.CONTENT as CONTENT0_0_,
- guestbook0_.CREATED_TIME as CREATE7_0_0_
- from
- GUESTBOOK guestbook0_
- where
- guestbook0_.ID=?
2.3.3 load()方法
可以通过Session对象的load()方法获取数据库中的一条数据,示例代码如下:
load()与get()方法都可以根据标识符属性值查询获取一个持久化对象,但是在未找到符合条件的持久化对象时,load()方法抛出违例;get()方法返回null。此处,get()方法先从Hibernate一级缓存中查询符合条件的对象,找不到则直接从数据库中查找记录;而load()方法则先从Hibernate的一级缓存中查找符合条件的对象,找不到还会在Hibernate的二级缓存中查找对象,仍未找到才会查找数据库。
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Guestbook gb = (Guestbook) session.load(Guestbook.class,
- new Integer(1));
- tx.commit();
2.3.4 update()方法
Session对象对脱管状态 的对象通过调用update()方法重新完成持久化,更新数据库中对应的数据,示例代码如下:
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Guestbook gb = (Guestbook) session.get(Guestbook.class,
- new Integer(1));
- tx.commit();
- gb.setName("张利国");
- session = sessionFactory.getCurrentSession();
- tx= session.beginTransaction();
- session.update(gb);
- tx.commit();
运行上面的代码后Hibernate输出的操作数据库的SQL语句如下:
- select
- guestbook0_.ID as ID0_0_,
- guestbook0_.NAME as NAME0_0_,
- guestbook0_.PHONE as PHONE0_0_,
- guestbook0_.EMAIL as EMAIL0_0_,
- guestbook0_.TITLE as TITLE0_0_,
- guestbook0_.CONTENT as CONTENT0_0_,
- guestbook0_.CREATED_TIME as CREATE7_0_0_
- from
- GUESTBOOK guestbook0_
- where
- guestbook0_.ID=?
- update
- GUESTBOOK
- set
- NAME=?,
- PHONE=?,
- EMAIL=?,
- TITLE=?,
- CONTENT=?,
- CREATED_TIME=?
- where
- ID=?
2.3.5 delete()方法
Session对象使用delete()方法删除数据库表中的一条记录,首先要通过该对象的get()或者load()方法获取要删除记录对应的持久化对象,然后通过delete()方法删除,示例代码如下:
运行上面的代码后Hibernate输出的操作数据库的SQL语句如下:
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Guestbook gb = (Guestbook) session.get(Guestbook.class,
- new Integer(1));
- session.delete(gb);
- tx.commit();
- select
- guestbook0_.ID as ID0_0_,
- guestbook0_.NAME as NAME0_0_,
- guestbook0_.PHONE as PHONE0_0_,
- guestbook0_.EMAIL as EMAIL0_0_,
- guestbook0_.TITLE as TITLE0_0_,
- guestbook0_.CONTENT as CONTENT0_0_,
- guestbook0_.CREATED_TIME as CREATE7_0_0_
- from
- GUESTBOOK guestbook0_
- where
- guestbook0_.ID=?
- delete
- from
- GUESTBOOK
- where
- ID=?
批量删除数据可以使用Hibernate的HQL语句,请参考12.5节。
2.4 Transaction接口
Transaction接口是对实际事务实现的一个抽象,这些实现包括JDBC事务或者JTA等。这样设计允许开发人员能够使用一个统一的事务操作接口使得自己的项目可以在不同的环境和容器(Container)之间方便地迁移。
Hibernate中的事务是通过配置hibernate.cfg.xml文件选择使用JDBC或者是JTA事务控制。参考下面的配置内容:
- <property name="transaction.factory_class">
- org.hibernate.transaction.JDBCTransactionFactory
- </property>
上面的配置内容表示Hibernate中的事务使用JDBC的事务控制,使用JTA事务控制的配置内容如下:
- <property name="transaction.factory_class">
- org.hibernate.transaction.JTATransactionFactory
- </property>
如果hibernate.cfg.xml文件中没有针事务的配置,则默认使用JDBC的事务控制Hibernate中的事务。
在Transaction接口中主要定义了commit()和rollback()两个方法,前者是提交事务的方法;后者是回滚事务的方法。下面是使用Transaction对象的示例代码:
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransactioin();
- ...
- tx.commit();
- session.close();
上面代码表明Transaction对象通过Session对象的beginTransactioin()方法创建,该方法同时启动这个事务,最后通过commit()或者rollback()方法提交或者回滚这个事务。
2.5 Query接口
使用Query类型的对象可以方便查询数据库的数据,它使用QBC、QBE、HQL或者原生SQL(Native SQL) 查询数据。Query对象不仅能查询数据,还可以绑定参数、限制查询记录数量,以及批量删除和批量更新等。使用Query对象的示例代码如下:
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Query query = session.createQuery("from Guestbook");
- List list = query.list();
- tx.commit();
上面代码表示Query对象通过Session对象的createQuery()方法创建,其中的方法参数值"from Guestbook"是HQL语句,表示要读取所有Guestbook类型的对象。即读取Guestbook表中的所有记录,把每条记录封装成Guestbook对象后保存到List对象中并返回List对象。
Query对象只在Session对象关闭之前有效,否则就会抛出SessionException类型的违例。因为Session对象就像JDBC中的Connection对象,表示与数据库的一次连接。关闭Connection对象,Statement对象则不能使用。所以关闭Session对象,也就不能使用Query对象。参考下面示例的错误代码:
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Query query = session.createQuery("from Guestbook");
- List list = query.list();
- tx.commit();
- query.list();//此行会抛出org.hibernate.SessionException
2.6 Criteria接口
Criteria与Query接口非常类似,它允许创建并执行面向对象方式的查询,示例代码如下:
上面的代码表示在guestbook表中模糊查找name字段值为"刘"字符开始且id值为1~10之间的所有记录,返回满足条件的Guestbook对象的List集合。
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.getCurrentSession();
- Transaction tx = session.beginTransaction();
- Criteria crit = session.createCriteria(Guestbook.class);
- Criterion criterion1 = Restrictions.like("name", "刘%");
- Criterion criterion2 = Restrictions.between("id", new Integer(1),
- new Integer(10));
- crit.add(criterion1);
- crit.add(criterion2);
- List list = crit.list();
- tx.commit();