概述
简介
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。
具体请参考百度百科 - Hibernate
优势
- Hibernate对JDBC访问数据库的代码做了轻量级封装,大大简化了数据访问层繁琐的重复性代码,并减少了内存消耗,加快了运行效率
- Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它很大程度的简化了dao层编码工作
- Hibernate的性能非常好。映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系
环境搭建
下载并引入jar包
由于地址可能会更新,在此略,可自行百度。
下载后解压可看到几个文件夹:
* documentation:存放文档,包含API文档
* lib:存放Hibernate编译和运行依赖的Jar包,其中requeired子目录为必须的Jar包
* project:存放Hibernate相关源代码
打开lib/required可看到Hibernate必要的包:
其中不包括JDBC驱动包,需自己从导入。
创建数据表及实体类
表
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_linkman` VARCHAR(64) DEFAULT NULL COMMENT '联系人',
`cust_ phone` VARCHAR(64) DEFAULT NULL COMMENT ' 固定电话',
`cust_mobile` VARCHAR(16) DEFAULT NULL COMMENT '移动电话' ,
PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO INCREMENT=1 DEFAULT CHARSET=utf8;
实体类
public Customer{
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry (String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level () {
return cust_level;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone (String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile (String cust_mobile) {
this.cust_mobile = cust_mobile;
}
}
配置对象与表的映射文件
实体类Customer目前还不具备持久化操作的能力,而Hibernate需要知道实体类Customer映射到数据库Hibernate中的哪个表,以及类中的哪个属性对应数据库表中的哪个字段,这些都需要在映射文件中配置。
在实体类Customer所在的包中,创建一个名称为Customer.hbm.xml的映射文件,在该文件中定义了实体类Customer的属性是如何映射到cst_customer表的列上的。
<?xml version="1. 0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN
"http://www.hibernate.org/ dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--建立类和表的一个映射关系:-->
<!--
class标签:用来建立类和表的映射
*name属性: 类中的全路径.
*table属性:表名(如果类名和表名是一致的,那么table属性客户省略)
*catalog属性:数据库名称,可以省略
-->
<class name="XXXX.Customer" table="cst_customer">
<!--建立类中的属性与表中的主键的映射-->
<!--
id标签:用来建立类中的属性与表中的主键字段对应
* name属性:类中的属性名
* column属性:表中字段名(如果类中的属性名和表中的字段名致, 那么省略column)
* length属性:字段的长度.
* type属性:类型。写Java数据类型,Hibernate数据类型(默认), SQL类型
-->
<id name="cust_id" column="cust_id">
<!--主键生成策略-->
<generator class="native"/>
</id>
<!--建立类中的普通属性与表中的字段的映射-->
<!--
property标签:用来建立类中的普通属性与表中的字段对应
* name属性: 类中的属性名
* column属性:表中字段名(如果类中的属性名和表中的字段名一致,那么省略column)
* length属性:字段的长度.
* type属性:类型。写Java数据类型,Hibernate数据类型(默认), SQL类型
-->
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>
核心配置
有两种配置方式。
* 一种是properties文件格式,默认名称为hibernate.properties
* 另一种是XML格式的文件,默认名称为hibernate.cfg.xml
上述两种配置文件都可以,推荐用第二种
hibernate.cfg.xml
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate配置文件的DTD信息 -->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- hibernate- configuration是连接配置文件的根元素 -->
<hibernate-configuration>
<session-factory>
<!-- 指定连接数据库所用的驱动 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 指定连接数据库的url,hibernate连接的数据库名 -->
<property name="connection.url">jdbc:mysql://localhost/数据库名</property>
<!-- 指定连接数据库的用户名 -->
<property name="connection.username">root</property>
<!-- 指定连接数据库的密码 -->
<property name="connection.password">32147</property>
<!-- 指定连接池里最大连接数 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 指定连接池里最小连接数 -->
<property name="hibernate.c3p0.min_size">1</property>
<!-- 指定连接池里连接的超时时长 -->
<property name="hibernate.c3p0.timeout">5000</property>
<!-- 指定连接池里最大缓存多少个Statement对象 -->
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">true</property>
<!-- 指定数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<!-- 根据需要自动创建数据表,其取值有四个
create:自动建表,每次框架运行都会创建新表,以前的表会被覆盖,表数据会丢失,适合在测试的时候用
create-drop:同上,但是框架运行结束会将表删除
update:常用,自动建表,如果表存在则不会再建,如果映射配置文件更新,会自动更新表,不会丢失数据
validate:校验表结构,如果与映射文件不同会抛出异常,不会更改表结构。
-->
<property name="hbm2ddl.auto">update</property>
<!-- 显示Hibernate持久化操作所生成的SQL -->
<property name="show_sql">true</property>
<!-- 将SQL脚本进行格式化后再输出 -->
<property name="hibernate.format_sql">true</property>
<!-- 罗列所有的映射文件 -->
<mapping resource="映射文件路径/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
hibernate.properties
## MySQL
#方言
hibernate.dialect org.hibernate.dialect.MySQLDialect
hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#驱动
hibernate.connection.driver_class com.mysql.jdbc.Driver
#数据库地址
hibernate.connection.url jdbc:mysql://127.0.0.1/datdabseName
#用户名
hibernate.connection.username root
#密码
hibernate.connection.password 12345
#是否在控制台输出sql语句
hibernate.show_sql true/false
#设置当创建sessionfactory时,是否根据映射文件自动建立数据库表。 create-drop:表示关闭sessionFactory时,将drop刚建的数据库表。该属性可以是update/create-drop/create
hibernate.hbm2ddl.auto update/create-drop/create
###########################
### C3P0 Connection Pool C3P0连接池###
###########################
#连接池最大链接数
hibernate.c3p0.max_size 2
#连接池最小连接数
hibernate.c3p0.min_size 2
#连接池连接的超时时长
hibernate.c3p0.timeout 5000
#缓存statements 的数量
hibernate.c3p0.max_statements 100
hibernate.c3p0.idle_test_period 3000
hibernate.c3p0.acquire_increment 2
hibernate.c3p0.validate true/false
############
### JNDI (java naming directory interface)Java命名目录接口###
###当无需hibernate自己管理数据源而是直接访问容器管理数据源 使用JNDI
############
#指定数据源JNDI名字
hibernate.connection.datasource dddd
#文件系统下
hibernate.jndi.class com.sun.jndi.fscontext.RefFSContextFactory
hibernate.jndi.url file:/
#网络
#指定JND InitialContextFactory 的实现类,该属性也是可选的。如果JNDI与Hibernate持久化访问的代码处于同一个应用,无需指定该属性
hibernate.jndi.class com.ibm.websphere.naming.WsnInitialContextFactory
#指定JNDI提供者的URL,该属性可选 如果JNDI与Hibernate持久化访问的代码处于同一个应用,无需指定该属性
hibernate.jndi.url iiop://localhost:900/
#指定链接数据库用户名
hibernate.connection.username root
#指定密码
hibernate.connection.password 1111
#指定方言
hibernate.dialect org.hibernate.dialect.MySQLDialect
#######################
### Transaction API 事务属性说明###
#######################
#指定是否在事务结束后自动关闭session
hibernate.transaction.auto_close_session true/false
#指定session是否在事务完成后自动将数据刷新到底层数据库
hibernate.transaction.flush_before_completion true/false
## 指定hibernate所有的事务工厂的类型,该属性必须是TransactionFactory的直接或间接子类
hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory
## 该属性值是一个JNDI名,hibernate将使用JTATTransactionFactory从应用服务器中取出JTAYserTransaction
jta.UserTransaction jta/usertransaction
jta.UserTransaction javax.transaction.UserTransaction
jta.UserTransaction UserTransaction
## 该属性值为一个transactionManagerLookup类名,当使用JVM级别的缓存时,或在JTA环境中使用hilo生成器策略时,需要该类
hibernate.transaction.manager_lookup_class org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.transaction.manager_lookup_class org.hibernate.transaction.WeblogicTransactionManagerLookup
hibernate.transaction.manager_lookup_class org.hibernate.transaction.WebSphereTransactionManagerLookup
hibernate.transaction.manager_lookup_class org.hibernate.transaction.OrionTransactionManagerLookup
hibernate.transaction.manager_lookup_class org.hibernate.transaction.ResinTransactionManagerLookup
编写测试代码
public class HibernateDemol {
@Test
/*使用Hibernate保存数据*/
public void demo1() {
// 1.加载配置文件:
Configuration cfg = new Configuration().configure();
// 2.创建一个SessionFactory:
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 3.创建Session对象. Session对象类似Connection.
Session session = sessionFactory.openSession() ;
// 4.开启事务:
Transaction tx = session.beginTransaction();
// 5.执行相关操作
Customer customer = new Customer() ;
customer.setCust_name("小王");
customer.setCust_source("网络推广");
session.save(customer) ;
// 6.事务提交
tx.commit() ;
// 7.释放资源
session.close();
}
}
常用对象
Configuration
配置加载类,用于加载主配置和ORM映射配置。
//推荐:加载默认配置:hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
//加载指定配置文件
Configuration cfg = new Configuration().configure("xxxx.xxx");
SessionFactory
用于创建操作数据库核心对象session的工厂。
负责保存和使用所有配置信息,消耗资源非常大。属于线程安全的对象设计。
保证在项目中,只创建一个SessionFactory。
//创建SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
sessionFactory.close();//释放资源
Session和Transaction
表达Hibernate框架与数据库之间的连接(会话)。类似于JDBC的Connection对象。可以完成对数据库的增删查改等操作。是Hibernate的核心对象。
//获得Session
//打开一个新的Session
Session session = sessionFactory.openSession() ;
//获取一个与线程绑定的Session,通过这种方法获取的Session不需手动不必,当事务提交,Session会自动关闭
Session session = sessionFactory.getCurrentSession() ;
//获取事务
//开启事务并获取事务对象(建议使用)
Transaction tx = session.beginTransaction();
//获取事务对象
Transaction tx = session.getTransaction();
//查询id为1的Customer
Customer customer = session.get(Customer.class,1);
customer.setCust_name("小王");
customer.setCust_source("网络推广");
session.update(customer);//执行修改
session.delete(customer);//执行删除
tx.commit();//提交事务
tx.rollback();//回滚事务
session.close();//释放资源(通过getCurrentSession方法获取的Session不需要此步)
封装Utils工具类
由于Configuration和SessionFactory需消耗大量资源。所以在一个项目中应只存在一个。因此,需要建立一个Hibernate工具类。使得Configuration和SessionFactory只创建一次。
package cn.itheima.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory sf;
static{
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
sf = conf.buildSessionFactory();
}
//获得session => 获得全新session
public static Session openSession(){
//3 获得session
Session session = sf.openSession();
return session;
}
//获得session => 获得与线程绑定的session
public static Session getCurrentSession(){
//3 获得session
Session session = sf.getCurrentSession();
return session;
}
public static void main(String[] args) {
System.out.println(HibernateUtils.openSession());
}
}
实体规则
实体类的三种状态
1.瞬态
一个实体通过new操作符创建后,没有和Hibernate的Session建立关系,也没有手动赋值过该实体的持久化标识(持久化标识可以认为是映射表的主键)。
此时该实体中任何属性的更新都不会反映到数据库表中。
2.持久化
当一个实体和Hibernate的Session创建了关系,并获取了持久化标识,而且在Hibernate的Session生命周期内存在。
此时针对该实体任何属性的更改都会直接影响到数据库表中一条记录对应字段的更新,即与数据库表同步。
3.托管
Hibernate的Session生命周期结束,原本是持久化的实体变为托管状态。
针对该实体任何属性的修改都不会及时反映到数据库表中。
实体类的条件
持久化类提供无参数构造方法
Hibernate在查询操作中需要无参构造方法来实例化对象,因此持久化类必须要包含无参构造方法。
成员变量私有,提供公有的get、set方法
Hibernate需要使用get、set方法来访问、修改私有变量。
持久化类中的属性应尽量使用包装类
包装类可以赋值为null,而基本数据类型不行。
基本数据类型 | 对应包装类 |
---|---|
int | Integer |
long | Long |
float | Float |
double | Double |
... | ... |
持久化类需提供id与表主键对应
持久化类需要有一个成员变量与表主键对应。
不要用final修饰class
Hibernate使用cglib生成代理对象,代理对象是继承被代理对象的。如果被final修饰,则无法生成代理。
主键生成策略
映射配置文件中需配置表主键的生成策略。具体策略有以下几种:
策略值 | 策略作用 |
---|---|
identity | 主键自增,有数据库来维护主键值,录入时不需要指定主键值。 |
increment | 主键自增,由hibernate来维护,每次插入前会先查询表中id最大值,+1作为新主键值,浪费资源,存在线程安全隐患。 |
sequence | Oracle中的生成策略。 |
hilo | 高低位算法,主键自增,由hibernate来维护。 |
native | 推荐使用,hilo+identity+squence,自动三选一。自动选择可采用的生成策略。 |
uuid | 产生随机不重复字符串作为主键,主键类型必须为String。 |
assigned | 需要自己设计生成策略,如果没有设计,则会抛出异常。 |
配置主键生成策略:
<class name="XXXX.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<!--在此配置主键生成策略-->
<generator class="native"/>
</id>
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
持久化实体转化为托管状态
在获取实体对象后,调用getHibernateTemplate().evict(entity)方法,该方法的作用是把持久化对象变成托管状态。变成托管状态后,Hibernate就不会再去自动更新该实体。
其他
缓存与快照
Hibernate存在缓存机制,可以调高执行效率。
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
Customer customer1 = session.get(Customer.class,1l);
Customer customer2 = session.get(Customer.class,1l);
Customer customer3 = session.get(Customer.class,1l);
session.save(customer) ;
tx.commit() ;
session.close();
}
}
上述代码只会执行一次数据库查询操作。且customer1==customer2==customer3。
其他配置
<!-- 指定数据库执行时的隔离级别
1 读未提交、2 读已提交 4 可重复度 8 串行化 -->
<property name="hibernate.connection.isolation">4</property>
<!-- 在指定session与当前线程绑定-->
<property name="hibernate.current_session_context_class">thread</property>
查询方式
此处仅做简要介绍,详细请参考Hibernate的查询方式
Criteria查询
适合单表条件查询
查所有
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();//返回List结果
tx.commit() ;
session.close();
}
}
条件查询
HQL符号与Restrictions对象的方法对应关系:
符号 | 方法名 | 全拼 |
---|---|---|
> | gt | Greater Than |
>= | ge | Greater than or Equal |
< | lt | Less Than |
<= | le | Less than or Equal |
== | eq | EQual |
!= | ne | Not Equal |
in | in | |
between and | between | |
like | like | |
is not null | isNotNull | |
is null | isNull | |
or | or | |
and | and |
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
/*添加查询参数*/
criteria.add(Restrictions.eq("cust_id",1l));//cust_id==1
Customer customer = criteria.uniqueResult();//返回单个结果
tx.commit() ;
session.close();
}
}
分页查询
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
//limit ?,?
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List<Customer> list = criteria.list();//返回List结果
tx.commit() ;
session.close();
}
}
聚合函数查询
Criterial也支持聚合函数,例如,查询记录总数:
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
//设置聚合函数为总行数
criteria.setProjection(Projection.rowCount());
Long list = (Long)criteria.uniqueResult();//返回单个结果
tx.commit() ;
session.close();
}
}
HQL
适合不复杂的多表查询
HQL类似于SQL,但是HQL是针对于对象的,SQL是针对于数据表的。
HQL不会出现相关的表名、字段名等信息。
查所有
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
String hql = "from cn.itheima.domain.Customer";
Query query = session.createQuery(hql);
List<Customer> list = query.list();//返回List结果
tx.commit() ;
session.close();
}
}
条件查询
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
//cust_id为Customer类的属性名,非表字段名
String hql = "from cn.itheima.domain.Customer where cust_id = :cust_id";
Query query = session.createQuery(hql);
//设置参数
query.setParameter("cust_id",1l);
Customer customer = (Customer)query.uniqueList();//返回取出单个结果
tx.commit() ;
session.close();
}
}
分页查询
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
String hql = "from cn.itheima.domain.Customer";
Query query = session.createQuery(hql);
//设置分页信息 limit ?,?
query.setFirstResult(0);//从第几个开始
query.setMaxResults(1);//获取结果个数
List<Customer> list = query.list();//返回List结果
tx.commit() ;
session.close();
}
}
原生SQL查询
适合复杂的多表查询
不封装对象
查询到的每一个字段都为Object类型
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
String sql = "select * from customer";
SQLQuery query = session.createSQLQuery(sql);
List<Object[]> list = query.list();//返回List结果
tx.commit() ;
session.close();
}
}
封装对象
将查询到的记录封装成对象返回。
public class HibernateDemol {
@Test
public void demo1() {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession() ;
Transaction tx = session.beginTransaction();
String sql = "select * from customer";
SQLQuery query = session.createSQLQuery(sql);
//将制定结果集封装到哪个对象中
query.addEntity(Customer.class);
List<Customer> list = query.list();//返回List结果
tx.commit() ;
session.close();
}
}
Comments | NOTHING