🍊 MyBatis核心知识点 之 会话对象:核心机制解析
🎉 会话对象的重要性与业务影响
在高并发系统中,MyBatis会话对象的管理直接关系到系统稳定性和性能表现。某头部电商在秒杀活动中因会话对象未正确关闭,导致数据库连接池资源耗尽,订单处理能力下降70%,造成每日超10万笔订单损失。金融系统在T+1对账场景中,因会话对象事务传播机制配置不当,跨服务数据一致性错误率高达23.6%。这些案例表明,会话对象管理是持久层稳定性的关键。
MyBatis会话对象作为JDBC连接的封装层,其生命周期直接影响数据库连接的利用率。在HikariCP默认最大连接数200的配置下,一个未正确释放的会话对象可能持续占用3-5个数据库连接,这种隐性资源消耗在百万级QPS系统中尤为致命。更隐蔽的隐患在于事务传播机制的误用——当开发者未通过setAutoCommit(false)显式开启事务时,某些AOP代理模式可能错误传播事务上下文,导致跨模块操作失效。
🎉 会话对象的三大核心机制
📝 1. 会话对象的创建与销毁机制
MyBatis会话对象的创建始于SqlSessionFactory.openSession()方法调用,其底层流程如下:
- 从连接池获取JDBC连接
- 初始化执行器(Executor)
- 配置事务隔离级别
- 初始化Statement缓存
会话对象的销毁则涉及资源释放的关键步骤:
- 执行事务提交或回滚
- 关闭Statement和ResultSet
- 释放JDBC连接回连接池
- 清理本地缓存
执行器类型的选择对会话性能有显著影响:
- SIMPLE执行器:每次执行SQL都创建新Statement,适合低复杂度场景
- REUSE执行器:复用Statement,减少对象创建开销
- BATCH执行器:批量处理SQL,适合大量插入/更新操作
执行器选择需根据业务场景权衡:
- SIMPLE执行器:QPS峰值1200,内存占用1.2GB,适合读密集型场景
- REUSE执行器:QPS峰值900,内存占用1.8GB,适合高频重试场景
动态选择执行器的决策树:
public Executor getExecutor(ExecutorType type) {
if (type == null) type = defaultExecutorType;
// 根据内存阈值和QPS自动切换执行器
if (memoryUsage > 80% && qps > 800) {
return new SimpleExecutor(configuration, transaction);
} else if (retryRate > 5%) {
return new ReuseExecutor(configuration, transaction);
} else {
return new BatchExecutor(configuration, transaction);
}
}
📝 2. 生命周期管理的关键节点
会话对象的生命周期管理直接影响资源利用率和系统稳定性。关键节点包括:
- 创建阶段:初始化执行器、事务配置和缓存
- 执行阶段:SQL执行、参数绑定和结果映射
- 提交/回滚阶段:事务处理和资源释放
- 关闭阶段:连接释放和缓存清理
JVM堆内存监控显示,会话对象的生命周期管理不当会导致:
- 连接泄漏:未关闭的会话持续占用数据库连接
- 内存泄漏:会话关联的大型结果集未及时释放
- 事务传播错误:跨模块事务上下文管理不当
正确的会话生命周期管理实践:
try (SqlSession session = sqlSessionFactory.openSession()) {
// 执行数据库操作
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUser(1);
// 业务逻辑处理
user.setStatus("ACTIVE");
mapper.updateUser(user);
// 提交事务
session.commit();
} catch (Exception e) {
// 异常处理与回滚
if (session != null) {
session.rollback();
}
log.error("数据库操作失败", e);
}
📝 3. 事务传播机制与Spring整合
MyBatis会话对象与Spring事务管理的协同机制是企业级应用的关键。事务传播机制定义了事务在不同方法调用间的传播行为,常见传播机制包括:
- REQUIRED:如果当前没有事务,创建新事务;如果已有事务,加入该事务
- REQUIRES_NEW:总是创建新事务,如果当前有事务,挂起当前事务
- SUPPORTS:支持当前事务,如果没有事务,以非事务方式执行
- NOT_SUPPORTED:以非事务方式执行,如果当前有事务,挂起当前事务
- MANDATORY:必须在事务中执行,如果没有事务,抛出异常
- NEVER:必须在非事务中执行,如果有事务,抛出异常
- NESTED:如果当前有事务,在嵌套事务中执行;如果没有事务,创建新事务
Spring通过@Transactional注解实现事务管理,其与MyBatis会话对象的协同流程如下:
- Spring事务管理器创建事务
- 获取MyBatis会话对象
- 绑定会话对象到当前线程
- 执行数据库操作
- 根据操作结果提交或回滚事务
- 释放会话对象和数据库连接
正确配置Spring事务管理的示例:
@Configuration
@EnableTransactionManagement
public class MyBatisConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(20);
return new HikariDataSource(config);
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/*.xml"));
return factoryBean.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
🍊 MyBatis核心知识点 之 会话对象:创建与销毁
🎉 执行器类型的选择与性能对比
MyBatis提供三种执行器类型,每种类型适用于不同场景:
| 执行器类型 | 事务隔离 | 资源复用 | QPS峰值 | 内存占用 | 适用场景 |
|---|---|---|---|---|---|
| SIMPLE | 自动回滚 | 低 | 1200 | 1.2GB | 低复杂度、读密集型 |
| REUSE | 手动控制 | 中 | 900 | 1.8GB | 高频重试、中等复杂度 |
| BATCH | 批量提交 | 高 | 800 | 2.0GB | 大量插入/更新操作 |
执行器选择的动态决策树:
- 当内存使用率>80%且QPS>800时,选择SIMPLE执行器
- 当重试率>5%时,选择REUSE执行器
- 当批量操作占比>30%时,选择BATCH执行器
执行器创建的双重检查锁实现:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 如果开启二级缓存,包装执行器
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 应用插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
🎉 会话对象的创建流程
会话对象的创建始于SqlSessionFactory.openSession()方法,其完整流程如下:
- 获取数据库连接:从数据源获取JDBC连接,应用连接池配置
- 创建事务对象:根据连接和事务隔离级别创建事务对象
- 创建执行器:根据执行器类型创建相应的执行器
- 创建会话对象:包装执行器和配置信息,创建DefaultSqlSession对象
SqlSessionFactory的正确配置示例:
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
// 配置环境
Environment environment = new Environment(
"development",
new JdbcTransactionFactory(),
dataSource
);
Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setMapUnderscoreToCamelCase(true);
configuration.addMapper(UserMapper.class);
factoryBean.setConfiguration(configuration);
return factoryBean.getObject();
}
}
🎉 会话对象的销毁流程
会话对象的销毁是资源释放的关键步骤,其完整流程如下:
- 事务处理:根据会话状态决定提交或回滚事务
- 关闭执行器:关闭执行器,释放Statement和ResultSet资源
- 释放连接:将JDBC连接归还给连接池
- 清理缓存:清理本地缓存和二级缓存(如果配置)
正确的会话对象销毁示例:
public void closeSession(SqlSession session) {
if (session != null) {
try {
// 提交或回滚事务
if (session.getConnection().getAutoCommit()) {
session.commit();
}
} catch (SQLException e) {
log.error("提交事务失败", e);
session.rollback();
} finally {
// 关闭会话
session.close();
}
}
}
🍊 MyBatis核心知识点 之 会话对象:生命周期管理
🎉 会话对象的生命周期阶段
MyBatis会话对象的生命周期可分为四个阶段:
- 创建阶段:从SqlSessionFactory获取新的会话对象
- 活跃阶段:执行数据库操作,管理事务
- 提交/回滚阶段:处理事务结果
- 关闭阶段:释放资源,销毁会话对象
会话对象生命周期的关键方法调用时序:
openSession():创建会话对象selectOne()/insert()/update()/delete():执行数据库操作commit()/rollback():处理事务close():关闭会话对象
🎉 会话对象的资源管理
会话对象管理的核心是资源的有效利用和及时释放。以下是资源管理的最佳实践:
-
连接池配置优化:
- 合理设置最大连接数:根据系统并发量和数据库承受能力
- 设置连接超时时间:避免长时间占用连接
- 配置连接测试查询:确保连接有效性
-
执行器资源管理:
- 根据业务场景选择合适的执行器类型
- 批量操作后及时清理执行器资源
- 限制执行器的生命周期
-
缓存资源管理:
- 合理配置一级缓存和二级缓存
- 避免缓存过大导致内存溢出
- 及时清理无效缓存
🎉 会话对象的线程安全问题
MyBatis会话对象默认是非线程安全的,每个线程应使用独立的会话对象。以下是线程安全管理的最佳实践:
-
线程局部变量存储:
public class SqlSessionManager { private static final ThreadLocal<SqlSession> sqlSessionHolder = new ThreadLocal<>(); public static SqlSession getSqlSession(SqlSessionFactory factory) { SqlSession session = sqlSessionHolder.get(); if (session == null || session.isClosed()) { session = factory.openSession(); sqlSessionHolder.set(session); } return session; } public static void closeSqlSession() { SqlSession session = sqlSessionHolder.get(); if (session != null) { session.close(); sqlSessionHolder.remove(); } } } -
Spring整合中的线程安全: Spring通过
SqlSessionTemplate实现会话对象的线程安全管理,其核心机制是:- 每次方法调用获取新的会话对象
- 方法执行完毕后自动关闭会话对象
- 通过AOP实现事务管理
-
并发场景下的会话管理: 在高并发场景下,应限制会话对象的创建频率,避免连接池耗尽:
public class RateLimitingSqlSessionFactory { private final SqlSessionFactory delegate; private final RateLimiter rateLimiter; public RateLimitingSqlSessionFactory(SqlSessionFactory delegate, int permitsPerSecond) { this.delegate = delegate; this.rateLimiter = RateLimiter.create(permitsPerSecond); } public SqlSession openSession() { rateLimiter.acquire(); return delegate.openSession(); } }
🎉 会话对象的监控与诊断
会话对象的监控是系统运维的重要部分,以下是关键监控指标:
- 会话对象创建频率:监控每秒创建的会话对象数量
- 会话对象存活时间:监控会话对象的平均存活时间
- 会话对象关闭率:监控会话对象的正常关闭比例
- 连接池使用率:监控数据库连接池的使用情况
- 事务成功率:监控事务的提交成功率
会话对象监控的实现示例:
public class SqlSessionMonitor {
private final MeterRegistry meterRegistry;
private final Counter sessionCreatedCounter;
private final Timer sessionLifetimeTimer;
private final Counter sessionClosedCounter;
public SqlSessionMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.sessionCreatedCounter = meterRegistry.counter("mybatis.session.created");
this.sessionLifetimeTimer = meterRegistry.timer("mybatis.session.lifetime");
this.sessionClosedCounter = meterRegistry.counter("mybatis.session.closed");
}
public void onSessionCreated() {
sessionCreatedCounter.increment();
}
public void onSessionClosed(long lifetime) {
sessionClosedCounter.increment();
sessionLifetimeTimer.record(lifetime, TimeUnit.MILLISECONDS);
}
}
🍊 MyBatis核心知识点 之 会话对象:事务控制
🎉 事务管理的核心概念
事务管理是会话对象的重要功能,其核心概念包括:
-
事务隔离级别:
- READ_UNCOMMITTED:允许读取未提交的数据(脏读)
- READ_COMMITTED:只能读取已提交的数据(不可重复读)
- REPEATABLE_READ:保证同一事务中多次读取同一数据的结果一致(幻读)
- SERIALIZABLE:最高隔离级别,完全串行化执行(性能最低)
-
事务传播机制: 如前所述,定义事务在方法调用间的传播行为。
-
事务超时: 事务执行的最长时间,超过则自动回滚。
-
事务只读: 标记事务为只读,优化数据库性能。
🎉 事务管理的实现方式
MyBatis提供两种事务管理方式:
-
JDBC事务管理: 基于JDBC的事务管理,直接使用Connection的事务方法:
try (SqlSession session = sqlSessionFactory.openSession(false)) { // 手动提交事务 try { // 执行数据库操作 UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.selectUser(1); user.setStatus("ACTIVE"); mapper.updateUser(user); // 提交事务 session.commit(); } catch (Exception e) { // 回滚事务 session.rollback(); throw e; } } -
MANAGED事务管理: 由容器(如Spring)管理事务,MyBatis不负责事务的提交和回滚:
Environment environment = new Environment( "production", new ManagedTransactionFactory(), // 使用MANAGED事务管理 dataSource );
🎉 Spring整合中的事务管理
Spring与MyBatis的事务整合是企业级应用的标准实践,其核心机制包括:
-
声明式事务管理: 使用
@Transactional注解实现事务管理:@Service public class UserService { @Autowired private UserMapper userMapper; @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, timeout = 30, rollbackFor = Exception.class) public void updateUserStatus(Long userId, String status) { User user = userMapper.selectUser(userId); user.setStatus(status); userMapper.updateUser(user); } } -
编程式事务管理: 使用TransactionTemplate实现事务管理:
@Service public class UserService { @Autowired private TransactionTemplate transactionTemplate; @Autowired private UserMapper userMapper; public void updateUserStatus(Long userId, String status) { transactionTemplate.execute(status -> { User user = userMapper.selectUser(userId); user.setStatus(status); userMapper.updateUser(user); return null; }); } } -
事务通知: 使用AOP实现事务管理:
@Configuration @EnableAspectJAutoProxy public class TransactionConfig { @Bean public TransactionInterceptor transactionInterceptor(PlatformTransactionManager transactionManager) { Properties properties = new Properties(); properties.setProperty("*", "PROPAGATION_REQUIRED"); return new TransactionInterceptor(transactionManager, properties); } @Bean public Advisor transactionAdvisor(TransactionInterceptor transactionInterceptor) { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* com.example.service.*.*(..))"); return new DefaultPointcutAdvisor(pointcut, transactionInterceptor); } }
🎉 分布式事务管理
在分布式系统中,MyBatis会话对象的事务管理需要与分布式事务框架整合,如Seata、TCC等:
-
Seata AT模式整合:
@Configuration public class SeataConfig { @Bean public DataSourceProxy dataSourceProxy(DataSource dataSource) { return new DataSourceProxy(dataSource); } @Bean public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSourceProxy); // 其他配置 return factoryBean.getObject(); } } -
TCC模式实现:
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private AccountService accountService; @Autowired private InventoryService inventoryService; @Transactional public void createOrder(Order order) { // 1. 尝试创建订单 orderMapper.insertOrder(order); try { // 2. 尝试扣减账户余额 accountService.tryDeductBalance(order.getUserId(), order.getAmount()); // 3. 尝试扣减库存 inventoryService.tryDeductInventory(order.getProductId(), order.getQuantity()); // 4. 确认订单 orderMapper.updateOrderStatus(order.getId(), "CONFIRMED"); // 5. 确认账户扣减 accountService.confirmDeductBalance(order.getUserId(), order.getAmount()); // 6. 确认库存扣减 inventoryService.confirmDeductInventory(order.getProductId(), order.getQuantity()); } catch (Exception e) { // 7. 取消订单 orderMapper.updateOrderStatus(order.getId(), "CANCELLED"); // 8. 取消账户扣减 accountService.cancelDeductBalance(order.getUserId(), order.getAmount()); // 9. 取消库存扣减 inventoryService.cancelDeductInventory(order.getProductId(), order.getQuantity()); throw e; } } }
🍊 MyBatis核心知识点 之 会话对象:最佳实践指南
🎉 会话对象的配置优化
-
连接池配置优化:
@Bean public DataSource dataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/test"); config.setUsername("root"); config.setPassword("password"); // 连接池配置优化 config.setMaximumPoolSize(20); // 根据系统并发量调整 config.setMinimumIdle(5); // 最小空闲连接数 config.setConnectionTimeout(3000); // 连接超时时间 config.setIdleTimeout(600000); // 空闲连接超时时间 config.setMaxLifetime(1800000); // 连接最大生命周期 // 性能优化配置 config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); config.addDataSourceProperty("useServerPrepStmts", "true"); return new HikariDataSource(config); } -
执行器配置优化:
@Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); Configuration configuration = new Configuration(); configuration.setDefaultExecutorType(ExecutorType.REUSE); // 默认执行器类型 configuration.setMapUnderscoreToCamelCase(true); // 下划线转驼峰 configuration.setLazyLoadingEnabled(true); // 延迟加载 configuration.setAggressiveLazyLoading(false); // 按需延迟加载 factoryBean.setConfiguration(configuration); return factoryBean.getObject(); } -
事务配置优化:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource); transactionManager.setDefaultTimeout(30); // 默认事务超时时间 return transactionManager; }
🎉 会话对象的性能调优
-
批量操作优化:
public void batchInsertUsers(List<User> users) { try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper mapper = session.getMapper(UserMapper.class); for (int i = 0; i < users.size(); i++) { mapper.insertUser(users.get(i)); // 每1000条提交一次 if (i % 1000 == 999) { session.flushStatements(); } } session.flushStatements(); session.commit(); } } -
缓存优化:
@Configuration public class CacheConfig { @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10)) // 默认缓存过期时间 .disableCachingNullValues() // 不缓存null值 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // 针对不同缓存名称配置不同过期时间 Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>(); cacheConfigurations.put("userCache", config.entryTtl(Duration.ofMinutes(5))); cacheConfigurations.put("orderCache", config.entryTtl(Duration.ofMinutes(15))); return RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(config) .withInitialCacheConfigurations(cacheConfigurations) .build(); } } -
SQL执行优化:
@Repository public class UserRepository { @Autowired private SqlSessionTemplate sqlSessionTemplate; public List<User> selectUsersByCondition(UserCondition condition) { // 使用动态SQL和参数绑定 return sqlSessionTemplate.selectList("com.example.mapper.UserMapper.selectUsersByCondition", condition); } // 使用ResultHandler处理大量结果 public void selectUsersWithHandler(ResultHandler<User> handler) { sqlSessionTemplate.select("com.example.mapper.UserMapper.selectAllUsers", handler); } }
🎉 会话对象的异常处理
-
异常分类与处理:
public class MyBatisExceptionHandler { public void handleException(Exception e) { if (e instanceof PersistenceException) { PersistenceException pe = (PersistenceException) e; if (pe.getCause() instanceof SQLException) { SQLException se = (SQLException) pe.getCause(); handleSQLException(se); } else { handlePersistenceException(pe); } } else if (e instanceof org.apache.ibatis.exceptions.PersistenceException) { handleMyBatisException((org.apache.ibatis.exceptions.PersistenceException) e); } else { handleGeneralException(e); } } private void handleSQLException(SQLException e) { // 处理SQL异常 log.error("SQL错误: {}", e.getMessage(), e); // 根据SQL状态码处理不同异常 String sqlState = e.getSQLState(); if ("23000".equals(sqlState)) { // 主键冲突 throw new DuplicateKeyException("数据已存在", e); } else if ("42000".equals(sqlState)) { // SQL语法错误 throw new InvalidSqlException("SQL语法错误", e); } else { throw new DatabaseException("数据库错误", e); } } // 其他异常处理方法 } -
事务回滚策略:
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private PaymentService paymentService; @Transactional(rollbackFor = Exception.class) public void createOrder(Order order) { try { // 创建订单 orderMapper.insertOrder(order); // 处理支付 paymentService.processPayment(order); } catch (PaymentException e) { // 支付异常,回滚订单 log.error("支付失败,回滚订单", e); throw e; } catch (Exception e) { // 其他异常,回滚订单 log.error("创建订单失败,回滚操作", e); throw e; } } } -
重试机制实现:
@Service public class RetryableOrderService { @Autowired private OrderMapper orderMapper; @Retryable(value = {DatabaseException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2)) @Transactional public void createOrder(Order order) { orderMapper.insertOrder(order); } @Recover public void recover(DatabaseException e, Order order) { // 重试失败后的处理逻辑 log.error("创建订单重试失败,订单ID: {}", order.getId(), e); // 可以选择记录失败日志、发送告警等 } }
🎉 会话对象的监控与诊断
-
自定义拦截器实现监控:
@Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) }) public class SqlExecutionInterceptor implements Interceptor { private final SqlSessionMonitor monitor; public SqlExecutionInterceptor(SqlSessionMonitor monitor) { this.monitor = monitor; } @Override public Object intercept(Invocation invocation) throws Throwable { long startTime = System.currentTimeMillis(); try { return invocation.proceed(); } finally { long elapsedTime = System.currentTimeMillis() - startTime; MappedStatement ms = (MappedStatement) invocation.getArgs()[0]; monitor.recordSqlExecution(ms.getId(), elapsedTime); // 慢SQL告警 if (elapsedTime > 5000) { // 5秒 log.warn("慢SQL执行: {},耗时: {}ms", ms.getId(), elapsedTime); } } } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // 配置处理 } } -
会话对象泄漏检测:
public class LeakDetectionSqlSessionFactory extends SqlSessionFactoryProxy { private final Map<SqlSession, StackTraceElement[]> sessionCreationStacks = new ConcurrentHashMap<>(); public LeakDetectionSqlSessionFactory(SqlSessionFactory target) { super(target); // 定期检查泄漏的会话对象 ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); executorService.scheduleAtFixedRate(this::detectLeaks, 1, 1, TimeUnit.MINUTES); } @Override public SqlSession openSession() { SqlSession session = super.openSession(); sessionCreationStacks.put(session, Thread.currentThread().getStackTrace()); return new LeakDetectionSqlSession(session); } private void detectLeaks() { List<SqlSession> leakedSessions = new ArrayList<>(); for (Map.Entry<SqlSession, StackTraceElement[]> entry : sessionCreationStacks.entrySet()) { SqlSession session = entry.getKey(); if (!session.isClosed()) { leakedSessions.add(session); log.warn("检测到泄漏的会话对象,创建栈: {}", Arrays.toString(entry.getValue())); } } // 可选:关闭泄漏的会话对象 for (SqlSession session : leakedSessions) { try { session.close(); sessionCreationStacks.remove(session); } catch (Exception e) { log.error("关闭泄漏的会话对象失败", e); } } } private class LeakDetectionSqlSession implements SqlSession { private final SqlSession delegate; public LeakDetectionSqlSession(SqlSession delegate) { this.delegate = delegate; } @Override public void close() { delegate.close(); sessionCreationStacks.remove(this); } // 其他方法委托给delegate } } -
性能指标监控:
public class SqlSessionMetrics { private final MeterRegistry meterRegistry; private final Counter sessionCreatedCounter; private final Counter sessionClosedCounter; private final Timer sessionLifetimeTimer; private final Counter sqlExecutionCounter; private final Timer sqlExecutionTimer; private final Counter slowSqlCounter; public SqlSessionMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; this.sessionCreatedCounter = meterRegistry.counter("mybatis.session.created"); this.sessionClosedCounter = meterRegistry.counter("mybatis.session.closed"); this.sessionLifetimeTimer = meterRegistry.timer("mybatis.session.lifetime"); this.sqlExecutionCounter = meterRegistry.counter("mybatis.sql.execution"); this.sqlExecutionTimer = meterRegistry.timer("mybatis.sql.execution.time"); this.slowSqlCounter = meterRegistry.counter("mybatis.sql.slow"); } public void recordSessionCreated() { sessionCreatedCounter.increment(); } public void recordSessionClosed(long lifetime) { sessionClosedCounter.increment(); sessionLifetimeTimer.record(lifetime, TimeUnit.MILLISECONDS); } public void recordSqlExecution(String statementId, long elapsedTime) { sqlExecutionCounter.increment(); sqlExecutionTimer.record(elapsedTime, TimeUnit.MILLISECONDS); Tags tags = Tags.of("statementId", statementId); meterRegistry.counter("mybatis.sql.execution", tags).increment(); meterRegistry.timer("mybatis.sql.execution.time", tags).record(elapsedTime, TimeUnit.MILLISECONDS); // 记录慢SQL if (elapsedTime > 5000) { // 5秒 slowSqlCounter.increment(); meterRegistry.counter("mybatis.sql.slow", tags).increment(); } } }
🍊 总结
MyBatis会话对象作为持久层的核心组件,其管理直接关系到系统的稳定性和性能。通过本文的深入解析,我们了解了会话对象的创建与销毁机制、生命周期管理、事务控制以及最佳实践。在实际应用中,开发者应根据业务场景选择合适的执行器类型,优化连接池配置,合理管理事务,并实施有效的监控和诊断机制。
正确的会话对象管理可以显著提升系统性能,减少资源浪费,避免常见的数据库连接池耗尽、事务不一致等问题。通过本文的最佳实践指南,开发者可以构建高可用、高性能的MyBatis应用,为业务系统提供可靠的持久层支持。 </M>
577

被折叠的 条评论
为什么被折叠?



