1.前言
Hibernate是一个持久层框架,它的作用主要是用来持久化数据的。
1.1市面流行的持久层技术
1.jdbc
2.JdbcTemplate
3.Hibernate
4.MyBatis
1.2JDBC和JDBCTemplat的对比
JDBC:
优势:
最低层,效率高
缺点:
操作繁琐,尤其是封装数据结果集时。
JdbcTemplate:它是JDBC的简单封装
优势:
效率还是很高,而且封装结果集变的简单
缺点:
还是要编写sql,如果插入或更新字段较多时,还是比较繁琐。
1.3Hibernate框架的思想
有没有一个框架可以把我们上述问题解决掉?
答案:有,Hibernate框架就是一个很好的框架,帮我们完成上述问题的解决
想法:
Eg:保存一个商品 :save(Good);
查询一个商品 :get(id);
答案:
可以完成上述操作
有想法?
是否得有一个表存储商品信息--------good
create table good (
id int primary key auto_increment,
good_name varchar
);
是否得有一个实体存储商品信息-----Good
public class Good{
private int id;
private String goodName;
}
l 是否要建立它两之间的关系?--------肯定要,怎么建立?
sql来建立关系,jdbc实现方式。
insert into good (id,good_name) values (good.getId(),good.getName())
通过配置文件:properties,xml(当前知道的)
那我们选择哪一种(只有一种)?
xml:properties配置取代不了(描述层级关系)。
对应关系配置示例:
<class name=”类名” table=”表名” > <id name=”属性名称” column=”表中主键字段名称”/> <property name=”属性名称” column=”表中字段名”/> </class>
是否要解析配置文件生成一条sql语句?------肯定要,框架帮我们做了。
insert into $tablename$ ($columnname$,$columnname$)values(good.getId(),good.getGoodName())
ORM
ORM(Object Relational Mapping)对象关系映射。是一种程序技术,可理解为一种规范,它概述了ORM框架的基本特征。用于完成面向对象编程语言中的对象与关系型数据库的表对应关系 。简单的说就是程序中的实体类要与数据库中的表建立起关系,最终达到操作实体类就相当于操作数据库表。ORM框架当成应用程序和数据库的桥梁。采用ORM框架之后,应用程序不直接操作底层数据库,而是以面向对象的方式操作对象,而ORM框架将面向对象的这些操作转换为底层的SQL操作。
可以把ORM理解为关系型数据和对象的一个纽带,开发人员只需要关注纽带一端映射的对象即可。ORM原理如图1-1所示。
Hibernate
Hibernate概述
Hibernate是面向Java环境实现了ORM的一个轻量级、企业级、开源的持久层框架。
- 轻量级:一般是非侵入性的、依赖的东西非常少,占用资源非常少,部署简单,比较容易使用。
- 企业级:有固定客户群体的程序。
- 开源的:开放源代码。
为什么要学习Hibernate及使用它
使用传统的JDBC开发应用系统时,如果是小型应用系统,并不觉得有什么麻烦,但是对于大型应用系统的开发,使用JDBC就会显得力不从心。
- 例如对几十、几百张包含几十个字段的表进行插入操作时,编写的SQL语句不但很长,而且繁琐,容易出错;
- 在读取数据时,需要写多条getXxx语句从结果集中取出各个字段的信息,不但枯燥重复,并且工作量非常大。
- 为了提高数据访问层的编程效率,Gavin King开发出了一个当今最流行的ORM框架,它就是Hibernate框架。
Hibernate的优势
- Hibernate对JDBC访问数据库的代码做了轻量级封装,大大简化了数据访问层繁琐的重复性代码,并且减少了内存消耗,加快了运行效率。
- Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现,它很大程度的简化了DAO(Data Access Object,数据访问对象)层编码工作。
- Hibernate的性能非常好,映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系。
- 可扩展性强,由于源代码的开源以及API的开放,当本身功能不够用时,可以自行编码进行扩展。
Hibernate的下载
http:hibernate.org
Hibernate压缩包分析
documentation:这是hibernate的文档文件夹
lib:这是Hibernate依赖的jar包
required:使用hibernate必须导入的jar包
optional: 根据需求,可以选择导入的jar包
project:这是hiernate的原码
Hibernate快速入门
1.导入jar包
mysql的驱动jar
hibernate的必须jar包
###2.创建数据库及相关表
create database if not exists third_hibernate;
use third_hibernate;
create table if not exists user_info(
id int primary key auto_increment,
username varchar(50) not null comment '用户名',
password varchar(64) not null comment '密码',
real_name varchar(50) not null
);
insert into user_info (username,password,real_name) value('zwj',123,'张无忌');
insert into user_info (username,password,real_name) value('xz',123,'小昭');
insert into user_info (username,password,real_name) value('zzr',123,'周芷若');
insert into user_info (username,password,real_name) value('zr',123,'蛛儿');
select * from user_info;
###3.创建实体(持久化类)
public class UserInfo{
private Integer id;
private String username;
private String password;
private String realName;
...get/set
}
4.编写映射配置文件
实体类UserInfo目前还不具备持久化操作的能力,而Hibernate需要知道实体类UserInfo映射到数据库中的哪个表,以及类中的哪个属性对应数据库表中的哪个字段,这些都需要在映射文件中配置。
配置文件的位置:(建议和实体类在一个包中,命名为xxxx.hbm.xml)
在实体类UserInfo所在的包中,创建一个名称为UserInfo.hbm.xml的映射文件
创建名为:实体名称.hbm.xml的xml文件。
引入hibernate-mapping的DTD约束。
配置实体与表的映射关系
<?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">
<!-- package用于设定包的名称,接下来该配置文件中用到此包中的对象时都可以省略包名 -->
<hibernate-mapping package="com.fubo.entity">
<!-- class标签
作用:建立实体类和表的对应关系
属性:
name:指定实体类的名称
table:指定数据库表的名称
-->
<class name="UserInfo" table="user_info">
<!-- id标签
作用:用于映射主键
属性:
name:指定的是属性名称。也就是get/set方法后面的部分,并且首字母要转小写。
column:指定的是数据库表的字段名称
-->
<id name="id" column="id">
<!-- generator标签:
作用:配置主键的生成策略。
属性:
class:指定生成方式的取值。
取值之一:native。使用本地数据库的自动增长能力。
mysql数据库的自动增长能力是让某一列自动+1。不是所有数据库都支持这种方式。
-->
<generator class="native"></generator>
</id>
<!-- property标签:
作用:映射其他字段
属性:
name:指定属性的名称。和id标签的name属性含义一致
column:指定数据库表的字段名称
-->
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="realName" column="real_name"></property>
</class>
</hibernate-mapping >
5.编写hibernate的主配置文件
Hibernate的映射文件反映了持久化类和数据库表的映射关系,而Hibernate的配置文件主要用来配置数据库连接以及Hibernate运行时所需要的各个属性的值。在项目的src下创建一个名称为hibernate.cfg.xml的文件
创建名为:hibernate.cfg.xml的xml文件。文件放在项目根目录。
引入hibernate-configuration的DTD约束。
配置hibernate相关信息
<?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> <!-- 第一部分,数据库配置 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/third_hibernate?serverTimezone=GMT%2B8</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property> <!-- 第二部分,Hibernate的可选配置 --> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 第三部分,实体映射文件配置 --> <mapping resource="com/fubo/entity/UserInfo.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 事务是否自动提交
6.测试类的编写
package com.fubo.test;
import com.fubo.entity.UserInfo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class Test1 {
/**
* 步骤分析:
* 1、加载主配置文件
* 2、根据主配置文件中的配置构建SessionFactory
* 3、使用工厂生产一个Session对象
* 4、使用Session对象开启事务
* 5、执行保存客户操作
* 6、提交事务
* 7、释放资源
*/
public static void main(String[] args) {
UserInfo user = new UserInfo();
user.setUsername("jhpp");
user.setPassword("jhpp");
user.setRealName("金花胖胖");
Configuration configuration = new Configuration();
configuration.configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(user);
transaction.commit();
session.close();
}
}
7.Hibernate执行过程
首先创建Configuration类的实例,并通过它来读取并解析配置文件hibernate.cfg.xml。
然后创建SessionFactory读取解析映射文件信息,并将Configuration对象中的所有配置信息拷贝到SessionFactory内存中。
接下来,打开Session,让SessionFactory提供连接。
开启一个事务
之后创建对象,向对象中添加数据,通过session.save()方法完成向数据库中保存数据的操作。
最后提交事务,并关闭资源。
Hibernate API详解
Configuration对象(会用)
作用
在使用Hibernate时,首先要创建Configuration实例,Configuration实例主要用于启动、加载、管理hibernate的配置文件信息。在启动Hibernate的过程中,Configuration实例首先确定Hibernate配置文件的位置,然后读取相关配置,最后创建一个唯一的SessionFactory实例。
Configuration对象只存在于系统的初始化阶段,它将SessionFactory创建完成后,就完成了自己的使命。
Hibernate通常使用Configuration config = new Configuration().configure();的方式创建实例,此种方式默认会去src下读取 hibernate.cfg.xml配置文件。如果不想使用默认的hibernate.cfg.xml配置文件,而是使用指定目录下(或自定义)的配置文件,则需要向configure()方法中传递一个文件路径的参数,其代码写法如下:
Configuration config = new Configuration().configure(“xml文件位置”);
此种写法hibernate会去指定位置查找配置文件,例如,想要使用src下config包中的 hibernate.cfg.xml文件,只需将文件位置加入configure()中即可,其代码如下所示:
Configuration config = new Configuration().configure("/config/hibernate.xml");
Hibernate除了可以使用Configuration对象加载核心配置文件以外,还可以利用该对象加载映射文件。因为如何使用properties文件作为Hibernate的核心配置文件,其他的属性可以使用key=value的格式来设置,但是映射没有办法加载。这时这个对象就有了用武之地。可以在手动编写代码的时候去加载映射文件。
Configuration configuration = new Configuration().configure(“xml文件位置”);
configuration.addResource(“com/fubo/entity/UserInfo.hbm.xml”);
常用方法
无参构造器
- 它只能加载类的根路径下,名称为hibernate.properties的配置文件。不能加载xml
configure()
- 它用于加载类的根路径下,名称为hibernate.cfg.xml的配置文件。
configure(String cfgLocation)
它用于加载指定根路径下,名称为指定名称的配置文件。
Configuration configuration = new Configuration(); configuration.configure("/config/hibernate.cfg.xml");
buildSessionFactory()
- 它的作用是构建一个Session工厂
addResource(String resource);
- 指定映射文件的位置
addClass(Class cla)
指定实体类的字节码。(映射文件名必须和实体类名相同)
configuration.addClass(UserInfo.class);
SessionFactory
SessionFactory并不是轻量级的!实际上它的设计者的意图是让它能在整个应用中共享,其创建和销毁需要耗费很大的资源。典型地来说,一个项目通常只需要一个SessionFactory就够了,但是当你的项目要操作多个数据库时,那你必须为每个数据库指定一个SessionFactory。 并且SessionFactory是线程安全,多个并发线程可以同时访问一个 SessionFactory 并从中获取Session实例。
使用原则:一个应用只有一个SessionFactory,应用加载时创建,应用销毁时销毁。
作用
SessionFactory接口负责Hibernate的初始化和建立Session对象。它在Hibernate中起到一个缓冲区作用,Hibernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。
SessionFactory 实例是通过Configuration对象获取的,其获取方法如下所示。
SessionFactory sessionFactory = config.buildSessionFactory();
维护很多信息
- 连接数据库的信息
- hibernate的基本配置
- 映射文件的位置,以及映射文件中的配置
- 一些预定义的SQL语句(这些语句都是通用的) 比如:全字段保存,根据id的全字段更新,根据id的全字段查询,根据id的删除等等。由于JAVAEE是多线程的,这样做可以提供效率。
- hibernate的二级缓存(了解)
###常用方法
openSession();
每次都是生成一个新的Session
使用原则
由于SessionFactory维护了很多信息同时又是线程安全的,一般情况下,一个项目中只需要一个SessionFactory,只有当应用中存在多个数据源时,才为每个数据源建立一个SessionFactory实例。因此,不应该反复的创建和销毁。
原则:
一个应用应该只有一个SessionFactory。在应用加载时创建,应用卸载时销毁。
Session(非常重要)
作用
- Session是轻量级的,创建和销毁它都不会占用很多资源。在实际开发中会不断的创建和销毁Session对象。Session是一个单线程对象,它的作用为对象提供创建、删除、修改、读取方法。
- 获取Session的方式
- sessionFactory.openSession()
- sessionFactory.getCurrentSession(),这个方式需要配置session绑定当前线程
- 区别
- 采用openSession方法获取Session实例时,SessionFactory直接创建一个新的Session实例,并且在使用完成后需要调用close方法进行手动关闭。
- getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或回滚操作时会自动关闭。
###Session的常用方法
- save(Object entity); :保存一个实体到数据库
- update(Object entity);:更新一个实体
- delete(Object entity);:删除一个实体
- get(Class clazz,Serializable id);:根据id查询一个实体。参数的含义:Class表示要查询的实体类字节码。Serializable就是查询的条件。(立即加载)
- load(Class class,Serializable id) ;//根据一个id获取实体(延迟加载)
- beginTransaction();:开启事务,并返回事务对象
- getTransaction(); :获取事务
Session细节
- 它是一个轻量级对象。
- 是线程不安全的。
- 它维护了hibernate的一级缓存。
- 它的反复创建销毁不会消耗太多资源
Session使用原则
每个线程绑定一个Session
Transaction
###作用
Transaction接口主要用于管理事务,它是Hibernate的数据库事务接口,且对底层的事务接口进行了封装。Transaction接口的事务对象是通过Session对象开启的,其开启方式如下所示。
Transaction tx = session.getTransaction(); //该方式只是获取到了事务,并未开启事务,如果不开启事务,session的每个操作,都是独立的 //开启事务 tx.begin();
Transaction tx = session.beginTransaction(); //开启并返回事务
###常用方法
- begin():开启事务
- commit():提交事务
- rollback():回滚事务
- Session执行完数据库操作后,要使用Transaction接口的commit()方法进行事务提交,才能真正的将数据操作同步到数据库中。
- 发生异常时,需要使用rollback()方法进行事务回滚,以避免数据发生错误。因此,在持久化操作后,必须调用Transaction接口的commit()方法和rollback()方法。
- 如果没有开启事务,那么每个Session的操作,都相当于一个独立的操作。
第三方数据库连接池使用
C3P0连接池使用
导入c3p0相关jar包
c3p0-0.9.5.2.jar
mchange-commons-java-0.2.11.jar
导入c3p0和hibernate的整合包
hibernate-c3p0-5.4.1.Final.jar
在hibernate.cfg.xml中增加如下配置
<!--c3p0--> <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<?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>
<!-- 第一部分,数据库配置 -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/third_hibernate?serverTimezone=GMT%2B8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<!-- 第二部分,Hibernate的可选配置 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 第三部分,实体映射文件配置 -->
<mapping resource="com/fubo/entity/UserInfo.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
Druid数据库连接池
1.导入druid的相关jar包
2.在hibernate.cfg.xml中进行druid的配置,由于 Hibernate没有提供整合Druid的jar包。所以数据库连接信息的设置,要按druid的名称来设置
<?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> <!-- 第一部分,数据库配置 --> <property name="driverClassName">com.mysql.jdbc.Driver</property> <property name="url">jdbc:mysql://localhost:3306/third_hibernate?serverTimezone=GMT%2B8</property> <property name="username">root</property> <property name="password">123456</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property> <property name="connection.provider_class">com.alibaba.druid.support.hibernate.DruidConnectionProvider</property> <!-- 第二部分,Hibernate的可选配置 --> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 第三部分,实体映射文件配置 --> <mapping resource="com/fubo/entity/UserInfo.hbm.xml"></mapping> </session-factory> </hibernate-configuration>
Hibernate工具类编写
package com.fubo.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
Configuration configuration = new Configuration();
configuration.configure("/config/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
}
/**
* 使用工厂生产一个Session对象,
* 每次都是一个新的
* 此时Session还不符合开发的使用原则。
* @return
*/
public static Session openSession(){
return sessionFactory.openSession();
}
}
Hibernate实现CRUD
1.保存操作
public void testSave(){
Session session = HibernateUtil.openSession();
UserInfo user = new UserInfo();
user.setPassword("123");
user.setStatus(1);
user.setRealName("付波2");
user.setUsername("fubo2");
//4.开启事务
Transaction tx = session.beginTransaction();
//5.执行操作
session.save(user);
//6.提交事务
tx.commit();
//7.关闭资源
session.close();
}
2.获取一个实体,通过get方式
/**
* 根据id查询一个实体
*/
@Test
public void testFindOne(){
//1.使用工具类获取一个Session
Session session = HibernateUtil.openSession();
//2.开启事务
Transaction tx = session.beginTransaction();
//3.根据id查询
UserInfo c = session.get(UserInfo.class, 1);
System.out.println(c);
//4.提交事务
tx.commit();
//5.释放资源
session.close();
}
3.获取一个实体,通过load方式
/*
* 根据id查询一个实体
*/
@Test
public void testFindOne2(){
//1.使用工具类获取一个Session
Session session = HibernateUtil.openSession();
//2.开启事务
Transaction tx = session.beginTransaction();
//3.根据id查询
UserInfo c = session.load(UserInfo.class, 1);
System.out.println(c);
//4.提交事务
tx.commit();
//5.释放资源
session.close();
}
4.get和load的区别
1、查询的时机不一样
get方法任何时候都是立即加载,即只要一调用get马上发起数据库查询
load方法默认情况下是延迟加载,即真正用到对象的非OID字段数据才发起查询
load方法可以通过配置的方式改为立即加载。
配置的方式:
由于load方法是hibernate的方法所以只有XML的方式:
<class name="UserInfo" table="user_info" lazy="false">
2、返回的结果不一样
get方法永远返回查询的实体类对象。
load方法当是延迟加载时,返回的是实体类的代理对象。
立即加载:是不管用不用马上查询。
延迟加载:等到用的时候才真正发起查询。
\
5.获取多个实体
public static void testFindAll(){
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
//hql hibernate query lanaguage,里面的表名我们要换成实体名称,字段名换成属性名称,站位符后要加索引
Query query = session.createQuery("from UserInfo where id>?0");
query.setParameter(0,5);
List<UserInfo> list = query.list();
transaction.commit();
session.close();
}
6.修改实体
/**
* 修改一个实体
*/
@Test
public void testUpdate(){
//1.使用工具类获取一个Session
Session session = HibernateUtil.openSession();
//2.开启事务
Transaction tx = session.beginTransaction();
//3.根据id查询
UserInfo u = session.get(UserInfo.class, 1L);
u.setUsername("lisi");
//修改实体
session.update(u);
//4.提交事务
tx.commit();
//5.释放资源
session.close();
}
7.删除实体
/**
* 删除一个实体
*/
@Test
public void testDelete(){
//1.使用工具类获取一个Session
Session session = HibernateUtil.openSession();
//2.开启事务
Transaction tx = session.beginTransaction();
//3.根据id查询
UserInfo c = session.get(UserInfo.class, 1);
//删除实体
session.delete(c);//delete from cst_customer where cust_id = ?
//4.提交事务
tx.commit();
//5.释放资源
session.close();
}
获取一个Session
Session session = HibernateUtil.openSession();
//2.开启事务
Transaction tx = session.beginTransaction();
//3.根据id查询
UserInfo u = session.get(UserInfo.class, 1L);
u.setUsername(“lisi”);
//修改实体
session.update(u);
//4.提交事务
tx.commit();
//5.释放资源
session.close();
}
## 7.删除实体
```java
/**
* 删除一个实体
*/
@Test
public void testDelete(){
//1.使用工具类获取一个Session
Session session = HibernateUtil.openSession();
//2.开启事务
Transaction tx = session.beginTransaction();
//3.根据id查询
UserInfo c = session.get(UserInfo.class, 1);
//删除实体
session.delete(c);//delete from cst_customer where cust_id = ?
//4.提交事务
tx.commit();
//5.释放资源
session.close();
}