我正试图在我的Spring Boot应用程序中实现跨Hazelcast的XA事务,而JPA持续到PostgreSQL。将Atomikos Spring Boot启动器放入我的pom.xml中,可以加载JtaTransactionManager以与@Transactional注释一起使用,但是Hazelcast XA资源没有加入该事务。
如何使用JTA UserTransaction将Spring Boot自动登记到我的XA资源,作为使用JtaTransactionManager的AOP事务拦截器的一部分?
答案 0 :(得分:0)
我通过使用注释和AspectJ Aspect来解决这个问题,如here所述。另请参阅this以定义与类或方法级别注释匹配的切入点,您可能需要执行此操作:
@EnableTransactionManagement(order = Ordered.HIGHEST_PRECEDENCE)
在调用此代码之前发生事务拦截器。
@Aspect
@Component
public class XAResourceAspect {
@Autowired
JtaTransactionManager jtaTransactionManager;
@Autowired
ApplicationContext applicationContext;
@Pointcut("within(@XAResource *)")
public void beanAnnotatedWithAnnotation() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithAnnotation()")
public void publicMethodInsideAnnotatedClass() {}
private ThreadLocal<Map<Transaction, Set<String>>> enlistedResources = new ThreadLocal<>();
@Around("@annotation(ppi.nestup.v3.annotation.XAResource) || publicMethodInsideAnnotatedClass()")
public Object enlistResources(ProceedingJoinPoint joinPoint) throws Throwable {
boolean setThreadLocal = false;
Transaction transaction = jtaTransactionManager.getTransactionManager().getTransaction();
if (transaction != null) {
Map<Transaction, Set<String>> transactionMap = enlistedResources.get();
LOG.info("Enlisting resources for joinpoint " + joinPoint + " and transaction " + transaction);
if (transactionMap == null) {
transactionMap = new HashMap<>();
enlistedResources.set(transactionMap);
setThreadLocal = true;
LOG.info("Created new ThreadLocal for transaction " + transaction);
} else {
LOG.info("Found existing ThreadLocal " + transactionMap);
}
transactionMap.computeIfAbsent(transaction, k -> new HashSet<>());
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Class withinType = joinPoint.getSourceLocation().getWithinType();
XAResource annotation = method.getAnnotation(XAResource.class);
if (annotation == null) {
annotation = (XAResource) withinType.getAnnotation(XAResource.class);
}
String[] resourceNames = annotation.value();
for (String name : resourceNames) {
if (!transactionMap.get(transaction).contains(name)) {
javax.transaction.xa.XAResource resource =
(javax.transaction.xa.XAResource) applicationContext.getBean(name);
try {
transaction.enlistResource(resource);
} catch (IllegalStateException e) {
LOG.error("Caught exception trying to enlist resource " + name + " for transaction " + transaction + " and joinpoint " + joinPoint);
e.printStackTrace();
}
transactionMap.get(transaction).add(name);
}
}
}
Object proceed = joinPoint.proceed();
if (setThreadLocal) {
LOG.info("Removing threadlocal");
enlistedResources.remove();
}
return proceed;
}
}
我还没有对此做过很多测试,但到目前为止它已经开始工作了。