Hibernate的事务管理 ---- Hibernate入门学习

叙:本章中本人开始并不算熟悉,因此,我细致的梳理了一遍,可能会显得东西有些多,但是却是事务这个知识点比较全面、深入检出的笔记;

Hibernate事务管理

学习hibernate的事务管理前首先学习一下什么是事务?事务中存在哪些问题?如何解决的?这些都是事务的基础知识,其后才是hibernate的事务管理设置;

事务基础

什么是事务
事务在Java中就是指一个逻辑上的一组操作,组成这个逻辑的逻辑单元要么全部完成,要么全部失败;

事务的特性

  1. 原子性:代表事务是不可分割的,要么同时完成要么同时失败,存在例外;
  2. 一致性:代表数据执行前后数据保持一致,例如:甲乙买卖,最终两个人的钱和货物相加还是原始量,不会有不明下落的数据;
  3. 隔离性:意思是指一个事物的执行过程中不应该和其他的事务有交集;
  4. 持久性:代表事务执行完后,数据就会被持久存放到数据库中,不会被执行过的事务所调用;

在事务的特性中重点需要了解的是事物的隔离性,下面进行详细了解;

如果不考虑事务的隔离,会导致的问题:

隔离的目的是为了解决不同的事务同时并发的情况所会存在的问题,防止事务间的相互影响;如果不考虑事务的隔离,则会引发多种问题,总结为两大类,分别是读的问题和写的问题;

读的问题:
1)脏读:是指事物读B到事务A未提交的数据 — 既是:事务B读到的是事务A可能要提交也可能要回滚的数据;
2)不可重复度:是指事务A在进行操作数据并且读取到了数据,而此时事务B突然插队进来也操作数据,并且在A事务提交前进行了事务提交,则会导致事务A读取前后的数据不一致和操作不成功;
3)虚读(幻读):事务A开始操作数据库,把表中数据全部修改成某种样式的,但与此同时,事务B也在修改数据表,数据B的是添加一条原始样式的数据,在两个人都提交后,表中只有一条数据是原始样式的,当事务A回头查看时会发现又一条数据没有修改成新样式;

注意:这个幻读和不可重复度很容易搞混;
辨析:幻读是指之前查询不存在的,中途被其他事务添加了,再次查询却出现了,而不可重复度是指之前查询存在的,中途被其他事务修改了,再次查询却不同了;区别点就在于第一个事务第一次查询是否存在这个数据;

写的问题(了解即可)

  1. 引发丢失更新
    A事务在回滚时把B事务已经提交的更新数据也给回滚了(当然也有可能是A事务提交后覆盖了B事务的更新操作,导致需要的事务B操作的丢失了更新的结果,不一定非要是回滚,只是回滚更方便理解)!

事务的解决 — 事务的隔离级别

设置事务隔离级别(4种):

隔离级别名称隔离读取级别解决问题级别
Read uncommitted读取未提交的数据以上的读问题都会发生
Read committed读取已提交的数据除脏读其他均可能发生
Repeatable read读取到已经修改过的只有幻读可能会发生
Serializable读问题都可以解决串行化序列执行(例:排队上厕所,一个出来后另一个才能用)效率太低

隔离级别处理问题能力表:
隔离级别处理问题能力表
Oracle使用的是 read committed 的隔离级别来配置事务管理;
MySQL使用的是 repeatable read 的隔离级别来配置事务管理;


事务进阶 — hibernate中设置隔离级别

上面回顾了不隔离导致的问题以及各个隔离级别的作用范围等,现在学习在hibernate中如何设置隔离级别;

hibernate中设置事务的隔离级别
首先,要知道hibernate中设置事务的隔离级别是在核心配置文件中进行的,其次,所使用的标签以及标签所对应的属性值,具体介绍如下:
在核心文件配置中的<session-factory></session-factory>标签内进行定义的,所使用的方法举例为<property name=”hibernate.connection.isolation”>4</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>
		<!--连接数据库的基本参数 -->
		<!-- 方言 。。。 dialect -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property>
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day02</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">root</property>

		<!-- 可选配置 -->
		<property name="hibernate.show_sql">true</property>
		<property name="hibernate.format_sql">true</property>
		<property name="hibernate.hbm2ddl.auto">update</property>
		
		<!-- 配置隔离级别 -->
		<property name="hibernate.connection.isloation">4</property>
		
		<!-- 引入orm数据源路径 -->
		<mapping resource="com/java/demo/Customer.hbm.xml" />
	</session-factory>
</hibernate-configuration>

配置标签、属性什么的都好说,只要记住就好,主要注意的是标签中间的数字,例中是4,还有其他的1,2,8;这些数字代表的是其对应的隔离级别,具体介绍如下:

隔离级别对应数值隔离级别名称备注
1read uncommitted
2read committedOracle使用的隔离级别
4repeatable readMySQL使用的隔离级别
8serializable

以上就是核心配置文件中的配置方法,配置完核心配置中的后需要使用,具体的是service层在使用;

Service层事务

事务管理等是在Service层的,事务层 = Service层;
为什么要把事务加在Service层?
答:三层架构,Web层、Service层、Dao层;Dao层里封装的是一个个对数据源单一操作的方法,每个对数据的增删改查的业务要分为四个方法,每个方法都要重新创建一个单独的连接(Hibernate中的是Session,JDBC中的是Connection),这样不便于业务逻辑的管理;而在service层中封装的是一个业务逻辑操作(最少两个的对数据源操作的Dao层方法,就比如转账的业务逻辑,由转出方扣钱和转入方加钱的业务统一成一个业务逻辑),service层便于此业务逻辑的事物管理;

回顾事务管理在service层中:
Service层事务管理管理的是一个业务逻辑,其中连接Dao层的多个对数据源单一操作的方法,这样的话就需要使用同一个连接,这个连接在Hibernate中就是Session。
在JDBC中使用的有两种方法,一种是在Service层创建完后传递给Dao层,Dao层的进行调用创建好的同一个连接,第二种是使用ThreadLocal(线程本地变量/线程本地储存)对象,这个对象的原理是将连接保存到线程中,通过线程来传递连接到Dao层;
Hibernate中的事务管理:
在Hibernate框架中提供的有已绑定好的ThreadLocal,存在于SessionFactory中,方法名叫做getCurrentSession(),此方法默认是关闭的,需要手动设置打开,操作方法:

  1. 工具类;向生成一般的Session对象所在的工具类中添加可以生成getCurrentSession()方法;添加部分如下所示:
package com.java.hibernate.Utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/*
 * hibernate生成session的工具类
 */
public class HibernateUtils {
	
	public static final Configuration conf;
	public static final SessionFactory sf;
	
	static{
		//加载读取核心配置文件对象
		conf = new Configuration().configure();
		//使用核心配置文件对象创建Session工厂,生成链接session连接对象
		sf = conf.buildSessionFactory();
	}
	
	public static Session openSession(){
		return sf.openSession();
	}
	//添加 --- 生成线程session代码
	public static Session getCurrentSession(){
		return sf.getCurrentSession();
	}
}
  1. 配置允许使用getCurrentSession()方法的操作;在核心配置文件中进行配置,配置如下所示:
<property name="hibernate.current_session_context_class">thread</property>

其属性有三个,分别是:
(1) Thread:Session对象生命周期与本地线程绑定!!!
(2) jta:Session对象生命周期与JTA事务绑定(跨数据库事务);
(3) managed: Hibernate委托程序来管理session生命周期;
3) 测试

@Test
public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction bt = session.beginTransaction();
		
		Customer cust = session.load(Customer.class, 1l);
		System.out.println(cust);
		
		bt.commit();
	}

能通过就算成功

注意:在使用此方法进行操作时后不需要有释放资源的操作(即:session.close()),因为线程会自动关闭一次,如果自己再手动关闭Session就会报错;


《本章完》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清风暖云

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

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

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

打赏作者

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

抵扣说明:

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

余额充值