我想在Spring Boot中分析和跟踪事务。
目前我在@Before
注释上使用@Transactional
方面,然后使用TransactionSynchronizationAdapter
注册提交挂钩。但这不包括使用程序化api开始的任何交易(例如PlatformTransactionManager
)。
我尝试在@Before("execution(* org.springframework.transaction.PlatformTransactionManager.getTransaction(..))")
上设置方面切入点,但是doesn't seem to work。
春天推荐的方法是什么?理想情况下使用基于注释的配置?
这是我到目前为止所做的:
@Aspect
@Component
@ConditionalOnProperty("transaction.metrics.enabled")
public class TransactionProfilerAspect {
private static final Logger logger = LoggerFactory.getLogger(TransactionProfilerAspect.class);
private static final AtomicLong TX_ID_FACTORY = new AtomicLong();
@Autowired
@Qualifier("longRunningTransactionDetectorExecutor")
ScheduledExecutorService scheduledExecutorService;
@Value("${transaction.metrics.timeoutMillis:5000}")
Long transactionTimeoutMillis;
@Before("@annotation(org.springframework.transaction.annotation.Transactional) && execution(* *(..))")
public void beforeTransactional() {
long txId = TX_ID_FACTORY.incrementAndGet();
String txName = TransactionSynchronizationManager.getCurrentTransactionName();
logger.info("Starting transaction [txId={}], [txName={}]", txId, txName);
Stopwatch stopwatch = Stopwatch.createStarted();
ScheduledFuture<?> future = scheduleTransactionTimeout(txId, stopwatch);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void beforeCommit(boolean readOnly) {
logger.info("Attempting commit for [txId={}]", txId);
}
@Override
public void afterCommit() {
logger.info("Commit successful for [txId={}]", txId);
}
@Override
public void afterCompletion(int status) {
if (status == STATUS_ROLLED_BACK) {
logger.warn("Rolling back transaction [txId={}]", txId);
}
synchronized (stopwatch) {
if (!future.isDone()) {
future.cancel(true);
}
}
long elapsed = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
logger.info("Completed transaction [txId={}], took {}ms", txId, elapsed);
}
});
}
private ScheduledFuture<?> scheduleTransactionTimeout(long txId, Stopwatch stopwatch) {
return scheduledExecutorService.schedule(() -> {
synchronized (stopwatch) {
logger.warn("Transaction [txId={}] exceeded the time limit of {}ms", txId, transactionTimeoutMillis);
}
}, transactionTimeoutMillis, TimeUnit.MILLISECONDS);
}
}