Hibernate 学习详解(1)

Hibernate 学习详解

Hibernate简介

在这里插入图片描述
Hibernate框架

简介
Hibernate 是数据持久化框架之一,也是一个开发源代码的ORM(对象关系映射) 解决方案;
Hibernate 内部封装了通过JDBC 访问数据库的操作,
创始人:Gavin King
EJB 3.0专家委员会成员,JBoss核心成员之一,《Hibernate in Action》的作者;
Hibernate是ORM解决方案
基于ORM HIbernate在对象模型——关系数据库之间建立了一座桥梁;
通过Hibernate 可以实现不在需要编写SQL语句操作关系型数据库中的表
使用APl 直接操作JavaBean对象就可以实现数据 存储 查询 更改 删除…提高了程序开发速度…

Hibernate的优缺点

优点:

  1. 简化了JDBC 繁琐的编码,提高持久化代码的开发速度, 降低了维护成本;
  2. 支持面向对象的特效:组合 继承 多态…使开发者不必在, 对象模型 数据模型之间来回切换;
  3. 可移植性好(对于多种数据库之间来回切换几乎不受影响), 开源免费!!

缺点:

  1. 不适合需要使用数据库的特定优化机制的情况
  2. 不适合大规模的批量数据处理 (底层固定的SQL对于高数据的查询不方便优化~)

Hibernate 和 Mybatis比较
都属于ORM框架,为数据层提供持久化操作的支持;

  1. Hibernate的ORM实现更加完善,提供了对象状态管理、级联操作等功能
  2. 完全面向对象,语句与数据库无关,开发者无需关注SQL的生成,开发简单,便于修改,数据库移植性好
  3. 由于直接使用SQL,MyBatis使用自由度较高方便调优

Hibernate框架搭建

部署JAR文件

Hibernate的官方网站http://hibernate.org   下载需要的jar文件;
推荐下载:hibernate-distribution-3.6.10.Final-dist.zip

Hibernate所需Jar文件

名称说明
antlr-2.7.6.jar语法分析器
commons-collections-3.1.jar各种集合类和工具类的封装
dom4j-1.6.1.jarXML读写
javassist-3.12.0.GA.jar分析,编辑和创建Java字节码类库
jta-1.1.jarJava事务Apl
slf4j-api-1.6.1.jar日期输出
hibernate-jpa-2.0-api-1.0.1.Final.jar提供JPA(Java持久化APl)规范的支持;

部署至Web项目 lib下…

创建Hibernate 核心配置文件 hibernate.cig.xml

Hibernate 配置文件主要用于配置数据库连接和 Hibernate运行时所需的各种特性。

用于配置数据库连接
运行时所需的各种特性
一般命名为 'hibernate.cfg.xml'   (MyElicpse对于创建核心配置文件有自带的DTD文件..)

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" >

<hibernate-configuration>
	
	<session-factory>
		<!-- 加载数据库驱动 -->
		<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> 
		<!-- 数据库URL -->
		<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property>
		<!-- 数据库用户 -->
		<property name="connection.username">用户名</property>
		<!-- 数据库用户密码 -->
		<property name="connection.password">密码</property>
		
		<!-- 每一个数据库都有其对应的方言(Dialect),以匹配其平台特性: MySQL Oracle 都遵循SQL语言,总有一些语法不一样 -->
		<property name="dialect">org.hibernate.dialect.OracleDialect</property> 
		<!-- 程序运行时输出SQL语句:可以在控制台中看到对应执行的真实SQL如果实在不会写了的话可以来借鉴 -->
		<property name="show_sql">true</property>
		<!-- 程序运行输出格式化的SQL语句 -->
		<property name="format_sql">true</property>
		<!-- 可选,指定getCurrentSession(); 得到的Session由谁来管理  thread值由当前线程管理; -->		
		<property name="current_session_context_class">thread</property>


		<!-- 引入所需的映射文件 -->
		<mapping resource="com/zb/entity/映射文件.xml"/>
		<mapping resource="..." />
		
	</session-factory>
</hibernate-configuration>

<!-- 
	这里使用的是Oracle
		oracle.jdbc.driver.OracleDriver 					Oracle驱动;
		jdbc:oracle:thin:@127.0.0.1:1521:全局数据库名		Oracle本地连接URl,orcl是全局数据库名;
 	current_session_context_class:
 		可以在多线程的应用环境中获得线程安全Session对象;
 		每个执行的线程首次调用 getCurrentSession();方法时,会为当前执行线程创建并保持一个线程;
		当前线程在次嗲偶 getCurrentSession();会返回该线程当前的Session对象; (保证了每个执行线程都是字节都有的Session对象)
		且,当关联的事务结束(提交/回滚),会自动关闭当前执行线程解绑;
 -->

创建持久化类 和 映射文件

完成了Hibernate 的核心配置文件, 之后就是要准备 持久化类和映射文件 l

持久化类
就是业务需求中的 实体类
注意:Hibernate 要求实体类必须有一个无参的构造函数,类实现 Serializable序列化接口;
映射文件
创建持久化类之后, 通过映射文件来告诉 Hibernate该类对应的是数据库这具体的
Hibernate 中, 映射文件通常与对应的持久化类同名已 .hbm.xml后缀

xxx.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>

	<class name="持久化类的全限定名" table="对应的数据库表名" >
		<!-- 表示数据库与实体类的,主键列对应 -->
		<id name="实体类属性名" type="java.lang.Integer" >  <!-- 对应Java类型 -->
			<column name="数据库主键列名"></column>
			<!-- 主键增长的方式  assigned:用户自己填写-->
			<generator class="assigned"></generator>
		</id>
		<property name="Java属性名" type="对应类型" >
			<column name="对应数据库列名"></column>
		</property>
		<!-- 其它元素配置.. -->
	</class>
</hibernate-mapping>
<!-- 
注意:
	Java区分大小写,name="Java类名注意大小写"  其实体类存在对应的 get/set();  可以通过鼠标悬浮Ctrl,验证是否成功!
	Hibernate通过 get/set();访问器实现... 
generator元素属性:
	assigned:	主键由应用程序负责生成,无须hibernate参与,没有指定generator 默认值;
	increment:	对应类型为 int short long的主键,已自动增长方式生成主键值 且持续递增每次+1;
	identity:	使用数据库自带的主键生成策略来实现...
	native:		由hibernate 根据底层数据库自行判断采用何种主键生成策略,即由使用的数据库生成主键的值;	
	 sequence:	对于Oracle DB2 等支持序列的数据库,可以使用其属性;
	 			<generator class="assigned">
					<param name="sequence"> 序列名 </param>
				</generator>
	 ....还有一些不常用属性..
-->

持久化类 映射文件定义完成之后, 别忘了核心配置文件引入: 映射文件;

使用Hibernate 完成持久化操作:

使用Hibernate 操作数据库包括七个步骤:

  1. 读取并解析配置文件及映射文件

    Configuration configuration = new Configuration().configure(“hibernate.cfg.xml”);
    // configure() :如果核心配置文件名为 hibernate.cfg.xml 可以省略。。。

  2. 依据配置文件 和映射文件信息, 创建SessionFactory对象;

    SessionFactory sessionFactory = configuration.buildSessionFactory();

    // configuration对象会根据当前数据库配置信息,构造除一个SessionFactory对象;
    // SessionFactory一旦构造完成, configuration就不会在影响 SessionFactory 对象;
    // 如果Hibernate 有改动,则需要根据改动后的 configuration 重新构建一个 SessionFactory 对象;

  3. 打开Session

    Session session = sessionFactory.openSession();

    session session = sessionFactory.getCurrentSession();
    // Session是Hibernate 持久化操作的基础,提供了众多持久化的操作 :
    // save() delete() update() get() load()…等

  4. 开始一个事务

    Transaction tx = session.beginTransaction();

  5. 数据库操作
    … … 增删改查 … …

  6. 结束提交事务

    一般是处理异常,根据情况:
    tx.commit(); 提交事务或 tx.rollback(); 回滚事务;

  7. 关闭资源

    session.close();
    // 如果Session是通过 openSession(); 获取的则需要手动关闭资源…
    // 如果通过getCurrentSession();获取的 核心配置文件中设置了: current_session_context_class 值thread;
    // 则会在关联的事务结束后,自动的关闭资源,一般很少使用…

SessionFactory工厂实现获取Session

在项目开发过程中,通常会使用工具类来管理SessionFactory 和 Session的关系…
HibernateUtil.java

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
	//静态属性;
	private static SessionFactory factroy;
	
	//静态代码块:类加载给工厂对象赋值;
	//类只加载一次,创建的工厂也只有一个!!
	static{
		Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
		factroy = configuration.buildSessionFactory();
	}
	//获取Session
	public Session openSession(){
		 return factroy.openSession();
	}
	//关闭资源
	public void closeSessionn(Session session){
		if(session!=null){
			session.close();
		}
	}
}

Hibernate实现增删改查:

为了方便讲解举例这里带上实例代码:
前言

这里使用Oracle数据库来操作,使用 Scott用户 密码是ok;
用户下的 DEPT系统表

-- 建一个和DEPT 结构一样的表:DEPT2 
create table dept2 
as 
select * from dept where 1=2; 

select * from dept2

insert into dept2 values(1,'人事','RS');
insert into dept2 values(2,'研发','YF');
insert into dept2 values(3,'技术','JS');

在这里插入图片描述

搭建Hibernate框架:

在这里插入图片描述
这里没有使用三层…只有Dao 借鉴学习即可…

导入Jar
核心配置文件

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" >

<hibernate-configuration>
	
	<session-factory>
		<!-- 加载数据库驱动 -->
		<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> 
		<!-- 数据库URL -->
		<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property>
		<!-- 数据库用户 -->
		<property name="connection.username">scott</property>
		<!-- 数据库用户密码 -->
		<property name="connection.password">ok</property>
		
		<!-- 每一个数据库都有其对应的方言(Dialect),以匹配其平台特性: MySQL Oracle 都遵循SQL语言,总有一些语法不一样 -->
		<property name="dialect">org.hibernate.dialect.OracleDialect</property> 
		<!-- 程序运行时输出SQL语句 -->
		<property name="show_sql">true</property>
		<!-- 程序运行输出格式化的SQL语句 -->
		<property name="format_sql">true</property>
		
		<!-- 引入所需的映射文件 -->
		<mapping resource="com/wsm/entity/Dept.hbm.xml"/>
		
	</session-factory>
</hibernate-configuration>
数据持久化类 及其 核心配置文件;

Dept.java数据持久化类

import java.io.Serializable;

//实体类:实现接口Serializable 
	//这并不是Hibernate所必须的,为了方便用于数据传输等用途时正确的执行序列化操作;
public class Dept implements Serializable {		
	//必须提供的无参构造
	public Dept(){
	}
	
	//属性
	private Integer deptno;
	private String dname;
	private String loc;
	
	//get/set
	public Integer getDeptno() {
		return deptno;
	}
	public void setDeptno(Integer deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
	//重新toString();
	@Override
	public String toString() {
		return "Dept [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
	}	
}

Dept.hbm.xml核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>

	<class name="com.wsm.entity.Dept" table="dept2">
	
		<id name="deptno" type="java.lang.Integer">
			<column name="DEPTNO"></column>
			<!-- 主键增长的方式  assigned:用户自己填写-->
			<generator class="assigned"></generator>
		</id>
		
		<property name="dname" type="string">
			<column name="DNAME"></column>
		</property>
		
		<property name="loc" type="string">
			<column name="loc"></column>
		</property>
	</class>
	
</hibernate-mapping>
Util工具类

HibernateUtil.java可以借鉴上面…


增删改查开始…
这里的关键代码写在DeptDao.Java:

import org.hibernate.Session;
import com.wsm.entity.Dept;
import com.wsm.util.HibernateUtil;

public class DeptDao {
	//创建hibernateutil 工具对象;
	private HibernateUtil hibernateUtil = new HibernateUtil();
}

使用Hibernate实现主键查询

Hibernate提供了两种方法加载对象: get() 和 load()方法;

  • Object get( Class clazz, Serializable id );
  • Object load( Class clazz, Serializable id );
get();

DeptDao.Java

	//根据主键当前对象 get
	public Dept selget(Integer id){
		//获取Session
		Session session = hibernateUtil.openSession();
		Dept dept = (Dept) session.get(Dept.class, id);		//查询
		//关闭资源
		hibernateUtil.closeSessionn(session);
		
		return dept;
	}

使用Session 的get(); 方法根据主键查询数据时, 如果数据库中没有对应数据;
get(); 方法返回结果为 null;

load();

DeptDao.Java

	//根据主键当前对象 load
	public Dept selload(Integer id){
		Session session = hibernateUtil.openSession();
		Dept dept = (Dept) session.load(Dept.class, id);	
		//关闭资源
		//hibernateUtil.closeSessionn(session);			注释了关闭资源...
		return dept;
	}

可以看到使用 load(); 方法和get() 几乎相同;
唯一不同: 注释了关闭资源… 因为load()方法访问数据库, 属于的是懒加载机制 ;
即: 用的时候才做查询…如果不用则不做…而提前关闭了资源. 无法完成数据库交互查询…所以不可以关闭资源…
如果数据表中不存在对应数据, 会抛出异常!!

使用Hibernate实现数据库 增删改;

增 save();

Test.java

	// 原生新增:增一条Dept
	public void save(){
		Dept dept = new Dept();
		dept.setDeptno(4);
		dept.setDname("运维");
		dept.setLoc("YW");

		// 读取并解析配置文件及映射文件
		Configuration configuration = new Configuration().configure(); // "hibernate.cfg.xml"
																		// 核心配置文件名为,可以不参数指定;
		// 依据配置文件 和映射文件信息, 创建SessionFactory对象;
		SessionFactory sessionFactory = configuration.buildSessionFactory();
		// 打开Session
		Session session = sessionFactory.openSession();
		// 开始一个事务
		Transaction tx = session.beginTransaction();

		try {
			// 数据库操作: 新增save();
			session.save(dept);				// ALT+SHift+z 快速给选中行添加try-catch...
			tx.commit();
			System.out.println("新增成功"); // 提示新增成功;
		} catch (HibernateException e) {
			// 回滚事务;
			tx.rollback();
		}
		// 关闭资源
		session.close();
	}

save(Object);
数传入 操作表对应的 实体类对象;
根据对象的属性值, 进行对应的新增…

删 delete();

DeptDao.java

	//删除:参数要删除的数据; Hibernate是以面向对象方式实现的 数据持久化...
	public void deleteDept(Integer id){
		Session session = hibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Dept dept = new Dept();
		dept.setDeptno(id);			
				
		try {
			session.delete(dept);	//封装对象数据,要删除的id;
			tx.commit();			//成功提交事务
			System.out.println("删除成功!");
		} catch (HibernateException e) {
			tx.rollback(); 			//失败回滚;
			System.out.println("删除失败!");
		}  
		//关闭资源;	
		hibernateUtil.closeSessionn(session);	
	}

.delete(Object);
参数传入 操作表对应的 实体类对象;
给对象属性赋值, Hibernate底层自动生成SQL语句; 属性作为删除的条件…进行删除;

改(两种) update(Object) / Setxx(xx) ;
update(Object)

DeptDao.java

		//session.update(Object);
		//修改1 根据传入的dept来进行修改;
		public void updateDept(Dept dept){
			Session session = hibernateUtil.openSession();
			Transaction tx = session.beginTransaction();
		
			try {
				session.update(dept);
				tx.commit();
				System.out.println("修改成功");
			} catch (HibernateException e) {
				tx.rollback();
				System.out.println("修改失败");
			}
			hibernateUtil.closeSessionn(session);
		}

session.update(Object);
注意: 传入参数(对应持久类的对象) ,其主键属性必须需要赋值, 不然执行不成功!!

Setxx(xx);

DeptDao.java

	//修改2 使用Setxx() 进行修改
	public void setDept(Integer id){
		System.out.println("三态修改...");
		
		Session session = hibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Dept dept = (Dept)session.load(Dept.class,id);
		
		//根据三态原则进行修改;
		try {
			dept.setDname("修改");
			tx.commit();
			System.out.println("修改成功");
		} catch (Exception e) {
			tx.rollback();
			System.out.println("修改失败");
		}
		hibernateUtil.closeSessionn(session);
	}

三态进行修改Setxx(xx)
使用该方法修改数据时, 首先要加载对象, 然后通过修改对象的属性。最后提交事务;
Hibernate 会生成并执行修改SQL语句; (Hibernate三态原则)

Hibernate中Java对象的三种状态(三态)

瞬时状态

瞬时状态又称临时状态:
Java对象与数据库中的数据, 没有任何的关联; (此时的Java对象状态为瞬时状态)
Session 对于瞬时状态的Java对象是一无所知的, 当Java对象不在被其它对象引用时, 被虚拟机回收~

持久状态

当Java对象与Session关联时,就处于持久状态(该状态下的对象, 同时对应着数据库中的一条记录)
处于持久状态的Java对象, Session会持续跟踪和管理它们, 如果对象的内部结构发生了任何改变;
Hibernate 会选择合适的时机(事务提交~), 将对象的变更与数据库实时同步~ 着就是Setxx(); 之所以可以完成修改的原因!!

游离状态

游离状态:又称托管状态, Session放弃或不足管理Java对象, 此时的对象处于了游离状态;
没有了Session的跟踪监视管理, 此时调用Setxx(); 就不会自动同步修改数据了…

在这里插入图片描述

三种状态之间的转换

瞬时——持久
执行Session的 save() saveOrUpdate() 等方法保存对象时候,该对象有瞬时状态转换为持久状态;
执行Session 的 get() load() 方法获取对象, 该对象就处于持久状态;
持久——瞬时
执行Session 的 delete() 方法持久状态的对象转换为瞬时状态
持久——游离
执行Session调用 evict() clear() close() 对象有原来的持久转换为游离状态;
游离——持久
执行Session 的update() saveOrupdate() 方法, 对象由游离状态转换为持久
游离——瞬时
执行Session的 delete() 对象由游离转换为瞬时…

脏检查 与 刷新缓存机制

脏检查

Hibernate 中, 数据前后发生变化的对象, 称为脏对象;
当一个 Java对象被Session管理时候, Hibernate会对对象进行检测保存;
以判断对象属性,是否发生变化, 这种判断称为脏检测
如果对象发生改变,Session会根据脏对象的值进行比较, 将最新数据存储到数据库中…

刷新缓存机制

Session中的对象属性发生改变时,Session并不会立即执行脏检查相关的SQL语句; 而是在特定的时间(刷新缓存时执行)
优点
当对象属性进行多次更改,而Hibernate不会每次都进行匹配修改 ,而是在最后一次执行一次SQL进行数据匹配;
提高应用程序的数据访问性能;
Session.flush() 和 事务提交可以立即执行脏检查进行数据校验!!

Session的其它方法

saveOrUpdate()

saveorUpdate(Objext) 同时包含了 save() 和 Update() 功能, 如果入参对象是瞬时状态就新增,游离状态就修改;
即: 如果数据库中存在对应的数据, 修改 | 新增;
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java.慈祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值