事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰。 数据库向用户提供保存当前程序状态的方法,叫事务提交(commit);当事务执行过程中,使数据库忽略当前的状态并回到前面保存的状态的方法叫事务回滚(rollback)。


1、事务的特性

事务具备原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)4个属性,简称ACID。下面对这4个特性分别进行说明。
原子性:将事务中所做的操作捆绑成一个原子单元,即对于事务所进行的数据修改等操作,要么全部执行,要么全部不执行。
一致性:事务在完成时,必须使所有的数据都保持一致状态,而且在相关数据中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构都应该是正确的。
隔离性:由并发事务所做的修改必须与任何其他事务所做的修改相隔离。事务查看数据时数据所处的状态,要么是被另一并发事务修改之前的状态,要么是被另一并发事务修改之后的状态,即事务不会查看由另一个并发事务正在修改的数据。这种隔离方式也叫可串行性。
持久性:事务完成之后,它对系统的影响是永久的,即使出现系统故障也是如此。


2 、事务隔离

事务隔离意味着对于某一个正在运行的事务来说,好像系统中只有这一个事务,其他并发的事务都不存在一样。在大部分情况下,很少使用完全隔离的事务。但不完全隔离的事务会带来如下一些问题。

更新丢失(Lost Update):两个事务都企图去更新一行数据,导致事务抛出异常退出,两个事务的更新都白费了。

脏数据(Dirty Read):如果第二个应用程序使用了第一个应用程序修改过的数据,而这个数据处于未提交状态,这时就会发生脏读。第一个应用程序随后可能会请求回滚被修改的数据,从而导致第二个事务使用的数据被损坏,即所谓的“变脏”。

不可重读(Unrepeatable Read):一个事务两次读同一行数据,可是这两次读到的数据不一样,就叫不可重读。如果一个事务在提交数据之前,另一个事务可以修改和删除这些数据,就会发生不可重读。

幻读(Phantom Read):一个事务执行了两次查询,发现第二次查询结果比第一次查询多出了一行,这可能是因为另一个事务在这两次查询之间插入了新行。针对由事务的不完全隔离所引起的上述问题,提出了一些隔离级别,用来防范这些问题。

读操作未提交(Read Uncommitted):说明一个事务在提交前,其变化对于其他事务来说是可见的。这样脏读、不可重读和幻读都是允许的。当一个事务已经写入一行数据但未提交,其他事务都不能再写入此行数据;但是,任何事务都可以读任何数据。这个隔离级别使用排写锁实现。

读操作已提交(Read Committed):读取未提交的数据是不允许的,它使用临时的共读锁和排写锁实现。这种隔离级别不允许脏读,但不可重读和幻读是允许的。

可重读(Repeatable Read):说明事务保证能够再次读取相同的数据而不会失败。此隔离级别不允许脏读和不可重读,但幻读会出现。

可串行化(Serializable):提供最严格的事务隔离。这个隔离级别不允许事务并行执行,只允许串行执行。这样,脏读、不可重读或幻读都可发生。


在一个实际应用中,开发者经常不能确定使用什么样的隔离级别。太严厉的级别将降低并发事务的性能,但是不足够的隔离级别又会产生一些小的Bug,而这些Bug只会在系统重负荷(也就是并发严重时)的情况下才会出现。

一般来说,读操作未提交(Read Uncommitted)是很危险的。一个事务的回滚或失败都会影响到另一个并行的事务,或者说在内存中留下和数据库中不一致的数据。这些数据可能会被另一个事务读取并提交到数据库中。这是完全不允许的。

另外,大部分程序并不需要可串行化隔离(Serializable Isolation)。虽然,它不允许幻读,但一般来说,幻读并不是一个大问题。可串行化隔离需要很大的系统开支,很少有人在实际开发中使用这种事务隔离模式。
现在留下来的可选的隔离级别是读操作已提交(Read Committed)和可重读(Repeatable Read)。Hibernate可以很好地支持可重读(Repeatable Read)隔离级别。


3、在hibernate配置文件中设置隔离级别

hibernate事务隔离级别的数字意义:

1:读操作未提交(Read Uncommitted)
2:读操作已提交(Read Committed)
4:可重读(Repeatable Read)
8:可串行化(Serializable)

设置隔离级别的两种方式:

1)、在hibernate.properties中设置:hibernate.connection.isolation 42)、在hibernate.cfg.xml中设置:<session-factory>……//把隔离级别设置为4<property name="hibernate.connection.isolation">4</property>……
</session-factory>

在开始一个事务之前,hibernate从配置文件中获得隔离级别的值。


4、在hibernate中使用JDBC和JTA(Java Transaction API)事务

说明一:Hibernate本身没有实现自己的事务管理功能,而是对底层JDBC事务或JTA事务的轻量级封装

hibernate本身没有实现自己事务管理功能,而是对
底层JDBC事务或JTA事务的轻量级封装。Hibernate将底层的JDBCTransaction或JTATransaction进行了封装,再在外面套上Transaction和Session的外壳,其实是通过委托底层的JDBC或JTA来实现事务的处理功能的。


下面我们来通过源码来看一下hibernate是如何封装的

org.hibernate.impl.SessionImpl类(该类是会话的实现类):

public Transaction beginTransaction() throws HibernateException {errorIfClosed();if ( rootSession != null ) {log.warn( "Transaction started on non-root session" );}Transaction result = getTransaction();result.begin();return result;
}public Transaction getTransaction() throws HibernateException {errorIfClosed();return jdbcContext.getTransaction();
}

org.hibernate.jdbc.JDBCContext类:

public Transaction getTransaction() throws HibernateException {if (hibernateTransaction==null) {hibernateTransaction = owner.getFactory().getSettings().getTransactionFactory().createTransaction( this, owner );}return hibernateTransaction;
}

TransactionFactory有很多实现类:

选择最基本的org.hibernate.transaction.JDBCTransactionFactory观察一下:

public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)throws HibernateException {return new JDBCTransaction( jdbcContext, transactionContext );
}

org.hibernate.transaction.JDBCTransaction类的说明:

Transaction implementation based on transaction management through a JDBC Connection. This the Hibernate’s default transaction strategy.

事务开始时会禁用自动提交:

public void begin() throws HibernateException {if (begun) {return;}if (commitFailed) {throw new TransactionException("cannot re-start transaction after failed commit");}log.debug("begin");try {toggleAutoCommit = jdbcContext.connection().getAutoCommit();if ( log.isDebugEnabled() ) {log.debug("current autocommit status: " + toggleAutoCommit);}if (toggleAutoCommit) {log.debug("disabling autocommit");jdbcContext.connection().setAutoCommit(false);//关闭事务自动提交}}catch (SQLException e) {log.error("JDBC begin failed", e);throw new TransactionException("JDBC begin failed: ", e);}callback = jdbcContext.registerCallbackIfNecessary();begun = true;committed = false;rolledBack = false;if ( timeout>0 ) {jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);}jdbcContext.afterTransactionBegin(this);
}

通过日志也能看出一点东西:

[2013-08-09 16:37:55] DEBUG  -> begin
[2013-08-09 16:37:55] DEBUG  -> opening JDBC connection
[2013-08-09 16:37:55] DEBUG  -> current autocommit status: false
[2013-08-09 16:37:55] DEBUG  -> generated identifier: 1, using strategy: org.hibernate.id.Assigned
[2013-08-09 16:37:55] DEBUG  -> commit

说明二:不需要显式的调用flush()方法,事务提交时会根据session的FlushMode自动触发session的flush

还是通过最基本的JDBCTransaction类看一下:

事务提交完成之后又恢复了事务的自动提交:

public void commit() throws HibernateException {if (!begun) {throw new TransactionException("Transaction not successfully started");}log.debug("commit");if ( !transactionContext.isFlushModeNever() && callback ) {transactionContext.managedFlush(); //根据FlushMode(通常为AUTO)刷新SessionnotifySynchronizationsBeforeTransactionCompletion();if ( callback ) {jdbcContext.beforeTransactionCompletion( this );}try {commitAndResetAutoCommit();//在该方法中重新开启了事务自动提交log.debug("committed JDBC Connection");committed = true;if ( callback ) {jdbcContext.afterTransactionCompletion( true, this );}notifySynchronizationsAfterTransactionCompletion( Status.STATUS_COMMITTED );}catch (SQLException e) {log.error("JDBC commit failed", e);commitFailed = true;if ( callback ) {jdbcContext.afterTransactionCompletion( false, this );}notifySynchronizationsAfterTransactionCompletion( Status.STATUS_UNKNOWN );throw new TransactionException("JDBC commit failed", e);}finally {closeIfRequired();}
}private void commitAndResetAutoCommit() throws SQLException {try {jdbcContext.connection().commit();}finally {toggleAutoCommit();}
}private void toggleAutoCommit() {try {if (toggleAutoCommit) {log.debug("re-enabling autocommit");jdbcContext.connection().setAutoCommit( true );//重新开启事务自动提交}}catch (Exception sqle) {log.error("Could not toggle autocommit", sqle);//swallow it (the transaction _was_ successful or successfully rolled back)}
}

JDBC事务默认自动提交,但是如果Hibernate的事务策略使用JDBC,在事务开始之前,Hibernate会关闭事务自动提交,在事务结束之后,重新开启事务自动提交


5、 在Hibernate中使用JDBC事务

Hibernate对JDBC进行了轻量级的封装,它本身在设计时并不具备事务处理功能。Hibernate将底层的JDBCTransaction或JTATransaction进行了封装,再在外面套上Transaction和Session的外壳,其实是通过委托底层的JDBC或JTA来实现事务的处理功能的。

要在Hibernate中使用事务,可以在它的配置文件中指定使用JDBCTransaction或者JTATransaction。在hibernate.properties中,查找“transaction.factory_class”关键字,得到以下配置:

# hibernate.transaction.factory_class
org.hibernate.transaction.JTATransactionFactory
# hibernate.transaction.factory_class
org.hibernate.transaction.JDBCTransactionFactory

Hibernate的事务工厂类可以设置成JDBCTransactionFactory或者JTATransactionFactory。如果不进行配置,Hibernate就会认为系统使用的事务是JDBC事务。

在JDBC的提交模式(commit mode)中,如果数据库连接是自动提交模式(auto commit mode),那么在每一条SQL语句执行后事务都将被提交,提交后如果还有任务,那么一个新的事务又开始了。

Hibernate在Session控制下,在取得数据库连接后,就立刻取消自动提交模式,即Hibernate在一个执行Session的beginTransaction()方法后,就自动调用JDBC层的setAutoCommit(false)。如果想自己提供数据库连接并使用自己的SQL语句,为了实现事务,那么一开始就要把自动提交关掉(setAutoCommit(false)),并在事务结束时提交事务。

使用JDBC事务是进行事务管理最简单的实现方式,Hibernate对于JDBC事务的封装也很简单。下面是一个在Hibernate中使用JDBC事务的例子:

try { Session session = HibernateUtil.currentSession();Transaction tx = session.beginTransaction(); //在默认情况下,开启一个JDBC事物 for(int i=0; i<10; i++) { Student stu = new Student(); stu.setName("Student" + i); session.save(stu); } tx.commit(); //提交事务 session.close(); } catch(Exception e) {… tx.rollback(); //事务回滚 }

6、 在Hibernate中使用JTA事务

JTA(Java Transaction API)是事务服务的J2EE解决方案。本质上,它是描述事务接口的J2EE模型的一部分,开发人员直接使用该接口或者通过J2EE容器使用该接口来确保业务逻辑能够可靠地运行。

JTA有3个接口,它们分别是UserTransaction接口、TransactionManager接口和Transaction接口。这些接口共享公共的事物操作,例如commit()和rollback(),但也包含特殊的事务操作,例如suspend()、resume()和enlist(),它们只出现在特定的接口上,以便在实现中允许一定程度的访问控制。

在一个具有多个数据库的系统中,可能一个程序会调用几个数据库中的数据,需要一种分布式事务,或者准备用JTA来管理跨Session的长事务,那么就需要使用JTA事务。下面介绍如何在Hibernate的配置文件中配置JTA事务。在hibernate.properties文件中设置如下(把JTATransactionFactory所在的配置行的注释符“#”取消掉):

#hibernate.transaction.factory_classorg.hibernate.transaction.JTATransactionFactory
# hibernate.transaction.factory_classorg.hibernate.transaction.JDBCTransactionFactory

或者在hibernate.cfg.xml文件中配置如下:

<session-factory> …<property name=” hibernate.transaction.factory_class”> org.hibernate.transaction.JTATransactionFactory </property>    …
</session-factory>

下面是一个应用JTA事务的例子:


javax.transaction.UserTransaction tx = null;
tx = new initialContext().lookup(” javax.transaction.UserTransaction ”) ;
tx.begin();
Session s1 = sf.openSession();
……
s1.flush();  s1.close();
Session s2 = sf.openSession();
……
s2.flush();  s2.close();
tx.commit();

【大话Hibernate】hibernate事务管理相关推荐

  1. Hibernate的事务管理

    2019独角兽企业重金招聘Python工程师标准>>> 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整 ...

  2. Hibernate事务管理

    事务只是一个工作单位(单元). 在这种情况下,如果一个步骤失败,则整个事务失败(称为原子性). ACID属性(原子性,一致性,隔离性和持久性)可以描述事务. Hibernate中的事务接口 在hibe ...

  3. atitit.spring hibernate的事务机制 spring不能保存对象的解决

    atitit.spring hibernate的事务机制 spring不能保存对象的解决 sessionFactory.openSession() 不能..log黑头马sql语言.. sessionF ...

  4. orm jpa_Spring ORM示例– JPA,Hibernate,事务

    orm jpa Welcome to the Spring ORM Example Tutorial. Today we will look into Spring ORM example using ...

  5. Spring 事务管理高级应用难点剖析

    Spring 事务管理高级应用难点剖析: 第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts1/index.html htt ...

  6. Spring 事务管理高级应用难点剖析--转

    第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...

  7. Spring JDBC-Spring对事务管理的支持

    概述 事务管理关键抽象 Spring事务管理的实现类 Spring JDBC 和MybBatis的事务管理器的配置 JPA的事务管理器的配置 Hibernate的事务管理器的配置 JTA 的事务管理器 ...

  8. Spring的事务管理难点剖析(1):DAO和事务管理的牵绊

    2019独角兽企业重金招聘Python工程师标准>>> 有些人很少使用Spring而不使用Spring事务管理器的应用,因此常常有人会问:是否用了Spring,就一定要用Spring ...

  9. Spring配置事务管理

    1. spring 注解事务的配置 <!-- 注册配置事务管理器 -->     <bean id="transactionManager" class=&quo ...

  10. spring事务管理的两种方式

    一.注解式事务 1.注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo. 2.事务配置实例 (1).spring+mybatis 事务配置 &l ...

最新文章

  1. 数据科学学习课件:实用数据挖掘与人工智能
  2. 独立成分分析ICA系列5:信息极大化的 ICA 算法
  3. codeigniter在nginx安装配置及URL重写
  4. java猜拳游戏代码_Java实现简单猜拳游戏
  5. python中print是什么意思_python中print什么意思
  6. angular 字符串转换成数字_Python基础语法大全:字符串的处理与使用
  7. ASP.NET Cache缓存管理基于web的缓存
  8. mac memcached_如何在Mac OS上安装Memcached Server
  9. JS—触摸事件、手势事件
  10. 联通发送wap push备忘录
  11. 【计算机三级网络技术】 快速求出IP地址块经聚合后的IP地址
  12. linux访问mdio接口函数,Linux 下smi/mdio总线通信
  13. iReport使用入门
  14. MATLAB 整数小数负数十进制转换为十六进制
  15. 软件工程3 软件开发过程
  16. Java数字转换为人民币的大写
  17. 【个人学习笔记】概率论与数理统计知识梳理【一】
  18. MATLAB绘图合集:imagesc绘图
  19. selenium+Java环境搭建
  20. Android RxJava操作符的学习---变换操作符

热门文章

  1. RAC+单实例DATAGUARD 配置
  2. Android JNI(Java Native Interface)技术介绍
  3. WebKit 内核源码分析 (二) FrameLoader
  4. SpringCloud微服务架构之,Hystrix 熔断器,Gateway 网关
  5. eclipse tomcat jsp乱码
  6. python 游戏 —— 汉诺塔(Hanoita)
  7. SpringBoot专栏(一) -- SpringBoot简介
  8. RPi 树莓派 DSI 接口研究 MIPI raspberry pi
  9. 日期年月日的比较以及判断
  10. 洛谷 P2046 BZOJ 2007 海拔(NOI2010)