java应用Out of Memory的情况下,spring事务会回滚嘛?

   

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);依然会执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值