Skip to content
liuyangming edited this page Sep 15, 2018 · 20 revisions

一、ByteTCC为什么要基于事务管理器(TransactionManager)来实现TCC全局事务?

1.1、首先,TCC事务既然属于事务处理范畴,使用TransactionManager来实现应该说是自然而然的思路;
1.2、其次,Java平台中,主流的bean容器(如EJB、spring)都采用声明式事务机制来管理应用程序的事务,通过委托TransactionManager模块来管理事务,因此使用TransactionManager的实现方式可以作为独立模块与bean容器无缝衔接;
1.3、由于bean容器的事务处理均由TransactionManager接管,因此在TCC全局事务中TransactionManager对各阶段service绑定哪些资源以及资源事务(如数据库事务)的开启、完成情况可以有比较精准的掌握,有助于控制全局事务;相反,如果在应用系统层实现TCC全局事务,则效果控制效果要差很多,例如全局事务可能不太容易获知service参与的资源事务的提交/回滚情况。如果try阶段service的资源事务的提交/回滚情况无法获知,就无从判断该service对应的cancel操作是否应该执行;如果confirm/cancel阶段service参的资源事务的提交/回滚情况无法获知,就无从判断该confirm/cancel是否仍然需要再次执行,因而只能通过要求业务系统操作自行保证幂等性,并通过反复执行来保障confirm/cancel被成功调用(一来业务系统逻辑复杂度高,二来由于confirm/cancel操作可能会被反复多次执行,也导致性能开销较大)。

二、ByteTCC为什么要兼容JTA规范?

JTA是Java平台中的事务管理规范,它为事务管理器和资源管理器、应用服务器定义了标准的事务处理接口,被主流的bean容器所兼容。因此,兼容JTA规范,有助于ByteTCC对各类资源管理器的支持和对各类bean容器的支持。

三、兼容JTA会不会导致ByteTCC性能低下?

1、JTA(Java Transaction API)仅是一套接口而已,并不会直接造成性能问题,各JTA实现的性能是否低下更关键的还是取决于各自的实现方式;
2、JavaEE平台中的事务可分为LocalTransaction、XATransaction两种:i)LocalTransaction,即本地事务,例如可以通过java.sql.Connection的commit()和rollback()方法提交和回滚的事务就属于LocalTransaction;ii)XATransaction,即分布式事务,基于两阶段事务提交机制实现的事务。这两种事务中,只有XATransaction属于分布式事务范畴,也网上争议较多的,因为使用2pc机制,所以性能较差。
3、ByteTCC仅使用LocalTransaction来管理各阶段(Try/Confirm/Cancel)service参与的普通事务,并没有使用XATransaction,所以不会因为兼容JTA而造成性能低下

四、为什么ByteTCC推荐使用注解而不是xml来配置声明式事务?

使用注解方式来配置声明式事务,可以让开发者明确了解自己所编写的service是否参与事务以及使用何种传播级别参与事务;而使用xml方式配置时,开发者可能意识不到自己所编写的service参与事务的情况;

五、我想使用xml来配置spring声明式事务,应该怎么处理?

  1. 0.3.0-RC4及之前版本:从bytetcc-core.xml文件中删除配置;
  2. 0.3.0-RC4之后版本:从bytetcc.xml文件中删除配置;

六、"Only compensable transaction can propagate its transaction context to the remote node!"异常如何处理?

使用ByteTCC时,只有参与TCC全局事务的service可以将事务分支传播到远程节点(即可以通过dubbo来执行远程调用),若service参与的不是TCC全局事务且发起dubbo远程调用时则抛出该异常。出现该问题的可能,有两种:

  1. ByteTCC的事务配置没有生效,即业务系统启动的时候没有找到bytetcc.xml文件或没有成功引入bytetcc.xml文件;
  2. 触发全局事务创建的service(注意:可能不是发起dubbo调用的service)不是Compensable-Service,即没有标注@Compensable注解;
    解决思路:可在org.bytesoft.bytetcc.TransactionManagerImpl类中的begin()方法中打一个断点初步debug一下:i)如果未能进入该断点,确定问题为情况1; ii)如果在begin方法中执行的是普通事务流程分支,确定问题为情况2;

七、使用Spring Data JPA & Hibernate时,出现"javax.persistence.TransactionRequiredException: Executing an update/delete query!"异常如何处理?

该异常是由于hibernate没有对spring的JtaPlatform提供默认支持所致。处理方式如下:

  1. 请咨询ByteTCC作者(或查看用户指南文档),如果ByteTCC的当前版本中提供了默认的支持,则使用默认支持的配置;
  2. 如果ByteTCC尚未提供默认支持,请按如下步骤进行配置;
    2.1) 创建类SpringJtaPlatform;
public class SpringJtaPlatform extends AbstractJtaPlatform {
	private static final long serialVersionUID = 1L;
	protected javax.transaction.TransactionManager locateTransactionManager() {
		CompensableBeanRegistry registry = CompensableBeanRegistry.getInstance();
		CompensableBeanFactory beanFactory = registry.getBeanFactory();
		return beanFactory == null ? null : beanFactory.getTransactionManager();
	}
	protected javax.transaction.UserTransaction locateUserTransaction() {
		return null;
	}
}

2.2) 为LocalContainerEntityManagerFactoryBean添加hibernate.transaction.coordinator_class和hibernate.transaction.jta.platform属性;

<bean id="......" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="jpaProperties">
		<props>
			<prop key="hibernate.transaction.coordinator_class">jta</prop>
			<prop key="hibernate.transaction.jta.platform">${步骤2.1中定义的SpringJtaPlatform的全限类名}</prop>
		</props>
	</property>
</bean>

注意:若按情况2配置时,引入bytetcc.xml的操作最好放在步骤2.2的配置项之前

八、使用Spring Data JPA & Hibernate时,出现"InvalidDataAccessApiUsageException: no transaction is in progress!"异常如何处理?

在'main/resources/META-INF/'目录下添加persistence.xml文件,内容如下

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
	version="1.0">
	<persistence-unit name="default" transaction-type="JTA">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
	</persistence-unit>
</persistence>

九、使用SpringCloud时,为什么强制在Controller上加注@Compensable注解?

ByteTCC倾向于认为,使用SpringCloud时提供服务的是Controller,而Controller所调用的Service仅仅是内部服务,因此Controller加注@Compensable是自然而然的事情。
相反,如果不在Controller上加注@Compensable,而是在它调用的Service上加,则会出现如下的二义性问题:
1、该Controller不接受远程事务传播时,它调用的Service为主事务发起方,此时,Controller不参与全局事务,Controller中所做的操作与Service中的操作不在一个全局事务中。
2、该Controller接受远程事务传播时,Controller及它调用的Service为事务参与方,此时,Controller中所做的操作与Service中的操作在同一个全局事务中。
因此,就带来一个问题,在写这个Controller和Service时,怎么知道这二者的操作到底是在一个全局事务中,还是不在一个全局事务中呢?