顶级架构师学习——第十八阶段:数据库管家Hibernate

25 篇文章 2 订阅
8 篇文章 0 订阅

Hello,今天要学习的是Hibernate,我把它称之为数据库管家,嘿嘿ヾ(≧O≦)〃嗷~

目录

一、Hibernate简介

二、Hibernate入门

三、Hibernate的API详解

四、Hibernate进阶


一、Hibernate简介

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。

我们通过一张图来展示一下什么是Hibernate框架吧!

简单的说,Hibernate就是帮我们从繁琐的sql操作当中解放出来的~~

我们为什么要使用Hibernate呢?

我们使用传统的jdbc进行开发应用系统时,如果是小型系统,并不会觉得有什么麻烦。然而当我们开发大型应用系统时,jdbc就会显得有些力不从心。比如说对于几十甚至上百张表进行操作时,编写的sql语句不仅长而且繁琐,容易出错且工作量巨大。为了提高数据访问层的变成效率,一种流行的ORM架构应运而生,这就是我们的Hibernate框架。

ORM指的时Object Relation Mapping(对象关系映射),它共分为四级,Hibernate属于第四级的ORM架构,它完全面向对象操作数据库。开发人员仅需关注一段的映射,其他的数据库操作均由Hibernate框架负责解决,极大的减少了代码数量,并且优化了内存,加快了运行效率。同时它也具有极强的可扩展性,有很多开源的代码可以直接使用来实现各种不同的附加功能,当然,你自己也可以编写相应的扩展代码来实现自己的业务需求。

二、Hibernate入门

1、框架搭建

我们从官网下载最新的Hibernate压缩包,解压后的目录情况如下:

我们在javaee工程中引入Hibernate的jar包以及mysql的数据库驱动包,导入相应的dtd约束(hibernate-configuration-3.0.dtd和hibernate-mapping-3.0.dtd)。

OK!

2、创建数据库及示例表

3、修改配置文件

  1.orm元数据(Customer.hbm.xml)

<!-- 1、根元素 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.itheima.domain" >


<!-- 2、class元素 -->
<!-- 
	class元素: 配置实体与表的对应关系的
		name: 完整类名
		table:数据库表名
 -->
<class name="Customer" table="cst_customer" >


<!-- 3、id元素 -->
<!-- id元素:配置主键映射的属性
		name: 填写主键对应属性名
		column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
		type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
				每个类型有三种填法: java类型|hibernate类型|数据库类型
		not-null(可选):配置该属性(列)是否不能为空. 默认值:false
		length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
 -->
<id name="cust_id"  >

<!-- property元素 -->
<!-- property元素:除id之外的普通属性映射
		name: 填写属性名
		column(可选): 填写列名
		type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
				每个类型有三种填法: java类型|hibernate类型|数据库类型
		not-null(可选):配置该属性(列)是否不能为空. 默认值:false
		length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
 -->
<property name="cust_name" column="cust_name" >

  2.Hibernate主要配置(hibernate.cfg.xml 文件的名字不要改!!!默认的文件名)

<!-- 必选属性配置 -->
<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
 <!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_32</property>
 <!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">root</property>
 <!-- 数据库连接密码 -->
<property name="hibernate.connection.password">1234</property>
<!-- 数据库方言
	不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
	sql99标准: DDL 定义语言  库表的增删改查
			  DCL 控制语言  事务 权限
			  DML 操纵语言  增删改查
	注意: MYSQL在选择方言时,请选择最短的方言.
 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 可选属性配置 -->
<!-- 将hibernate生成的sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成的sql语句格式化(语法缩进) -->
<property name="hibernate.format_sql">true</property>
<!-- 
## auto schema export  自动导出表结构. 自动建表
#hibernate.hbm2ddl.auto create		自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
#hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
#hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
#hibernate.hbm2ddl.auto validate	校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
 -->
<property name="hibernate.hbm2ddl.auto">update</property>

<!-- 元数据引入 -->
<!-- 引入orm元数据
    路径书写: 填写src下的路径
-->
<mapping resource="cn/itheima/domain/Customer.hbm.xml" />

4、Demo

这个Demo我们尝试保存一个新用户到我们的表当中。

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import cn.itheima.domain.Customer;

//测试Hibernate框架
public class Demo {

	@Test
	//保存客户
	public void fun1(){
		Configuration conf = new Configuration().configure();
		
		SessionFactory sessionFactory = conf.buildSessionFactory();
		
		Session session = sessionFactory.openSession();
	
		Transaction tx = session.beginTransaction();
		//----------------------------------------------
		Customer c = new Customer();
		c.setCust_name("google公司");
		
		session.save(c);//执行保存
		
		//----------------------------------------------
		tx.commit();
		session.close();
		sessionFactory.close();
	}
}

三、Hibernate的API详解

我们以上面的API为引,展示了如何使用Hibernate框架快速的操作数据库,接下来我们详细的介绍一下Hibernate的API。

1、Configuration

// 1 创建,调用空参构造
Configuration conf = new Configuration();

// 2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
conf.configure();

// 3 读取指定orm元数据(扩展),如果主配置中已经引入映射配置.不需要手动加载
//conf.addResource(resourceName);
//conf.addClass(persistentClass);

// 4 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();

2、SessionFactory

// SessionFactory功能: 用于创建操作数据库核心对象session对象的工厂.
//					 简单说功能就一个---创建session对象
// 注意:1.sessionfactory 负责保存和使用所有配置信息.消耗内存资源非常大.
//	  2.sessionFactory属于线程安全的对象设计.
// 结论: 保证在web项目中,只创建一个sessionFactory.

// 4 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();

// 5 获得session
// 打开一个新的session对象
sf.openSession();

// 6 获得一个与线程绑定的session对象
sf.getCurrentSession();

3、Session

// 学习Session对象
// session对象功能: 表达hibernate框架与数据库之间的连接(会话).session类似于
//				JDBC年代的connection对象. 还可以完成对数据库中数据的增删改查操作.
//				session是hibernate操作数据库的核心对象

// 1 创建,调用空参构造
Configuration conf = new Configuration().configure();

// 2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();

// 3 获得session
Session session = sf.openSession();

// 4 session获得操作事务的Transaction对象
// 获得操作事务的tx对象
// Transaction tx = session.getTransaction();
// 开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();

// 增删改查操作
// 增
Customer c = new Customer();
c.setCust_name("传智播客");
session.save(c);
// 查
Customer customer = session.get(Customer.class, 1l);
// 改
Customer c = session.get(Customer.class, 1l);
c.setCust_name("黑马程序员");
session.update(c);
// 删
Customer c = session.get(Customer.class, 1l);
session.delete(c);

tx2.commit();//提交事务
tx2.rollback();//回滚事务
session.close();//释放资源
sf.close();//释放资源

4、Transaction

//获得操作事务的tx对象
//Transaction tx = session.getTransaction();
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();

四、Hibernate进阶

1、实体规则

  1.实体类创建的注意事项

    · 持久化类提供无参构造

    · 成员变量私有,提供公有get/set方法访问,称为属性

    · 持久化类中的属性,应尽量使用包装类型

    · 持久化类中需提供与数据库中主键对应的id

    · 不要使用final修饰class

  2.主键类型

    · 自然主键:这个在业务当中比较少见,它要求业务本身具有至少一个唯一且与业务相关的属性

    · 代理主键:我们人为的创建的一种必须有且不重复的特征

  3.主键生成策略

    · sequence:Oracle数据库使用的一种主键生成策略

    · hilo:采用高低位算法实现主键自增,也是由hibernate维护的,开发当中一般不使用

    · identity:由数据库本身维护的一种主键自增

    · native:自动从前面所说的三种策略中根据数据库本身选择其中一种

    · uuid:生成随机字符串作为主键,主键类型必须为String类型

    · increment:hibernate维护的一种主键自增,每次插入前会查询表内最大的id值,自增1后作为新的主键值插入

    · assigned:自然主键生成策略,由开发人员手动输入

2、对象状态

对象分为三种状态:瞬时状态(无id,不在session缓存中),持久化状态(有id,在session缓存中),游离状态(有id,不在session缓存当中)

我们使用Hibernate的其中一个目的便是将对象转化为持久化状态

三种状态的转换关系如下图:

3、一级缓存

与我们电脑使用缓存的目的相似——提高操作数据库效率!

使用缓存有两种方式:

  1.提高查询效率

  2.减少不必要的修改语句发送(快照)

4、事务

Hibernate中的事务与数据库的事务相同,同样具备ACID特性,有着同样的事务隔离级别。

我们在hibernate的配置文件当中对事务的隔离级别进行配置:

<!-- 指定数据库的隔离级别 
    #hibernate.connection.isolation 1|2|4|8
    0001 1 读未提交
    0010 2 读已提交
    0100 4 可重复读
    1000 8 串行化
-->
<!-- 数据库默认为可重复读级别,串行化虽然能够完全解决脏读、不可重复读、幻读等问题,但效率太低! -->
<property name="hibernate.connection.isolation">4</property>

我们如何在项目当中管理事务呢?

我们在dao层和service层都在使用session对象完成对数据库的操作,因此,为了保证我们能够获取到同一个session,我们在开发当中仅需要调用sessionFactory.getCurrentSession()方法即可获得与当前线程绑定的session对象。我们通过这个方法获得的session在事务提交之后会自动关闭,而不要我们手动关闭。

5、批量查询

Hibernate中的批量查询有三种方法:HQL查询、Criteria查询、原生SQL查询。下面我们来一一介绍:

  1.HQL查询

从名字当中我们也可以猜出来,HQL查询是Hibernate独家的查询语言,属于面向对象的查询语言,它适用于不很复杂的多表查询。


// 1 获得session
Session session = HibernateUtils.openSession();
// 2 控制事务
Transaction tx = session.beginTransaction();
// 3 执行操作
//-------------------------------------------

// 基本查询
// 1> 书写HQL语句
//		String hql = " from cn.itheima.domain.Customer ";
String hql = " from Customer "; // 查询所有Customer对象
// 2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
// 3> 根据查询对象获得查询结果
List<Customer> list = query.list();	// 返回list结果
// query.uniqueResult();//接收唯一的查询结果

// 条件查询
//1> 书写HQL语句
String hql = " from Customer where cust_id = 1 "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();

// 带占位符的条件查询
//1> 书写HQL语句
String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
//query.setLong(0, 1l);
query.setParameter(0, 1l);
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();

// 分页查询
//1> 书写HQL语句
String hql = " from Customer  "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置分页信息 limit ?,?
query.setFirstResult(1);
query.setMaxResults(1);
//3> 根据查询对象获得查询结果
List<Customer> list =  query.list();

//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联

  2.Criteria查询

Criteria是Hibernate自创的一种无语句面向对象查询。

// 基本查询
//查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();

// 条件查询
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//添加查询参数 => 查询cust_id为1的Customer对象
criteria.add(Restrictions.eq("cust_id", 1l));
//执行查询获得结果
Customer c = (Customer) criteria.uniqueResult();
System.out.println(c);

// 分页查询
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置分页信息 limit ?,?
criteria.setFirstResult(1);
criteria.setMaxResults(2);
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);

// 查询总记录数
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询的聚合函数 => 总行数
criteria.setProjection(Projections.rowCount());
//执行查询
Long count = (Long) criteria.uniqueResult();
System.out.println(count);

  3.原生SQL查询

//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------

// 基本查询
//1 书写sql语句
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//3 调用方法查询结果
// 返回数组List
List<Object[]> list = query.list();
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
// 返回对象List
List<Customer> list = query.list();
System.out.println(list);

// 条件查询
//1 书写sql语句
String sql = "select * from cst_customer where cust_id = ? ";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, 1l);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);

// 分页查询
//1 书写sql语句
String sql = "select * from cst_customer  limit ?,? ";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, 0);
query.setParameter(1, 1);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);

//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联

6、数据表的一对一&多对一&多对多

数据库中表的三种关系由下图给出:

实体表之间的映射关系在数据库当中是由外键来描述的。

一对多的建表原则:在多的一方创建外键指向一的一方的主键。

多对多的建表原则:创建一个中间表,中间表至少两个字段作为外键分别指向两张表的主键。

一对一的建表原则:唯一外键对应(同一对多,但外键唯一)或主键对应(一方的主键作为另一方的主键)。

相应的xml文件配置如下:

<!-- 集合,一对多关系,在配置文件中配置Customer.hbm.xml -->
<!-- 
	name属性:集合属性名
	column属性: 外键列名
	class属性: 与我关联的对象完整类名
 -->
<!-- 
级联操作:	cascade
	save-update: 级联保存更新
	delete: 级联删除
	all: save-update + delete
级联操作: 简化操作,目的就是为了少写两行代码.
-->
<!-- inverse属性: 配置关系是否维护. 
	true: customer不维护关系
	false(默认值): customer维护关系
	
inverse属性: 性能优化.提高关系维护的性能.
原则: 无论怎么放弃,总有一方必须要维护关系.
一对多关系中: 一的一方放弃,也只能一的一方放弃,多的一方不能放弃.
多对多关系中:一定要有一方放弃维护关系!
-->
<set name="linkMens" inverse="true" cascade="delete"  >
	<key column="lkm_cust_id" ></key>
	<one-to-many class="LinkMan" />
</set>

<!-- 多对一LinkMan.hbm.xml -->
<!-- 
	name属性:引用属性名
	column属性: 外键列名
	class属性: 与我关联的对象完整类名
 -->
<many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
</many-to-one>

今天的内容就到这里~~~

我是小昶,明天见啦o(*^@^*)o

日常推一推我们的公众号:落饼枫林,有需要相关代码的请在后台留言呢~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值