Hibernate入门第七讲——Hibernate中的事务管理

回顾事务

什么是事务?

事务就是逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功,要么全都失败。

事务的四个特性

Hibernate入门第七讲——Hibernate中的事务管理_第1张图片

不考虑事务的隔离性,会产生什么问题?

如果不考虑事务的隔离性,那么就会产生如下问题:

  • 脏读:一个事务读取到了另一个事务的未提交数据;
  • 不可重复读:一个事务读取到了另一个事务提交的数据(主要是指update操作),会导致两次读取的结果不一致;
  • 虚读(也叫幻读):一个事务读取到了另一个事务提交的数据(主要是指insert操作),会导致两次(也有可能是多次)读取结果不一致。

对于上述问题如何解决?

我们可以通过设置隔离级别来解决上述问题:
Hibernate入门第七讲——Hibernate中的事务管理_第2张图片
常见数据库的默认级别:

  • Oracle默认的事务隔离级别是READ_COMMITTED;
  • 而MySQL默认的事务隔离级别是REPEATABLE_READ。

Hibernate中的事务管理

Hibernate中设置事务隔离级别

事务回顾完之后,我们已经知道了通过设置事务的隔离级别来解决不考虑事务的隔离性会产生的问题,那么你不仅要问,在Hibernate中如何设置事务的隔离级别呢?Hibernate框架中可通过hibernate.connection.isolation属性来设置事务的隔离级别,它可取的值有1、2、4、8。
Hibernate入门第七讲——Hibernate中的事务管理_第3张图片
在Hibernate框架中设置事务的隔离级别,可在hibernate.cfg.xml核心配置文件中添加如下配置:
在这里插入图片描述

Hibernate解决Service层的事务管理

要想进行事务管理的话,我们都知道事务都是加在Service层的,也就是说事务通常也被称之为是Service层的事务,为什么要把事务加在业务层呢?至于要说明白这个事情,那又是一篇长篇累牍了,而且要解释通,说得清楚明白,还挺难的,幸好我之前记录过有关的内容,如果你感兴趣的话,可以参考我写的《Java Web基础入门第六十二讲 JDBC应用中的事务管理》这篇文章,懒得看的话,那你就一定要记住事务都是加在Service层上的。
第二个问题又来了,Hibernate是如何解决Service层事务管理的呢?Hibernate提供了三种管理Session的方式,在Hibermate的核心配置文件中,hibernate.current_session_context_class属性就是用于指定Session的管理方式的,该属性的可选值包括:

  • thread:Session对象的生命周期与本地线程绑定。本地线程绑定Session这种方式的大概内部原理可用下图来表示:
    Hibernate入门第七讲——Hibernate中的事务管理_第4张图片
  • jta:Session对象的生命周期与JTA事务(即跨数据库的事务,啥叫跨数据库的事务呢?我打个比方,比如说我往MySQL中执行了一个操作,又往Oracle里面也执行了一个操作,这个时候,我要保证它俩在一个事务里,这时就有可能需要用到JTA事务了)绑定;
  • managed:Hibernate委托程序来管理Session对象的生命周期。

我们之前一直所使用的都是第三种方式,即通过程序获取一个Session对象,然后使用它,最后关闭它,即session.close()。在实际开发中我们一般使用的是前两种,但由于第二种方式是基于分布式数据库而言的,所以在此主要介绍关于本地线程绑定Session的这种方式。你要是想使用这种方式在Hibernate中解决Service层的事务管理,那么就需要在hibernate.cfg.xml核心配置文件中添加如下配置:
在这里插入图片描述
然后,通过SessionFactory的getCurrentSession()方法获得与本地线程绑定的Session对象,这样一来,咱的HibernateUtils工具类就要修改为:

package com.meimeixia.hibernate.utils;

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

public class HibernateUtils {

	public static final Configuration cfg;
	
	public static final SessionFactory sf;//一个项目只会创建一个SessionFactory对象
	
	static {
		cfg = new Configuration().configure();
		sf = cfg.buildSessionFactory();
	}
	
	public static Session openSession() {
		return sf.openSession();
	}
	
	public static Session getCurrentSession() {
		return sf.getCurrentSession();
	}
	
}

最后,我们来编写程序测试当前与线程绑定的Session。

package com.meimeixia.hibernate.demo01;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.meimeixia.hibernate.utils.HibernateUtils;

/**
 * 测试当前线程绑定的Session
 * @author liayun
 *
 */
public class HibernateDemo04 {

	@Test
	public void demo01() {
		Session session = HibernateUtils.getCurrentSession();//此时,使用getCurrentSession方法获取的Session用的都是同一个
		Transaction tx = session.beginTransaction();
		
		Customer customer = new Customer();
		customer.setCust_name("王思聪");
		
		session.save(customer);
		
		tx.commit();
		//这个时候,Session不用关闭了,你现在一关闭反而会报错(Session已经关闭了)。因为当你的线程一结束,它就会自动关闭了。
	}
	
}

还有人不相信此时Session关闭会报错,你就试着关闭一下嘛!看会不会报下面的错:
Hibernate入门第七讲——Hibernate中的事务管理_第5张图片
报错的原因:使用getCurrentSession方法获取的是与线程绑定的Session对象,在事务关闭(提交)时,Session对象就也被close掉了,简单说,就不需要我们再手动close掉Session对象了。

你可能感兴趣的:(Hibernate框架,Hibernate框架学习)