Q1:Hibernate 是什么?优势在哪里?相关概念:持久化、ORM?
A1:Hibernate 是一个优秀的Java 持久化层解决方案,是当今主流的对象—关系映射(ORM)工具
优势:a、一个开发源代码的对象关系映射框架;
b、对JDBC进行了非常轻量级的对象封装, 简化了JDBC 繁琐的编码;
Session session = HiberanteUtil.getSession();
Query query = session.createQuery("from User");
List<User> users =(List<User>)query.list();
c、将JavaBean对象和数据库的表建立对应关系。
体对象的三种状态:
瞬时态(Transient):不曾进行持久化,未与任何Session相关联,保存在内存的程序数据,程序退出后,数据就消失了,称为瞬时状态;
持久态(Persistent):已被持久化,且加入到Session缓存中,保存在磁盘上的程序数据,程序退出后依然存在,称为程序数据的持久状态;
游离态(也称脱管态,Detached):已经被持久化,但不再处于Session的缓存中,既没有与任何Session相关联。
注:三种状态之间的转换:
持久化:将程序数据在瞬时状态和持久状态之间转换的机制。
ORM(对象-关系映射):是持久化的一种解决方案,主要是把对象模型和关系型数据库关系模型映射起来,并且使用元数据对这些映射进行描述。
Q2:如何为系统同配置Hibernate支持?
A2:第一步:创建项目并导入jar包
第二步:创建Hibernate主配置文件:用于配置数据库连接、运行时所需的各种属性、默认文件名为“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>
<!-- 数据库连接URL -->
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:XE</property>
<!-- 数据库用户名 -->
<property name="connection.username">oa</property>
<!-- 数据库密码 -->
<property name="connection.password">oa123</property>
<!-- 数据库JDBC驱动类名 -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<!-- 数据库方言 -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- ddl语句自动建表 -->
<property name="hbm2ddl.auto">none</property>
<!-- 是否输出Hibernate生成的SQL语句,开发阶段一般需要开启 -->
<property name="show_sql">true</property>
<!-- 是否对输出SQL进行格式化 -->
<property name="format_sql">true</property>
<!-- 连接池配置 -->
<property name="hibernate.connection.provider_class">
org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider
</property>
<!-- 这是C3P0随时准备好的最少的JDBC连接数量 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 连接池中JDBC连接的最大数量 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 超时周期,在它之后,闲置连接将从池中移除 -->
<property name="hibernate.c3p0.timeout">300</property>
<!-- 最多高速缓存100个预编译语句,该属性是使Hibernate获得较好性能的要素。 -->
<property name="hibernate.c3p0.max_statements">100</property>
<!-- 连接被自动验证前,以秒为单位的闲置时间 -->
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!-- 注册ORM实体类映射文件-->
<mapping resource="实体类映射文件路径" />
</session-factory>
</hibernate-configuration>
注:1、数据库连接信息:驱动程序类名、URL、用户名、密码。
2、 Hibernate相关特性:dialect(方言)、show_SQL(输出SQL语句到控制台)、format_SQL(格式化SQL语句)。
3、 连接池相关信息。
4、 实体类映射文件:实体类与数据库表之间的逻辑映射。
第三步:测试连接
- <SPAN style="FONT-SIZE: 18px">public class HibernateTest {
- public static void main(String[] args) {
- //获取配置,默认读取classpath根目录下名为hibernate.cfg.xml的文件
- Configuration cfg = new Configuration().configure();
- ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
- //创建SessionFactory
- SessionFactory factory = cfg.buildSessionFactory(serviceRegistry);
- //获取session
- System.out.println(factory.openSession());
- }
- }</SPAN>
public class HibernateTest {
public static void main(String[] args) {
//获取配置,默认读取classpath根目录下名为hibernate.cfg.xml的文件
Configuration cfg = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
//创建SessionFactory
SessionFactory factory = cfg.buildSessionFactory(serviceRegistry);
//获取session
System.out.println(factory.openSession());
}
}
Q3:如何使用Hibernate完成数据增删改操作?
A3: 第一步:创建实体类。实体类(也称持久化类)是一个带有一些属性的JavaBean类,实体类对属性的存取方法(getter and setter method)使用了标准JavaBean命名约定,同时把类属性的访问级别设成私有的。为了通过反射机制来实例化类的对象,我们需要提供一个无参的构造器,所有的实体类都要求有无参的构造器,因为Hibernate需要使用Java反射机制来为你创建对象。最后要为实体类实现Java.io.Serializable 接口,以便Hibernate能更好的缓存实体对象。
第二步:创建和配置映射文件。通过实体映射文件,Hibernate知道怎样去加载和存储实体类的对象,知道应该访问数据库里面的哪个表及应该使用表里面的哪些字段。
- <SPAN style="FONT-SIZE: 18px"> "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="org.ijob.bean.Seeker" table="ijob_seeker"></SPAN>
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.ijob.bean.Seeker" table="ijob_seeker">
- <SPAN style="FONT-SIZE: 18px"> <!-- 主键映射 -->
- <id name="id" type="string">
- <column name="id" length="32"></column>
- <generator class="uuid" />
- </id>
- <!—属性映射 -->
- <property name="email" type="string">
- <column name="email" length="100"></column>
- </property>
- <property name="password" type="string">
- <column name="password" length="20"></column>
- </property>
- <property name="name" type="string">
- <column name="name" length="10"></column>
- </property></SPAN>
<!-- 主键映射 -->
<id name="id" type="string">
<column name="id" length="32"></column>
<generator class="uuid" />
</id>
<!—属性映射 -->
<property name="email" type="string">
<column name="email" length="100"></column>
</property>
<property name="password" type="string">
<column name="password" length="20"></column>
</property>
<property name="name" type="string">
<column name="name" length="10"></column>
</property>
- <SPAN style="FONT-SIZE: 18px"> <!—此处省略系列属性映射 -->
- </class>
- </hibernate-mapping></SPAN>
<!—此处省略系列属性映射 -->
</class>
</hibernate-mapping>
第三步:在主配置文件中添加实体映射文件路径。将映射文件的路径信息添加到hibernate.cfg.xml中。<mapping resource=“***/***/***.hbm.xml" />
第四步:测试
第五步:数据库操作(1、获取配置;2、创建SessionFactory;3、打开Session;4、开始一个事务;5、持久化操作(save()、update()、delete()、find())6、提交事务;7、关闭Session)
- <SPAN style="FONT-SIZE: 18px"> // 1、获取配置
- Configuration cfg = new Configuration().configure();
- ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
- .applySettings(cfg.getProperties()).buildServiceRegistry();
- // 2、创建SessionFactory
- SessionFactory factory = cfg.buildSessionFactory(serviceRegistry);
- // 3、获取session
- Session session = factory.openSession();
- Transaction tx = session.getTransaction();
- try {
- // 4、开启事务
- tx.begin();
- Seeker seeker = new Seeker();
- seeker.setEmail("abc@163.com");
- seeker.setPassword("abc");
- // 5、保存seeker对象
- session.save(seeker);
- // 6、提交事务
- session.getTransaction().commit();
- } catch (Exception e) {
- tx.rollback();
- e.printStackTrace();
- } finally {
- // 7、关闭session
- session.close();
- }
- }</SPAN>
// 1、获取配置
Configuration cfg = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties()).buildServiceRegistry();
// 2、创建SessionFactory
SessionFactory factory = cfg.buildSessionFactory(serviceRegistry);
// 3、获取session
Session session = factory.openSession();
Transaction tx = session.getTransaction();
try {
// 4、开启事务
tx.begin();
Seeker seeker = new Seeker();
seeker.setEmail("abc@163.com");
seeker.setPassword("abc");
// 5、保存seeker对象
session.save(seeker);
// 6、提交事务
session.getTransaction().commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
// 7、关闭session
session.close();
}
}
Q4:Hibernate中包括哪些关联关系?关联关系在映射文件(hbm.xml)中如何体现?
A4:(1)单项多对一(many-to-one)。即:many的一端应持有one的一端的对象(引用)。
- <SPAN style="FONT-SIZE: 18px">映射文件例:
- <hibernate-mapping>
- <class name="org.ijob.bean.Resume" table="ijob_resume">
- <!—省略主键映射及属性映射 -->
- <!-- 多对一关联 -->
- <many-to-one name="seeker" class="org.ijob.bean.Seeker"> 1
- <column name="seeker_id"></column> 2
- </many-to-one>
- </class>
- </hibernate-mapping>
- 1、name为属性名,class为“one”端类名
- 2、外键列列名</SPAN>
映射文件例:
<hibernate-mapping>
<class name="org.ijob.bean.Resume" table="ijob_resume">
<!—省略主键映射及属性映射 -->
<!-- 多对一关联 -->
<many-to-one name="seeker" class="org.ijob.bean.Seeker"> 1
<column name="seeker_id"></column> 2
</many-to-one>
</class>
</hibernate-mapping>
1、name为属性名,class为“one”端类名
2、外键列列名
(2)单向一对多关联(one-to-many)。one的一端应持有many端的对象集合。
- <SPAN style="FONT-SIZE: 18px">映射文件例:
- <hibernate-mapping>
- <class name="org.ijob.bean.Seeker" table="ijob_seeker">
- <!—省略主键映射及属性映射 -->
- <set name="resumes" > 1
- <key column="seeker_id"></key> 2
- <one-to-many class="org.ijob.bean.Resume"/> 3
- </set>
- </class>
- </hibernate-mapping>
- 代码解析:
- 1、set集合节点适用于配置一对多关联关系, name属性指定one的一端对应属性名。
- 2、外键列列名。
- 3、class属性指定many端的全限定类名。
- </SPAN>
映射文件例:
<hibernate-mapping>
<class name="org.ijob.bean.Seeker" table="ijob_seeker">
<!—省略主键映射及属性映射 -->
<set name="resumes" > 1
<key column="seeker_id"></key> 2
<one-to-many class="org.ijob.bean.Resume"/> 3
</set>
</class>
</hibernate-mapping>
代码解析:
1、set集合节点适用于配置一对多关联关系, name属性指定one的一端对应属性名。
2、外键列列名。
3、class属性指定many端的全限定类名。
(3)双向一对多/一对一关联。双向一对多特别简单,就是同时配置了单向的一对多和单向的多对一。
(4)一对一关联
(5)多对多关联。将其转换成两个一对多。
- <SPAN style="FONT-SIZE: 18px">如果中间表是联合主键:
- <!-- 联合主键 -->
- <composite-id>
- <!--同时表达这是外键-->
- <key-many-to-one name=“book” column=“book_id" class=“entity.Book" ></key-many-to-one>
- <key-many-to-one name=“student” column=“stu_id" class=“entity.Book" ></key-many-to-one>
- </composite-id></SPAN>
如果中间表是联合主键:
<!-- 联合主键 -->
<composite-id>
<!--同时表达这是外键-->
<key-many-to-one name=“book” column=“book_id" class=“entity.Book" ></key-many-to-one>
<key-many-to-one name=“student” column=“stu_id" class=“entity.Book" ></key-many-to-one>
</composite-id>
Q5:Hibernate的主要查询方式有哪些?
A5:主要支持两种查询方式:(1)HQL查询(Hibernate Query Languge,Hibernate 查询语言):是一种面向对象的查询语言,其中没有表和字段的概念,只有类、对象和属性的概念,应用较为广泛;注意:HQL中没有表和字段的概念,只有类、对象和属性的概念,这点需要大家好好体会。(2)Criteria查询:又称为“对象查询”,它用面向对象的方式将构造查询的过程做了封装(了解)。
附:HQL查询使用方法:a、得到Session;b、编写HQL语句;c、创建Query对象,Query接口是HQL 查询接口。它提供了各种的查询功能;d、执行查询,得到结果
Q6:关于Hibernate加载计划和策略。
A6:Hibernate提供了下列方法从数据库中获取对象:1、通过get()或load()方法按照id获取对象; 2、从一个已经加载的对象开始,通过系列的get方法访问被关联的对; 3、HQL查询获取单个或系列对象; 4、Criteria查询获取单个或系列对象; 5、原生SQL查询获取单个或系列对象。
关于加载计划:为了加以区别,我们称第一层次的查询目标为“主对象”。现在我们要关注的是主对象及其关联对象的加载计划和加载策略,即数据何时被加载以及数据被怎样加载的问题。
涉及到加载计划(何时加载)的关注点有以下几个:1、主对象的关联对象何时被加载;2、主对象的关联集合何时被加载;3、主对象本身何时被加载;4、主对象的属性何时被加载。
对于上面提到的关注点,Hibernate都有默认的加载计划。具体来说,是这样的:1、关联对象和关联集合的默认加载计划是:延迟加载,即加载主对象时它们不会被立即加载,而是直到使用这些对象和集合时才发送SQL语句、获取数据、初始化对象和集合;2、主对象本身是否延迟加载取决于使用的是load()方法还是其它方法,load()方法是延迟的,而get()方法或其它方法是立即的;3、主对象的属性默认是被立即加载的。
Q7:重点:Hibernate中的Session操作解释。
A7:public interface Session extendsSerializable
Java应用程序与Hibernate之间的主要运行时接口。它是抽象了持久化服务概念的核心抽象API类。
Session的生命周期绑定在一个物理的事务(tansaction)上面。(长的事务可能跨越多个数据库事物。)
Session的主要功能是提供对映射的实体类实例的创建,读取和删除操作。实例可能以下面三种状态存在:
自由状态(transient): 不曾进行持久化,未与任何Session相关联
持久化状态(persistent): 仅与一个Session相关联
游离状态(detached): 已经进行过持久化,但当前未与任何Session相关联
游离状态的实例可以通过调用save()、persist()或者saveOrUpdate()方法进行持久化。持久化实例可以通过调用 delete()变成游离状态。通过get()或load()方法得到的实例都是持久化状态的。游离状态的实例可以通过调用update()、0saveOrUpdate()、lock()或者replicate()进行持久化。游离或者自由状态下的实例可以通过调用merge()方法成为一个新的持久化实例。
save()和persist()将会引发SQL的INSERT,delete()会引发SQLDELETE,而update()或merge()会引发SQLUPDATE。对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起SQLUPDATE。saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE。
其具体实现并不一定是线程安全的。每个线程/事务应该从一个SessionFactory获取自己的session实例。
如果其持久化对象类是可序列化的,则Session实例也是可序列化的。
See Also:
SessionFactory
Session管理: