1.设置JVM大小:-Xms32m -Xmx32m
2.连接池配置:
poolName: TEST_Mysql_Hikari_Pool
minimumIdle: 10
maximumPoolSize: 1000
maxLifetime: 900000
connectionTimeout: 6000
idleTimeout: 300000
leakDetectionThreshold: 15000
3.新增测试代码
@Transactional(rollbackFor = Exception.class)
@RequestMapping("/testOutOfMemoryAndTransactionRollBack")
public void testRefineClass() throws Exception{
System.out.println("a211c");
myFileMapper.deleteFile("xiaxh1", 5900l);
List<MyBean> files=new ArrayList<MyBean>();
int i=0;
while(true) {
MyBean f=new MyBean();
f.setDocName(UUID.randomUUID().toString());
files.add(f);
if(i++>1000000000) {
break;
}
}
System.out.println(files.size());
}
3.访问/testOutOfMemoryAndTransactionRollBack
4.观察日志
日志1:
[WARN ][TEST_Mysql_Hikari_Pool housekeeper] com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detection triggered for com.mysql.jdbc.JDBC4Connection@25d1ebee on thread http-nio-17000-exec-1, stack trace follows
java.lang.Exception: Apparent connection leak detected
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128)
日志解析: leakDetectionThreshold: 15000 设置了连接被从连接池取出来之后15秒仍然未归还到连接池,则会打印次信息,注意线程是:TEST_Mysql_Hikari_Pool housekeeper,并不是用户请求处理线程:http-nio-17000-exec-*,所以这只是提示信息,并不影响用户线程的执行。
日志2:
[http-nio-17000-exec-1] org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31dbe98f]
[2021-07-24 13:39:26.335][DEBUG][http-nio-17000-exec-1] org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31dbe98f]
[2021-07-24 13:39:26.336][DEBUG][http-nio-17000-exec-1] org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31dbe98f]
日志解析:事务管理器关闭SqlSession
日志3:
[2021-07-24 13:39:26.358][INFO ][http-nio-17000-exec-1] com.zaxxer.hikari.pool.ProxyLeakTask - Previously reported leaked connection com.mysql.jdbc.JDBC4Connection@25d1ebee on thread http-nio-17000-exec-1 was returned to the pool (unleaked)
日志解析:跟日志1相互呼应的,用户请求处理线程在事务处理完毕之后归还数据库连接到连接池,但是这个连接之前已经被报告过借用连接超时。
日志4:
[2021-07-24 13:39:26.395][ERROR][http-nio-17000-exec-1] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause
java.lang.OutOfMemoryError: Java heap space
日志解析:用户请求处理线程抛出OutOfMemoryError异常
查看DB数据库记录,未更新成功
疑问:@Transactional(rollbackFor = Exception.class) 写明的是回滚Exception,为啥Error也回滚了呢?
翻看源码:
类1:DefaultTransactionAttribute
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
类2:RuleBasedTransactionAttribute extends DefaultTransactionAttribute
@Override
public boolean rollbackOn(Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
}
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Winning rollback rule is: " + winner);
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
debug下看到的
如果配置了规则,则按照规则走,如果找不到,依然会调用父类的来判断是否回滚:super.rollbackOn(ex);
这样就很清晰了,虽然配置了回滚规则,如果未命中回滚规则,则父类的回滚规则: return (ex instanceof RuntimeException || ex instanceof Error);依然会执行。