事务模型
java事务模型可分为三类:本地事务模型, 编程事务模型, 声明事务模型
本地事务:由资源管理器处理,比如JDBC Connection,通过设置自动提交模式是否禁用来使用事务,也就是说事务处理与Connection直接相关
编程事务模型:JTA事务由javax.transaction包API支持,事务处理与资源使用分离开来,由事务管理器参与协调多种事务性资源,所谓编程事务是相对容器管理事务而言的,这分别于EJB中的BMP和CMP对应。编程事务由javax.transaction.UserTransaction划分事务边界也就是使用begin/commit/rollback,当需要使用挂起/回复时,还必须用到javax.transaction.TransactionManager。使用它而不用容器管理事务的场景主要包括
客户端对远程EJB Session bean进行调用
开启JTA容器事务比较消耗资源,所以,对业务方法可以更进一步划分粒度,在方法中的莫一段使用事务
使用无状态会话BEAN时,当客户端发起多次调用BEAN的不同方法以完成一次事务时
容器管理事务:EJB使用声明式事务标识改BEAN的事务处理交给容器处理,容器可以接受远程编程式开启的事务,也可以自己开启事务,最终提交或回滚事务。在bean方法内,唯一能够做的有意义的事是:捕捉检查时异常,设置rollbackOnly
简要介绍下JTA API
javax.transaction.Status JTA事务状态,常用状态为ACTIVE,MARKED_ROLLBACK,ROLLBACKED
javax.transaction.Synchronization 定义了事务提交之前和提交或回滚之后执行的回调方法,这些方法一般用于清理资源,比如Session,Connection
javax.transaction.Transaction 定义了操作全:事务提交,回滚,绑定或解绑资源事务与资源,获取状态,设置回滚,同步
javax.transaction.TransactionManager定义了事务的所有动作,一般由应用服务器采用jts实现。也有开源实现,如JOTM.图中可以了解事务管理器与XAResource交互,并且必须提供有XADatasource的数据源
javax.transaction.TransactionSynchronizationRegistry定义了同步,JTA1.1规范新增接口。javax.transaction.UserTransaction提供给应用客户端化分事务边界的方法
javax.transaction.xa.XAResource定义了资源管理器与事务管理器的通信
javax.transaction.xa.Xid定义了资源事务关联的唯一标识,就好比树的枝干,每个资源管理器做的事就对应一条枝干的标识,而所有的枝干都长在一个树上象征着在每个资源管理器上做的事就对应着整颗树。Xid中包括全局事务格式,标识,分支标识。
org.hibernate.Transaction统一了各种事务的具体实现
JDBCTransaction
JTATransaction
CMTTransaction(事务托管给应用服务器完成)
三者都认为一个session只能允许同一时刻只能由一个未提交事务,实现中大量代码主要体现在事务提交前前后后的同步问题,我们将同步分为本地同步和JTA同步,之所以分开讨论,是因为这两种同步不能同时存在以上三种之一实现中。
如果条件flushBeforeCompletionEnabled||autoCloseSessionEnabled||connectionReleaseMode ==ConnectionReleaseMode.AFTER_TRANSACTION,即事务完成之前是否flush session,事务完成之后事务自动关闭 session,连接释放是否在提交事务之后 不为真,那么认为本地同步;
如果为真,则进行如下判断
如果采用的实现类是JBCTransaction或者TransactionManager没找到或者事务已经完成(提交或回滚,未激活等)或事务被标识为回滚,则为本地同步
否则,为JTA同步。
JDBCTransaction中
如果为本地同步并且flushmode !=Flushmode.Never则刷新session
如果为本地同步,则执行org.hibernate.jdbc.JDBCContext中的beforeTransactionCompletion和afterTransactionCompletion,同时执行synchronizations集合中的各个同步类(都是javax.transaction.Synchronization实现)
JTATransaction中
如果不是JTA同步,则认为是本地同步
如果是JTA同步,则同步方法的执行又JTA实现自动完成,hibernate不干预
如果是本地同步或!flushBeforeCompletionEnabled并且flushModel!=flushModel.Never,则刷新session
如果是本地同步并且JTA事务是通过Transaction begin启动,则执行beforeTransactionCompletion
如果JTA不是通过Transaction begin启动,则Transaction commit并不会真正触发提交
如果是本地同步,则执行afterTransactionCompletion
CMTTransaction中
如果不是JTA同步,Transaction begin抛出异常
如果是JTA同步并且!flushBeforeCompletionEnabled并且flushModel!=flushModel.Never,则刷新缓存
三种实现的总结:
JDBCTransaction只会执行本地同步
它通过java.sql.Connection实现,并会执行JdbcContext.beforeTransactionCompletion和afterTransactionCompletion
JTATransaction既可以进行JTA同步,也可进行本地同步;
它通过userTransaction实现,
但在调用Transaction begin方法时会调用registerSynchronizationIfPossible而此时如果找到事务管理器,并且事务是激活的会在事务注册同步org.hibernate.transaction.CacheSynchronization,间接调用调用JdbcContext.beforeTransactionCompletion和afterTransactionCompletion
否则是本地同步。事务允许通过userTransaction.begin开始,如果不是调用Transaction begin开启事务的,那自然就不会调用JdbcContext.beforeTransactionCompletion。如果是本地同步的话,还可以调用jdbcContext.afterTransactionCompletion
CMTTransaction不会进行实质性的事务开始,提交,回滚,超时,只设置回滚标志,当调用Transaction begin方法时会调用registerSynchronizationIfPossible而此时如果找到事务管理器会在事务上注册同步org.hibernate.transaction.CacheSynchronization,间接调用调用JdbcContext.beforeTransactionCompletion和afterTransactionCompletion
除了同步,必须关注回滚处理
JDBCTransaction 必须调用begin开始事务,负责提交和回滚
JTATransaction 调用begin,可能参与已经开启的事务。所以,如果只是参与性的,不能够提交,不能够回滚,只能设置rollbackOnly
CMTTransaction 不能开启事务,提交事务,只能够设置rollbackOnly
//$Id: JTATransaction.java 9601 2006-03-11 18:17:43Z epbernard $
package org.hibernate.transaction;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.TransactionException;
import org.hibernate.jdbc.JDBCContext;
import org.hibernate.util.JTAHelper;
/**
* Implements a basic transaction strategy for JTA transactions. Instances check to
* see if there is an existing JTA transaction. If none exists, a new transaction
* is started. If one exists, all work is done in the existing context. The
* following properties are used to locate the underlying <tt>UserTransaction</tt>:
* <br><br>
* <table>
* <tr><td><tt>hibernate.jndi.url</tt></td><td>JNDI initial context URL</td></tr>
* <tr><td><tt>hibernate.jndi.class</tt></td><td>JNDI provider class</td></tr>
* <tr><td><tt>jta.UserTransaction</tt></td><td>JNDI name</td></tr>
* </table>
* @author Gavin King
*/
public class JTATransaction implements Transaction {
private static final Log log = LogFactory.getLog(JTATransaction.class);
private final JDBCContext jdbcContext;
private final TransactionFactory.Context transactionContext;
private UserTransaction ut;
private boolean newTransaction;
private boolean begun;
private boolean commitFailed;
private boolean commitSucceeded;
private boolean callback;
public JTATransaction(
InitialContext context,
String utName,
JDBCContext jdbcContext,
TransactionFactory.Context transactionContext
) {
this.jdbcContext = jdbcContext;
this.transactionContext = transactionContext;
log.debug("Looking for UserTransaction under: " + utName);
try {
ut = (UserTransaction) context.lookup(utName);
}
catch (NamingException ne) {
log.error("Could not find UserTransaction in JNDI", ne);
throw new TransactionException("Could not find UserTransaction in JNDI: ", ne);
}
if (ut==null) {
throw new AssertionFailure("A naming service lookup returned null");
}
log.debug("Obtained UserTransaction");
}
public void begin() throws HibernateException {
if (begun) {
return;
}
if (commitFailed) {
throw new TransactionException("cannot re-start transaction after failed commit");
}
log.debug("begin");
try {
newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
if (newTransaction) {
ut.begin();
log.debug("Began a new JTA transaction");
}
}
catch (Exception e) {
log.error("JTA transaction begin failed", e);
throw new TransactionException("JTA transaction begin failed", e);
}
/*if (newTransaction) {
// don't need a synchronization since we are committing
// or rolling back the transaction ourselves - assuming
// that we do no work in beforeTransactionCompletion()
synchronization = false;
}*/
boolean synchronization = jdbcContext.registerSynchronizationIfPossible();
if ( !newTransaction && !synchronization ) {
log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
}
if (!synchronization) {
//if we could not register a synchronization,
//do the before/after completion callbacks
//ourself (but we need to let jdbcContext
//know that this is what we are going to
//do, so it doesn't keep trying to register
//synchronizations)
callback = jdbcContext.registerCallbackIfNecessary();
}
begun = true;
commitSucceeded = false;
jdbcContext.afterTransactionBegin(this);
}
public void commit() throws HibernateException {
if (!begun) {
throw new TransactionException("Transaction not successfully started");
}
log.debug("commit");
boolean flush = !transactionContext.isFlushModeNever()
&& ( callback || !transactionContext.isFlushBeforeCompletionEnabled() );
if (flush) {
transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
}
if (callback && newTransaction) {
jdbcContext.beforeTransactionCompletion(this);
}
closeIfRequired();
if (newTransaction) {
try {
ut.commit();
commitSucceeded = true;
log.debug("Committed JTA UserTransaction");
}
catch (Exception e) {
commitFailed = true; // so the transaction is already rolled back, by JTA spec
log.error("JTA commit failed", e);
throw new TransactionException("JTA commit failed: ", e);
}
finally {
afterCommitRollback();
}
}
else {
// this one only really needed for badly-behaved applications!
// (if the TransactionManager has a Sychronization registered,
// its a noop)
// (actually we do need it for downgrading locks)
afterCommitRollback();
}
}
public void rollback() throws HibernateException {
if (!begun && !commitFailed) {
throw new TransactionException("Transaction not successfully started");
}
log.debug("rollback");
/*if (!synchronization && newTransaction && !commitFailed) {
jdbcContext.beforeTransactionCompletion(this);
}*/
try {
closeIfRequired();
}
catch (Exception e) {
log.error("could not close session during rollback", e);
//swallow it, and continue to roll back JTA transaction
}
try {
if (newTransaction) {
if (!commitFailed) {
ut.rollback();
log.debug("Rolled back JTA UserTransaction");
}
}
else {
ut.setRollbackOnly();
log.debug("set JTA UserTransaction to rollback only");
}
}
catch (Exception e) {
log.error("JTA rollback failed", e);
throw new TransactionException("JTA rollback failed", e);
}
finally {
afterCommitRollback();
}
}
private static final int NULL = Integer.MIN_VALUE;
private void afterCommitRollback() throws TransactionException {
begun = false;
if (callback) { // this method is a noop if there is a Synchronization!
if (!newTransaction) {
log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
}
int status=NULL;
try {
status = ut.getStatus();
}
catch (Exception e) {
log.error("Could not determine transaction status after commit", e);
throw new TransactionException("Could not determine transaction status after commit", e);
}
finally {
/*if (status!=Status.STATUS_COMMITTED && status!=Status.STATUS_ROLLEDBACK) {
log.warn("Transaction not complete - you should set hibernate.transaction.manager_lookup_class if cache is enabled");
//throw exception??
}*/
jdbcContext.afterTransactionCompletion(status==Status.STATUS_COMMITTED, this);
}
}
}
public boolean wasRolledBack() throws TransactionException {
//if (!begun) return false;
//if (commitFailed) return true;
final int status;
try {
status = ut.getStatus();
}
catch (SystemException se) {
log.error("Could not determine transaction status", se);
throw new TransactionException("Could not determine transaction status", se);
}
if (status==Status.STATUS_UNKNOWN) {
throw new TransactionException("Could not determine transaction status");
}
else {
return JTAHelper.isRollback(status);
}
}
public boolean wasCommitted() throws TransactionException {
//if (!begun || commitFailed) return false;
final int status;
try {
status = ut.getStatus();
}
catch (SystemException se) {
log.error("Could not determine transaction status", se);
throw new TransactionException("Could not determine transaction status: ", se);
}
if (status==Status.STATUS_UNKNOWN) {
throw new TransactionException("Could not determine transaction status");
}
else {
return status==Status.STATUS_COMMITTED;
}
}
public boolean isActive() throws TransactionException {
if (!begun || commitFailed || commitSucceeded) return false;
final int status;
try {
status = ut.getStatus();
}
catch (SystemException se) {
log.error("Could not determine transaction status", se);
throw new TransactionException("Could not determine transaction status: ", se);
}
if (status==Status.STATUS_UNKNOWN) {
throw new TransactionException("Could not determine transaction status");
}
else {
return status==Status.STATUS_ACTIVE;
}
}
public void registerSynchronization(Synchronization sync) throws HibernateException {
if (getTransactionManager()==null) {
throw new IllegalStateException("JTA TransactionManager not available");
}
else {
try {
getTransactionManager().getTransaction().registerSynchronization(sync);
}
catch (Exception e) {
throw new TransactionException("could not register synchronization", e);
}
}
}
private TransactionManager getTransactionManager() {
return transactionContext.getFactory().getTransactionManager();
}
private void closeIfRequired() throws HibernateException {
boolean close = callback &&
transactionContext.shouldAutoClose() &&
!transactionContext.isClosed();
if ( close ) {
transactionContext.managedClose();
}
}
public void setTimeout(int seconds) {
try {
ut.setTransactionTimeout(seconds);
}
catch (SystemException se) {
throw new TransactionException("could not set transaction timeout", se);
}
}
protected UserTransaction getUserTransaction() {
return ut;
}
}
- 大小: 30.7 KB
分享到:
相关推荐
**JTA与JDBC的结合使用**:在Java企业级应用中,JDBC通常与JTA结合使用,以实现分布式事务。JDBC连接可以在JTA事务管理下工作,这样在同一个事务中,即使涉及多个数据库操作,也能保证数据的一致性。例如,在Servlet...
在Java编程中,处理事务主要涉及JDBC(Java Database Connectivity)和JTA(Java Transaction API)。理解这些概念对于开发可靠的、高性能的数据库应用至关重要。 首先,让我们从事务的四大特性说起: 1. **原子性...
JTA(XA)事务是Java Transaction API(JTA)的事务机制,它可以管理分布式事务,涉及多个资源管理器和事务管理器。JTA事务可以将多个资源管理器组合成一个事务,以确保分布式事务的一致性和可靠性。 使用JTA事务...
本文旨在深入探讨Hibernate事务管理机制,特别是JDBC Transaction与JTA Transaction在Hibernate中的实现方式及其区别。 #### 二、Hibernate事务管理配置 在使用Hibernate进行开发时,可以通过配置`hibernate....
- **跨资源事务控制**:JTA(Java Transaction API)用于管理跨系统的事务,JTS(Java Transaction Service)是其具体实现,两者协同工作确保分布式事务的一致性。 4. **常见问题** - **DriverManager与...
Java中的事务管理是确保数据一致性的重要机制,主要分为三种类型:JDBC事务、JTA(Java Transaction API)事务以及容器事务。本文将重点探讨JDBC事务和JTA分布式事务的区别和应用场景。 首先,JDBC事务是基于数据库...
Java Transaction API (JTA)是Java平台上的一个关键组件,主要负责处理分布式事务管理。作为Java Enterprise Edition (Java EE)的一部分,JTA定义了在分布式系统中如何协调多个资源(如数据库、消息队列等)的事务...
典型的J2EE三层结构,分为表现层... Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的Transaction实际上是底层的JDBC Transaction的封装,或者是JTA Transaction的封装,
本文将深入探讨在Eclipse环境中使用Hibernate开发应用程序时涉及到的Transaction管理,特别是JDBC Transaction和JTA(Java Transaction API)Transaction的区别与使用。 首先,Hibernate并不直接提供事务处理功能,...
org.hibernate.TransactionException: JDBC rollback failed
在 Hibernate 中,事务管理可以基于 JDBC Transaction 或 JTA (Java Transaction API) 进行,这两种方式各有特点。 首先,Hibernate 默认的事务处理机制是基于 JDBC Transaction。这意味着在进行数据库操作时,...
JTA即Java-Transaction-API,JTA允许应用程序执行分布式事务处理,即在两个或多个网络计算机资源上访问并且更新数据。JDBC驱动程序对JTA的支持极大地增强了数据访问能力。 XA协议是数据库层面的一套分布式事务管理...
JTA(Java Transaction API)允许应用程序执行分布式事务处理--在两个或多个网络计算机资源上访问并且更新数据。JDBC驱动程序的JTA支持极大地增强了数据访问能力。本文的目的是要提供一个关于的Java事务处理API(JTA)...
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/> <!-- JTA事务管理器 --> class="org.springframework.transaction.jta.JtaTransactionManager"> <!-- 数据源A --> ...
第五章 WebLogic Server JDBC 和 JTA 第六章 远程方法调用和分布式命名 第七章 使用 Java 消息服务进行企业消息传递 第八章 使用会话企业 JavaBean 第九章 实体 EJB 第十章 使用消息驱动 EJB 第十一章 使用 WebLogic...
5. **事务(Transaction)管理**:JDBC支持ACID(原子性、一致性、隔离性和持久性)事务属性,确保数据的完整性和一致性。`Connection`对象提供了开始、提交和回滚事务的方法。 6. **批处理(Batch Processing)**...
6. **JTA与JDBC/Java Persistence API (JPA)**: 在JDBC连接上启用JTA事务,需要使用`javax.sql.DataSource.getConnection(UserTransaction, ConnectionProperties)`方法,或者在JPA中通过`@Transactional`注解声明...
标题"Jta的jar包"指的是Java Transaction API (JTA)相关的Java库文件,这里提到了一个具体的版本号"1.0.1B"。描述中提到了"jbarcode-0.2.8"和"jbarcodebean-1.2.0",这是关于Java条形码生成库JBarcode的不同版本,但...
Java JTA,全称为Java Transaction API,是Java平台上的事务处理标准,用于管理跨系统或跨资源的事务。它提供了一种统一的方式来控制应用程序中的事务,使得开发者可以在不同的数据库、消息队列等资源之间进行协调,...