Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17094ff5]
时间: 2025-05-28 14:46:09 浏览: 29
### 关于 MyBatis 中 `Closing non transactional SqlSession` 的分析与解决方案
#### 问题描述
在使用 MyBatis 框架时,控制台日志频繁出现类似于以下的日志信息:
- 创建新的 `SqlSession`: `DEBUG - Creating a new SqlSession`
- 注册同步失败: `DEBUG - SqlSession [...] was not registered for synchronization because synchronization is not active`
- 非事务型 `SqlSession` 被关闭: `DEBUG - Closing non transactional SqlSession [...]`
这些日志表明,在某些情况下,MyBatis 正常创建并关闭了一个非事务型的 `SqlSession`。然而,如果程序逻辑存在问题或者配置不当,可能会导致异常情况发生。
---
#### 日志含义解析
1. **创建新 `SqlSession`**
当调用 MyBatis 方法(如查询、更新等)时,框架会自动创建一个新的 `SqlSession` 对象来执行 SQL 操作[^1]。
2. **未注册同步**
如果当前线程中没有激活 Spring 的事务管理机制,则不会将 `SqlSession` 注册到事务上下文中。这意味着每次操作都会独立创建和销毁一个 `SqlSession` 实例[^2]。
3. **关闭非事务型 `SqlSession`**
在完成数据库操作后,MyBatis 自动关闭了这个临时创建的 `SqlSession`。这是正常的行为,但如果频繁触发可能意味着存在不必要的多次连接开销[^3]。
---
#### 可能的原因及解决方法
##### 原因一:缺少事务管理器配置
如果没有正确配置 Spring 的事务管理器 (`DataSourceTransactionManager`),即使希望在一个事务范围内执行多个数据库操作,也无法实现真正的事务化管理。此时,MyBatis 将始终以非事务模式工作。
###### 解决方案
确保在 Spring Boot 应用中已正确定义事务管理器,并通过注解启用全局事务支持。例如:
```java
@Configuration
@EnableTransactionManagement // 启用事务管理功能
public class DataSourceConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
```
同时,在服务层方法上添加 `@Transactional` 注解以声明事务边界:
```java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional // 显式声明事务范围
public void updateUser() {
userMapper.updateUserStatus();
userMapper.insertLog(); // 若前一步失败,此处回滚
}
}
```
---
##### 原因二:重复提交或手动关闭 `SqlSession`
如果开发者直接干预了 `SqlSession` 的生命周期(比如手动调用了 `sqlSession.close()`),可能导致资源释放冲突或冗余日志记录。
###### 解决方案
避免显式操作 `SqlSession` 生命周期。通常情况下,Spring 和 MyBatis 已经封装好了相关逻辑,无需人为介入。例如:
```java
@Autowired
private SqlSessionFactory sqlSessionFactory;
// 不推荐的做法
public List<User> getUsersManually() throws Exception {
try (SqlSession session = sqlSessionFactory.openSession()) { // 手动打开 Session
UserMapper mapper = session.getMapper(UserMapper.class);
return mapper.selectAllUsers();
} finally {
sqlSession.close(); // 多次关闭可能引起问题
}
}
// 推荐做法
public List<User> getUsersAutomatically() {
return userMapper.selectAllUsers(); // 让框架自行管理 Session
}
```
---
##### 原因三:JDBC 数据源配置不合理
如果 JDBC 数据源池大小不足或超时设置过短,也可能导致频繁创建和销毁 `SqlSession`,从而增加系统负载。
###### 解决方案
优化数据源配置文件中的参数。例如,在 Spring Boot 的 `application.properties` 文件中调整 HikariCP 默认值:
```properties
spring.datasource.hikari.maximum-pool-size=20 # 最大连接数
spring.datasource.hikari.idle-timeout=300000 # 空闲超时时间(毫秒)
spring.datasource.hikari.connection-timeout=20000 # 获取连接的最大等待时间
```
---
##### 原因四:SQL Mapper XML 文件设计缺陷
复杂的嵌套查询或过多的结果映射可能导致单次请求占用较长时间,进而影响 `SqlSession` 的高效利用。
###### 解决方案
简化 SQL 查询逻辑,减少不必要的关联表加载。可以借助 MyBatis 提供的延迟加载特性降低内存消耗:
```xml
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
```
---
#### 总结
针对 `Closing non transactional SqlSession` 的问题,可以从以下几个方面入手排查和改进:
1. 确认是否正确配置了事务管理器以及合理使用 `@Transactional` 注解。
2. 避免手工干预 `SqlSession` 的生命周期。
3. 调整数据源池参数以适应高并发场景。
4. 设计高效的 SQL 查询语句,充分利用缓存和延迟加载策略。
---
### 示例代码片段
以下是基于 Spring Boot 和 MyBatis 的完整配置示例:
```yaml
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: secret
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
type-handlers-package: com.example.typehandlers
configuration:
lazy-loading-enabled: true
multiple-results-enabled: true
```
```java
// Transactional Service Example
@Service
@Transactional(readOnly = true)
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public List<Order> getOrdersByUserId(Long userId) {
return orderMapper.selectByUserId(userId);
}
@Transactional(readOnly = false)
public void updateOrderStatus(Long orderId, String status) {
orderMapper.updateStatus(orderId, status);
}
}
```
---
阅读全文
相关推荐


















