Hibernate_9

数据库事务必须具备ACID特征,ACID是Atomic(原子性)、Consistency(一致性)、Isoation(隔离性)、Durability(持久性)的缩写。
原子性:指整个数据库事务是不可分割的工作单元。只有事务中所有的操作执行成功,才算整个事务成功
一致性:数据库事务不能破坏关系数据的完整性及业务逻辑上的一致性
隔离性:在并发环境下,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间
持久性:只要事务成功结束,他对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统之后,数据库还能恢复到事务成功结束时的状态
事物的ACID特性是由关系数据库管理系统来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,若某个事务在执行过程中发生错误,就可以根据日志撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。
数据库管理系统采用所机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其它事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。

数据库系统的客户程序只要向数据库系统声明了一个事务,数据库系统就会自动保证事务的ACID特性。声明事务包含以下几方面:
事务的开始边界(BEGIN)
事务的正常结束边界(COMMIT):提交事务,永久保存被事务更新后的数据库状态
事务的异常结束边界(ROLLBACK):撤销事务,使数据库退回到执行事务前的初始状态
数据库支持以下两种事务模式:
自动提交模式:每个SQL语句都是一个独立的事务,当数据库系统执行完一个SQL语句后,会自动提交事务。
手工提交模式:必须由数据库的客户程序显式指定事务开始边界和结束边界

在MySQL中,数据库表分为3种类型:INNODB、BDB、MyISAM类型。其中INNODB和BDB类型的表是支持数据库事务的,而MyISAM类型的表是不支持事务的。

对于java应用,声明事务有以下方式:直接通过JDBC API类声明JDBC事务;直接通过Hibernate API来声明JDBC事务;直接通过Hibernate API来声明JTA事务;直接通过JTA API来声明JTA事务。

在mysql.exe程序中声明事务
每启动一个mysql.exe程序,都会得到一个单独的数据库连接。每个数据库连接都有一个全局变量@@autocommit,表示当前的事0务模式,它有两个可选值:0:表示手工提交模式;1默认值,表示自动提交模式
mysql> select @@autocommit
mysql> set autocommit=0;
在自动提交模式下运行事务:
在自动提交模式下,每个SQL语句都是一个独立的事务。
在手工提交模式下运行事务:
在手工提交模式下,必须显式指定事务开始边界和结束边界:事务的开始边界:begin、提交事务:commit、撤销事务:rollback
mysql > begin
mysql > select * from ACCOUNTS
mysql > commit

Java应用通过JDBC API声明JDBC事务
在JDBC API中,java.sql.Connection类代表一个数据库连接。Connection类提供了以下用于控制事务的方法:
setAutoCommit(boolean autoCommit):设置是否自动提交事务
commit():提交事务
rollback():撤销事务
可以通过setAtuoCommit(false)方法来设置手工提交事务模式,然后就可以把多条更新数据库的SQL语句作为一个事务,在所有操纵完成后调用commit()方法来整体提交事务,若一项SQL操作失败,则会抛出SQLException,此时,应在捕获异常的代码块中调用rollback()方法撤销事务。

Java应用通过Hibernate API声明JDBC事务
Hibernate冯各庄了JDBC API和JTA API,Java应用直接通过Hibernate API来声明事务,有两个有点:1.有利于跨平台开发 2.当应用程序通过Hibernate API声明事务时,事务与Session更加紧密地集成在一起。
在Hibernate API中,Session和Transaction接口提供了一下声明事务边界的方法:
声明事务的开始边界:
Transaction tx = session.beginTransaction(); //为Session对象分配数据库连接,并且自动把这个连接设为手工提交事务模式。Hibernate底层实现会自动调用代表数据库连接的java.sql.Connection对象的setAutoCommit(false)方法。开始一个新的JDBC事务。Session的beginTransaction()方法返回的Transaction实例的类型是由Hibernate配置文件中的hibernate.transaction.factory_class事务工厂属性决定的,该属性的默认值为org.hibernate.transaction.JDBCTransactionFactory。
JDBCTransactionFactory表示JDBC事务工厂,它负责创建JDBCTransaction类的实例。
提交事务:
tx.commit(); //在默认的情况下,Session采用自动清理缓存模式,在这种模式下,commit()方法会先自动调用Session的flush()方法清理缓存,即按照Session缓存中对象的变化去同步更新数据库;向底层数据库提交事务;释放Session占用的数据库连接
撤销事务:
tx.rollback(); //立即撤销事务,并且释放Session占用的数据库连接

在Hibernate3以前的版本中,Hibernate抛出的异常都属于受检查异常(Checked Excpetion)
,因此程序必须捕获并处理这种异常(JDBC API抛出异常都属于受检查异常)。但在多数情况下,Hibernate抛出的异常都是致命的。因此,从Hibernate3版本开始,Hibernate抛出的异常都是运行时异常。
public void doWork(){
Session session = factory.openSession();
Transaction tx;
try{
tx = session.beginTransaction();
tx.setTimeout(5); //设置事务超时时间
...
tx.commit();
}catch(RuntimeException e){
if(tx==null){
try{
tx.rollback();
}catch(RuntimeException ex){
log.error("无法撤销事务",ex);
}
}
throw e;
}finally{
try{
session.close();
}catch(RuntimeException ex){
log.error("无法关闭Session",ex);
}
}
}

一个Session可以对应多个事务,,但一个Session只允许有一个未提交的事务。

Java应用通过Hibernate API声明JTA事务
JTA事务主要运行在受管理环境中。与JDBC事务相比,JTA具有以下特点:由低层JTA实现来提供和管理数据库连接池。而对于JDBC事务,必须由Hibernate来管理数据库连接池;数据库连接池与JNDI绑定,应用程序可通过JNDI API来访问数据库连接池;在处理复杂的大事务方面,由JTA实现提供的数据库连接池更加健壮可靠,性能优越;通过JTA API来声明JTA事务时,支持分布式事务 ;JTA事务在运行时并不会产生额外的系统开销。对于非分布式的JTA事务,它和JDBC具有同样的运行效率。
通过Hibernate API来声明JTA事务的步骤:
在Hibernate配置文件中配置hibernate.connection.datasource属性、hibernate.transaction.factory_class属性和hibernate.transaction.manager_lookup_class属性
#指定数据库连接池的JNDI
hibernate.connection.datasource=java:comp/env/jdbc/SAMPLEDB

#制定事务工厂
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JbossTransactionManagerLookup

JTA和JDBC在Hibernate内部实现的运行时行为有以下区别:
对于JDBC事务,当事务开始时,Session被分配一个数据库连接,当事务结束时,Session就释放数据库连接;对于JTA事务,仅仅当执行完一个SQL语句时,Session才获得数据库连接,而SQL语句执行完毕后,Session就立刻释放数据库连接。JTA实现会保证同一个JTA事务中的所有SQL操作都是用同一个数据库连接。用org.hibernate.Transaction接口的setTimeout()方法来设定超时时间时,对于JDBC事务,实际上设定的是JDBC层的PreparedSatement执行SQL语句的超时时间;而对于JTA事务,JTA实现能够监控整个JTA事务是否超时,Transaction接口的setTimeout()方法与javax.transaction.UserTransaction接口的setTransactionTimeout()方法是等价的。

Java应用通过JTA API声明JTA事务
通过JTA API声明JTA事务的步骤如下:
在Hibernate配置文件中配置hibernate.transaction.factory_class属性和hibernate.transaction.manager_lookup_class属性
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JbossTransactionManagerLookup
在程序中,通过JTA的javax.transaction.UserTransaction接口来声明JTA事务。
UserTransaction utx = (UserTransaction)new InitialContext().lookup("UserTransaction");
Session session1 = null;
Session session2 = null;

try{
utx.begin();

session1 = sessionFactory.openSession();
session2 = sessionFactory.openSession();
....
//默认情况下,UserTransaction的commit()方法提交事务时,不会自动清理缓存
session1.flush();
session2.flush();

uxt.commit();

} }catch(RuntimeException e){
if(tx==null){
try{
utx.rollback();
}catch(RuntimeException ex){
log.error("无法撤销事务",ex);
}
}
throw e;
}finally{
try{
session1.close();
session2.close();
}catch(RuntimeException ex){
log.error("无法关闭Session",ex);
}
}
}
若在Hibernate配置文件中设置以下两个属性时,则可不必手动清理缓存和关闭Session
hibernate.transaction.flush_before_completion:若为true,在提交事务前自动清理缓存
hibernate.transaction.auto_close_session:若为true,在提交或撤销事务后自动关闭Session
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值