问题背景
报错: The specified log seems to be in use already: tmlog in ./. Make sure that no other instance is running, or kill any pending process if needed.

在使用 Spring Boot 3.3 + Atomikos 实现分布式事务时,发现事务日志文件(tmlog)总是生成在项目根目录,而不是期望的模块目录下。多个模块的 tmlog 文件混在一起,难以区分和管理。
在多模块的情况下,因为tmlog默认都是在父级模块下,所以每个模块都是共用一个tmlog,因为共用一个tmlog所以所有模块在同一时间只能启动一个,不能同时运行,但是部署在服务器不存在这个问题,因为在服务器上部署时每个模块的jar包不在想他目录,所以不会出现这个问题,主要解决的就是开发环境想要同时启动多个模块的问题,方便调试
环境信息
- JDK: 21
- Spring Boot: 3.3.0
- Atomikos: 6.0.0 (transactions-spring-boot3-starter)
- 项目结构: Maven 多模块
问题现象
默认配置下,所有模块的事务日志都输出到项目根目录:
shell
dog-auto-servers/
├── tmlog.lck
├── tmlog0.log
├── tmlog1.log
└── task-formula-ai/
└── task-auto-test/
错误尝试
方式一:自定义 TransactionManagerConfig Bean
最初尝试通过 Java 配置类手动创建 Bean:
java
@Configuration
public class TransactionManagerConfig {
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public UserTransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
// ❌ 这样设置无效!
return userTransactionManager;
}
@Bean(name = "transactionManager")
public JtaTransactionManager transactionManager() throws Throwable {
return new JtaTransactionManager(userTransaction(), atomikosTransactionManager());
}
}
结果:YAML 中的配置完全不生效,日志仍在根目录。
方式二:在 YAML 中配置但保留自定义 Bean
yaml
spring:
jta:
atomikos:
properties:
log-base-dir: ./logs/atomikos
log-base-name: task-formula-ai-tmlog
enable-logging: true
tm-unique-name: task-formula-ai
java
@Configuration
public class TransactionManagerConfig {
@Bean(name = "atomikosTransactionManager")
public UserTransactionManager atomikosTransactionManager() throws Throwable {
// ❌ 仍然无效!因为自定义 Bean 覆盖了自动配置
UserTransactionManager userTransactionManager = new UserTransactionManager();
return userTransactionManager;
}
}
结果 :配置依然不生效。原因:自定义 Bean 会覆盖 Spring Boot 的自动配置。
正确解决方案
✅ 方案:删除自定义配置类,使用 Spring Boot 自动配置
1. 删除 TransactionManagerConfig.java
直接删除自定义的配置类文件:
TransactionManagerConfig.java
2. 在 application.yml 中配置
yaml
spring:
application:
name: task-formula-ai # 服务名称
jta:
atomikos:
properties:
log-base-dir: ./logs/atomikos # 事务日志目录(相对路径)
log-base-name: ${spring.application.name}-tmlog # 日志文件基础名称
enable-logging: true # 启用磁盘日志
tm-unique-name: ${spring.application.name} # 事务管理器唯一标识
max-actives: 10000 # 最大活动事务数
default-jta-timeout: 300000 # 默认事务超时时间(毫秒)
force-shutdown-on-vm-exit: false # VM 关闭时是否强制关闭
3. 多模块配置示例
为每个模块设置不同的服务名称,日志文件就会自动区分开:
task-formula-ai:
yaml
spring:
application:
name: task-formula-ai
task-auto-test:
yaml
spring:
application:
name: task-auto-test
4. 重启验证
清理并重启应用后,日志文件结构变为:
shell
dog-auto-servers/
├── task-formula-ai/
│ └── logs/
│ └── atomikos/
│ ├── task-formula-ai-tmlog.lck
│ └── task-formula-ai-tmlog0.log
└── task-auto-test/
└── logs/
└── atomikos/
├── task-auto-test-tmlog.lck
└── task-auto-test-tmlog0.log
核心原理
为什么自定义 Bean 会导致配置失效?
Spring Boot 的自动配置类 AtomikosJtaConfiguration 使用了条件注解:
java
@Configuration
@ConditionalOnMissingBean(UserTransactionManager.class)
public class AtomikosJtaConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.jta.atomikos.properties")
public UserTransactionManager userTransactionManager() {
// 只有没有自定义 Bean 时才会创建
// 这里会自动读取 YAML 配置
}
}
当你手动定义了 UserTransactionManager Bean 后:
@ConditionalOnMissingBean条件不满足- 自动配置类不会生效
- YAML 中的
spring.jta.atomikos.properties.*配置不会被读取 - Atomikos 使用默认配置(日志输出到当前目录)
Atomikos 配置属性映射
| YAML 属性 | Atomikos 系统属性 | 说明 |
|---|---|---|
log-base-dir |
com.atomikos.icatch.log_base_dir |
日志目录 |
log-base-name |
com.atomikos.icatch.log_base_name |
日志文件基础名称 |
tm-unique-name |
com.atomikos.icatch.tm_unique_name |
事务管理器唯一标识 |
enable-logging |
com.atomikos.icatch.enable_logging |
是否启用日志 |
max-actives |
com.atomikos.icatch.max_actives |
最大活动事务数 |
default-jta-timeout |
com.atomikos.icatch.default_jta_timeout |
默认事务超时 |
如果必须使用自定义 Bean 怎么办?
某些场景下可能需要自定义 Bean(比如添加额外的初始化逻辑),这时可以通过设置系统属性来配置:
java
@Configuration
public class TransactionManagerConfig {
@Value("${spring.jta.atomikos.properties.log-base-dir:./logs/atomikos}")
private String logDir;
@Value("${spring.application.name:app}")
private String appName;
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public UserTransactionManager atomikosTransactionManager() throws Throwable {
// ⚠️ 必须在 init() 调用之前设置系统属性
System.setProperty("com.atomikos.icatch.log_base_dir", logDir);
System.setProperty("com.atomikos.icatch.tm_unique_name", appName);
System.setProperty("com.atomikos.icatch.log_base_name", appName + "-tmlog");
System.setProperty("com.atomikos.icatch.enable_logging", "true");
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
userTransactionManager.init();
return userTransactionManager;
}
}
最佳实践建议
- 优先使用 Spring Boot 自动配置
- 遵循约定优于配置原则
- 减少自定义代码
- 配置更直观、易维护
- 多模块项目务必设置唯一的服务名称
yaml
spring:
application:
name: ${project.artifactId} # 或使用具体名称
使用相对路径配置日志目录
- log-base-dir: ./logs/atomikos # 相对于工作目录
生产环境使用绝对路径
- log-base-dir: /var/logs/${spring.application.name}/atomikos
- 确保每个模块的
tm-unique-name唯一- 避免多个实例冲突
- 便于事务恢复和故障排查
验证清单
- 删除了自定义的
TransactionManagerConfig配置类 - 在
application.yml中正确配置了spring.jta.atomikos.properties.* - 为每个模块设置了不同的
spring.application.name - 清理了旧的 tmlog 文件
- 重启应用后检查日志目录是否正确生成
- 验证事务功能是否正常
常见问题 FAQ
Q1: 配置后仍然在根目录生成 tmlog 怎么办?
A: 检查以下几点:
- 确认已删除所有自定义的
TransactionManagerConfig类 - 清理 Maven 缓存:
mvn clean - 删除旧的 tmlog 文件
- 完全重启应用(不是热重载)
Q2: 多个模块可以共享同一个事务管理器吗?
A: 不建议。每个模块应该有自己独立的事务管理器,通过设置不同的 tm-unique-name 来区分。
Q3: 可以使用环境变量动态配置吗?
A: 可以,支持环境变量替换:
log-base-dir: ${ATOMIKOS_LOG_DIR:./logs/atomikos}
Q4: 生产环境如何配置?
A: 在生产环境配置文件中指定绝对路径:
yaml
# application-prod.yml
spring:
jta:
atomikos:
properties:
log-base-dir: /data/logs/${spring.application.name}/atomikos
enable-logging: true
总结
Spring Boot 的自动配置机制大大简化了 Atomikos 的配置,但前提是不要手动覆盖自动配置的 Bean。当遇到配置不生效的问题时,首先检查是否有自定义 Bean 覆盖了自动配置。
核心要点:
- ❌ 自定义
UserTransactionManagerBean → YAML 配置失效 - ✅ 删除自定义 Bean → YAML 配置生效
- 🔧 必须自定义时 → 通过
System.setProperty()设置
希望这篇文章能帮助你少走弯路!🎉