1、Hibernate简介
首先,什么是hibernate?Hibernate是一个开放源代码的ORM框架,它对JDBC进行了轻量级的对象封装,使得Java开发人员可以使用面向对象的编程思想来操作数据库。Hbernate框架对应Javaee三层结构中的DAO层,其是用来操作数据库的一个框架,使用Hibernate框架可以极大地简化DAO层的代码。
那么什么是ORM?ORM是一种技术,它是Object Relationship Mapping的简称,翻译为中文的含义为对象关系映射,其含义为将对象模型表示的对象映射到基于SQL的关系模型数据库结构中去。即将Java中的对象与关系型数据库中的表结构做映射,从效果上来说,它其实是创建了一个可以在编程语言里使用的“虚拟对象数据库”。简单的说就是把我们程序中的实体类和数据库表建立起来对应关系。
Hibernate框架的几点优点需要了解:
- Hibernate对JDBC访问数据库的代码做了轻量级封装,大大简化了数据访问层繁琐的重复性代码,并且减少了内存消耗,加快了运行效率。
- Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现,它很大程度的简化了DAO(Data Access Object,数据访问对象)层编码工作。
- Hibernate的性能非常好,映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系。
- 可扩展性强,由于源代码的开源以及API的开放,当本身功能不够用时,可以自行编码进行扩展。
2、Hibernate框架的环境搭建部分
a、下载:既然是一个框架,那么首先需要获取Jar包,框架对应的Jar包可由网站https://sourceforge.net/projects/hibernate/files/hibernate-orm/获取,选择不同的版本,下载对应的ZIP压缩包。
b、zip目录简介:
documentation文件夹:存放Hibernate的相关文档,包括参考文档的API文档。
lib文件夹:存放Hibernate编译和运行所依赖的JAR包。其中required子目录下包含了运行Hibernate5项目必须的JAR包。
project文件夹:存放Hibernate各种相关的源代码。
c、Hibernate基础开发环境搭建:
要使用Hibernate框架操作数据库,必须导入的jar包部分如下:
数据库驱动包,不同数据库对应不同的驱动jar包;
Hibernate/lib/required/*.jar,即required目录下的所有jar包;
日志记录的包,一般使用zip中提供的log4j的jar包;
3、Hibernate框架的基础使用(使用Hibernate实现基础增删改查)
a、在jar包导入完成或者说环境搭建完成后,首先需要准备相关表,此处使用的数据库为MySql,创建表的SQL语句如下:
/*客户表*/
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
`cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
b、创建与该表对应的实体类,需要注意的是,类中属性的类型要与数据库表字段数据类型保持一致
/**
* 客户的实体类
*/
public class Customer implements Serializable {
private Long custId;
private String custName;
private String custSource;
private String custIndustry;
private String custLevel;
private String custAddress;
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
@Override
public String toString() {
return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
+ ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
+ ", custPhone=" + custPhone + "]";
}
}
c、编写实体类与表之间的映射配置文件,该映射文件为xml文件,一般会和实体类放在同一个包中,且命名规范为:类名.hbm.xml。编写该xml需要遵循的xml规范文件一般位于所导入的hibernate-core-xxx.final.jar包中,具体目录示例为:\hibernate-core-5.0.7.Final\org\hibernate,该目录下的hibernate-mapping-3.0.dtd或hibernate-mapping-4.0.xsd即为该映射配置文件需要遵循的xml规范。此外,该规范一般为需要访问hibernate的一个网址的规范,如开发机无法联网,以eclipes为例,可以通过window-preference-xml Catalog菜单来将约束头中的网址指向本地的文件。其他约束文件同理。
该配置文件举例如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束:dtd约束
位置:在Hibernate的核心jar包中名称为hibernate-mapping-3.0.dtd
明确该文件中的内容:
实体类和表的对应关系
实体类中属性和表的字段的对应关系
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.itheima.domain"><!-- package属性用于设定包的名称,接下来该配置文件中凡是用到此包中的对象时都可以省略包名,此文件中主要是省略了class标签中name属性中的包名-->
<!-- class标签
作用:建立实体类和表的对应关系
属性:
name:指定实体类的名称
table:指定数据库表的名称
-->
<class name="Customer" table="cst_customer">
<!-- id标签
作用:用于映射主键
属性:
name:指定的是属性名称。也就是get/set方法后面的部分,并且首字母要转小写。
column:指定的是数据库表的字段名称
-->
<id name="custId" column="cust_id">
<!-- generator标签:
作用:配置主键的生成策略。
属性:
class:指定生成方式的取值。
取值之一:native。使用本地数据库的自动增长能力。
mysql数据库的自动增长能力是让某一列自动+1。但是不是所有数据库都支持这种方式。
-->
<generator class="native"></generator>
</id>
<!-- property标签:
作用:映射其他字段
属性:
name:指定属性的名称。和id标签的name属性含义一致
column:指定数据库表的字段名称
-->
<property name="custName" column="cust_name"></property>
<property name="custLevel" column="cust_level"></property>
<property name="custSource" column="cust_source"></property>
<property name="custIndustry" column="cust_industry"></property>
<property name="custAddress" column="cust_address"></property>
<property name="custPhone" column="cust_phone"></property>
</class>
</hibernate-mapping>
d、编写hibernate主配置文件,hibernate.cfg.xml,该配置文件主要用来配置数据库连接以及Hibernate运行时所需要的各个属性的值。一般需要在src目录下创建该xml文件,且文件名不可更改,这是因为该xml文件名为封装在jar包中的一个常量,会在加载配置文件时,主动加载该文件。该xml文件的约束文件同映射配置文件,位于\hibernate-core-5.0.7.Final\org\hibernate下,可取hibernate-configuration-3.0.dtd或者hibernate-configuration-4.0.xsd约束文件。此外,此配置文件中的property属性列表见\hibernate-release-5.0.7.Final\project\etc下的hibernate.properties文件,所有属性名均可以从该文件获取到。配置文件示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入dtd约束:
位置:在核心jar包中的名称为hibernate-configuration-3.0.dtd中
-->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 配置SessionFactory
SessionFactory就是一个工厂,用于生产Session对象的。
Session就是我们使用hibernate操作数据库的核心对象了。
明确:
它和我们Web的HttpSession没一点关系。
此配置文件中的内容不需要背,很多配置都是可以在开发包中找到的。
但是要求必须知道:
创建SessionFactory由三部分组成,缺一不可。要知道是哪三部分
1、连接数据库的基本信息
2、hibernate的基本配置
3、映射文件的位置
找配置文件的key都是在hibernate的开发包中project文件夹下的etc目录中的hibernate.properties
-->
<session-factory>
<!-- 1、连接数据库的基本信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/day36_ee48_hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1234</property>
<!-- 2、hibernate的基本配置 -->
<!-- 数据库的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 是否显示SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 是否格式化SQL语句 -->
<property name="hibernate.format_sql">true</property>
<!-- 是否让hibernate根据表结构的变化来生成DDL语句
DDL:数据定义语言
hibernate可以根据映射文件来为我们生成数据库的表结构。
但是他不能生成数据库。
hbm2ddl.auto的取值
* none:不用Hibernate自动生成表.
* create:每次都会创建一个新的表.(测试)
* create-drop:每次都会创建一个新的表,执行程序结束后删除这个表.(测试)
* update:如果数据库中有表,使用原来的表,如果没有表,创建一个新表.可以更新表结构。
* validate:只会使用原有的表.对映射关系进行校验.
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 3、映射文件的位置 -->
<mapping resource="com/itheima/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
该配置文件中常用属性配置表如下:
名称 | 用途 |
hibernate.dialect | 操作数据库的方言(不同数据库取值不同) |
hibernate.connection.driver_class | 连接数据库驱动程序 |
hibernate.connection.url | 连接数据库URL |
hibernate.connection.username | 数据库用户名 |
hibernate.connection.password | 数据库密码 |
hibernate.show_sql | 在控制台上输出SQL语句 |
hibernate.format_sql | 格式化控制台输出的SQL语句 |
hibernate.hbm2ddl.auto | 当SessionFactory创建时是否根据映射文件自动验证表结构或自动创建、自动更新数据库表结构。该参数的取值为:validate、update、create和create-drop。 |
hibernate.connection.autocommit | 事务是否自动提交 |
e、编写Java代码完成增删改查,具体操作步骤及代码如下:
public class HinernateDemo01 {
/**
基础步骤描述:加载主配置文件,创建SessionFactory,开启Session,对于增删改需要开启事务,
进行对应的操作,提交事务,关闭Session对象。
*/
//查询
@Test
public void query(){
Configuration configure = new Configuration().configure();
SessionFactory buildSessionFactory = configure.buildSessionFactory();
Session openSession = buildSessionFactory.openSession();
Customer cus = new Customer();
//通过get方式查询
cus = openSession.get(cus.getClass(), 1L);
System.out.println(cus.getCust_name());
//通过load方法查询
cus = openSession.load(cus.getClass(), 1L);
System.out.println(cus.getCust_name());
openSession.close();
}
//增加
@Test
public void add() {
Configuration configure = new Configuration().configure();
SessionFactory buildSessionFactory = configure.buildSessionFactory();
Session openSession = buildSessionFactory.openSession();
Transaction transaction = openSession.beginTransaction();
Customer cus = new Customer();
cus.setCust_name("limeng");
openSession.save(cus);
transaction.commit();
openSession.close();
}
//更新
@Test
public void update() {
Configuration configure = new Configuration().configure();
SessionFactory buildSessionFactory = configure.buildSessionFactory();
Session openSession = buildSessionFactory.openSession();
// Transaction beginTransaction = openSession.beginTransaction();
Customer cus = new Customer();
cus = openSession.load(cus.getClass(), 2L);
cus.setCust_name("孙悟空");
openSession.update(cus);
// beginTransaction.commit();
openSession.close();
}
//删除
@Test
public void delete(){
Configuration configuration = new Configuration().configure();
SessionFactory buildSessionFactory = configuration.buildSessionFactory();
Session openSession = buildSessionFactory.openSession();
Transaction beginTransaction = openSession.beginTransaction();
Customer cus = new Customer();
cus = openSession.get(cus.getClass(), 2L);
openSession.delete(cus);
beginTransaction.commit();
openSession.close();
}
}
4、Hibernate基础API
a、Configuration对象
在使用Hibernate时,首先要创建Configuration实例,Configuration实例主要用于启动、加载、管理hibernate的配置文件信息。在启动Hibernate的过程中,Configuration实例首先确定Hibernate配置文件的位置,然后读取相关配置,最后创建一个唯一的SessionFactory实例。Configuration对象只存在于系统的初始化阶段,它将SessionFactory创建完成后,就完成了自己的使命。
此外,如果不想使用默认的hibernate.cfg.xml文件,那么需要在创建Configuration对象的时候声明路径即可:
Configuration config = new Configuration().configure("xml文件路径");
configuration对象也可以用来加载实体类与表的映射文件,只需要调用addResource();方法即可,如:
configuration.addResource("/Customer.hbm.xml");
常用方法:
默认构造函数:
它只能加载类的根路径下,名称为hibernate.properties的配置文件。不能加载xml
configure():
它用于加载类的根路径下,名称为hibernate.cfg.xml的配置文件。
buildSessionFactory():
根据配置文件,构建SessionFactory
addResource(String url);
指定映射文件的位置
addClass(Class clazz);
指定实体类的字节码
b、SessionFactory
SessionFactory接口负责Hibernate的初始化和建立Session对象。它在Hibernate中起到一个缓冲区作用,Hibernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。通过config.buildSessionFactory()来获取。
常用方法:
openSession():生成一个新的Session
*
该对象维护了很多信息:
- 连接数据库的信息
- hibernate的基本配置
- 映射文件的位置,以及映射文件中的配置
- 一些预定义的SQL语句(这些语句都是通用的) 比如:全字段保存,根据id的全字段更新,根据id的全字段查询,根据id的删除等等。
- hibernate的二级缓存(了解)
同时,它是一个线程安全的对象,所有由该工厂生产的Session都共享工厂中维护的数据。一般情况下,一个项目中只需要一个SessionFactory,只有当存在多个消息源时,才为每一个数据源建立一个SessionFactory实例,因此,不应该反复创建和销毁SessionFactory。
c、Session
Session 是应用程序与数据库之间交互操作的一个单线程对象,是 Hibernate 运作的中心,它的主要功能是为持久化对象提供创建、读取和删除的能力,所有持久化对象必须在session的管理下才可以进行持久化操作。
创建SessionFactory实例后,就可以通过它获取Session实例。获取Session实例有两种方式,一种是通过openSession()方法,另一种是通过getCurrentSession()方法。两种方法获取session的代码如下所示:
//采用openSession方法创建session
Session session = sessionFactory.openSession();
//采用getCurrentSession()方法创建session
Session session = sessionFactory.getCurrentSession();
以上两种获取session实例方式的主要区别是,采用openSession方法获取Session实例时,SessionFactory直接创建一个新的Session实例,并且在使用完成后需要调用close方法进行手动关闭。而getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或回滚操作时会自动关闭。
需要注意的是,如果要通过getCurrentSession()来获取Session,需要在主配置文件中添加:
<property name="hibernate.current_session_context_class">thread</property>
此外,hibernate.current_session_context_class属性值还有以下值:
- thread:Session 对象的生命周期与本地线程绑定
- jta:Session 对象的生命周期与 JTA 事务绑定
- managed:Hibernate 委托程序来管理 Session 对象的生命周期
常用方法:
save(Object entity); :保存一个实体到数据库
update(Object entity);:更新一个实体
delete(Object entity);:删除一个实体
get(Class clazz,Serializable id);:根据id查询一个实体。参数的含义:Class表示要查询的实体类字节码。Serializable就是查询的条件。
load(Class clazz,Serializable id);:根据id查询一个实体。参数的含义:Class表示要查询的实体类字节码。Serializable就是查询的条件。
beginTransaction();:开启事务,并返回事务对象
*当使用getCurrentSession的时候,如果当前线程未开启Session,那么不一定可以获取到Session
对于Session的常用方法中,get和load方法都是用于根据id查询的方法,但是二者有区别,如下:
区别:
1、查询的时机不一样
get方法任何时候都是立即加载,即只要一调用get马上发起数据库查询
load方法默认情况下是延迟加载,即真正用到对象的非OID字段数据才发起查询
load方法可以通过配置的方式改为立即加载。
配置的方式:
由于load方法是hibernate的方法所以只有XML的方式:
<class name="Customer" table="cst_customer" lazy="false">
2、返回的结果不一样
get方法永远返回查询的实体类对象。
load方法当是延迟加载时,返回的是实体类的代理对象。
涉及的概念:
立即加载:
是不管用不用马上查询。
延迟加载:
等到用的时候才真正发起查询。
d、Transaction
Transaction接口主要用于管理事务,它是Hibernate的数据库事务接口,且对底层的事务接口进行了封装。Transaction接口的事务对象是通过Session对象开启的,其开启方式如下所示。
Transaction transaction = session.beginTransaction();
常用方法:
commit():提交事务
rollback():回滚事务
Session执行完数据库操作后,要使用Transaction接口的commit()方法进行事务提交,才能真正的将数据操作同步到数据库中。发生异常时,需要使用rollback()方法进行事务回滚,以避免数据发生错误。因此,在持久化操作后,必须调用Transaction接口的commit()方法和rollback()方法。如果没有开启事务,那么每个Session的操作,都相当于一个独立的操作。
5、更改hibernate中的连接池
Hibernate框架内部自己维护了一个连接池,如果要使用第三方连接池,如c3p0连接池,dbcp连接池,那么需要在主配置文件中进行声明,并且导入对应的连接池jar包。声明格式如下(以c3p0为例):
<property name="hibernate.connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>