一个方法内部只有查询并且是大量查询优化
问题分析
以前的方法是没有使用任何事务的, 所以使用的不是同一个会话连接
// 获取会话入口, SqlSessionTemplate.java SqlSession sqlSession = getSqlSession( SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); // SqlSessionUtils.java SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); SqlSession session = sessionHolder(executorType, holder); if (session != null) { return session; }
从最初的阿里云提供的 应用实时监控服务 ARMS, 可以看出一个方法内部出现大量查询的时候, 不断的获取(可能是创建)连接、 执行、 回收(可能是释放)连接, 几十次加起来耗时也不少
优化使用同一个连接(会话)
使用同一个连接的情况下, 需要使用到事务(注解事务)
@Transactional(readOnly = true)
public OrderDetailResp orderDetail(@Valid OrderDetailRqt orderDetailRqt) {
Long memberMasterId = orderDetailRqt.getMasterId();
Long orderId = orderDetailRqt.getOrderId();
或者使用到手动事务 (建议使用注解方式)
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionTemplate TransactionTemplate;
@Override
public OrderDetailResp orderDetail(@Valid OrderDetailRqt orderDetailRqt) {
Long memberMasterId = orderDetailRqt.getMasterId();
Long orderId = orderDetailRqt.getOrderId();
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
transactionTemplate.setReadOnly(Boolean.FALSE);
transactionTemplate.setIsolationLevel(TransactionTemplate.getIsolationLevel());
transactionTemplate.setPropagationBehavior(TransactionTemplate.getPropagationBehavior());
transactionTemplate.setTimeout(TransactionTemplate.getTimeout());
TransactionStatus transaction = platformTransactionManager.getTransaction(transactionTemplate);
OrderDetailResp orderDetailResp = new OrderDetailResp();
try {
orderDetailResp.setOrderBaseComposite(orderCompositeManager.getOrderBaseComposite(orderId));
orderDetailResp.setOrderLogisticsComposite(orderCompositeManager.getOrderLogisticsComposite(orderId));
orderDetailResp.setOrderGoodsComposites(orderCompositeManager.getOrderGoodsCompositeList(orderId));
orderDetailResp.setOrderOtherComposite(orderCompositeManager.getOrderOtherComposite(orderId));
OrderServeInfo orderServeInfo = super.getOrderServeInfoForTeamMember(orderId, memberMasterId, 1);
// 其他查询省略
} finally {
platformTransactionManager.commit(transaction);
}
return orderDetailResp;
}
到此, 方法内部大量查询都是使用同一个连接, 减少了获取、 回收连接的耗时
注意事项:
使用上面的情况, 可能会导致其他异常情况, 比如使用到了多数据源,
因为只会获取一次连接; 方法内部的查询不会在去获取连接, 无法获取到其他数据源
如果使用到主从库, 需要注意只读事务是不是走了主库, 如果是则需要考虑解决方法或者不使用只读事务
没有使用只读事务, 同一个SQL, 是可以查询到其他事务提交的最新数据
扩展
不使用只读事务的方式, 使用单条连接, 共用一个
SQLsession
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
自定义
SqlSessionTemplate
, 改造SqlSessionInterceptor
中的获取会话方法, 当事务中获取到的会话为空, 尝试线程变量获取或者其他方式!!!
还需要考虑如何关闭会话!!!
1