crontab java -jar --------- java.sql.SQLRecoverableException: 无法从套接字读取更多的数据

前阵子自己尝试用maven和mybatis写了一个小程序,本来是对业务系统的定时任务做监控的。

如果定时任务正常,就继续监控;如果定时任务没有正常写库,就发一个短信给我。

多么简单的需求,就是一个简单的读库操作。crontab里面定时执行一个java -jar,直接执行jar包,jar包代码直接读库,正常则继续;不正常则发短信。

结果倒好,隔三差五的误报警,简直被玩死。瞅来瞅去自己都快对报警短信麻木了。

准备分析这个问题的,结果去看crontab的系统日志,发现自己账户没有权限。但是crontab的定时监控脚本是自己写好保存并启动的。然后分析下来,觉得是因为直接-jar执行,没有跑在容器里面(如果是tomcat执行的话,就相当于跑在tomcat容器里面。log在tomcat里面可以看到)

自己改了一下代码,将原来代码里面的e.printStackTrace();改成了

这样至少可以把crontab的应用层面的log保留下来并自己查看了。观察了几天,发现报错都是下面这一种问题

在网上查了一些帖子,有人说是因为mybatis超时导致的,于是在config.xml中新增了

    <settings>
        <setting name="defaultStatementTimeout" value="720"/>
    </settings>

参数设置,然后发现没有效果。

又有人讲是需要在DataSource段中新增

                <property name="poolPingQuery" value="SELECT SYSDATE FROM dual" />
                <property name="poolPingEnabled" value="true" />

经人指点,应该在DB操作前后打印准确的时间戳,通过时间方便查找问题。于是进行了打印,果然可以看到问题

按照网上的样例,自己写了一个Mybatis读取数据库的代码。如下:
try {
                inputStream = Resources.getResourceAsStream(resource);
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                sqlSession = sqlSessionFactory.openSession();
                Map<String, Object> param = new HashMap<String, Object>();
                param.put("codeA", jobName);
                param.put("codeD", date);
                System.out.println("Before DB access " + String.valueOf(new SimpleDateFormat("yyyyMMdd HH:mm:ss:SSS").format(new Date())));
                tab = sqlSession.selectOne("com.lcd.cf.dao.ConsumeJournalDetailTabMapper.queryReturnCodeOfBatch",
                        param);
                System.out.println("After DB access " + String.valueOf(new SimpleDateFormat("yyyyMMdd HH:mm:ss:SSS").format(new Date())));
            } catch (Exception e) {
                System.out.println("After DB access " + String.valueOf(new SimpleDateFormat("yyyyMMdd HH:mm:ss:SSS").format(new Date())));
                System.out.println(e.toString());
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        System.out.println(e.toString());
                    }
                }
            }
测试下来功能实现了,但是实际跑这段代码发现问题如下:
生产上会连续多次读取多条数据,就是多次调用上面这段逻辑。

观察后台log发现:
20180201 19:30:01:704
Before DB access 20180201 19:30:02:036
Input args: {codeA=放款通知, codeD=20180201}
After DB access 20180201 19:30:58:065
Before DB access 20180201 19:30:58:116
Input args: {codeA=还款提醒1, codeD=20180201}
After DB access 20180201 19:30:58:146
Before DB access 20180201 19:30:58:181
Input args: {codeA=还款提醒2, codeD=20180201}
After DB access 20180201 19:30:58:221
Before DB access 20180201 19:30:58:265
Input args: {codeA=还款提醒3, codeD=20180201}
After DB access 20180201 19:30:58:292
Before DB access 20180201 19:30:58:325
Input args: {codeA=还款提醒4, codeD=20180201}
After DB access 20180201 19:30:58:361
Before DB access 20180201 19:30:58:399
Input args: {codeA=逾期提醒, codeD=20180201}
After DB access 20180201 19:30:58:446
Before DB access 20180201 19:30:58:479
Input args: {codeA=逾期提醒2, codeD=20180201}
After DB access 20180201 19:30:58:563
看时间打印,第一次读取,花了56s,而后面的每次读取都是不到1s就可以搞定。
为什么第一次会这么慢,后面快起来又是为啥?都是同样的逻辑。每次读取数据库都会关闭session的。后续的读库操作,不应该和前面的操作一样的开销吗?

最省事的解决方案是把读取数据库的超时报错调整一下。过两天看效果


更新一下,这个问题我到现在也没有解决,说啥呢,mybatis好像默认60秒超时,我也没有搞清楚到底为什么会超时。有人知道怎么搞,请告知我,有人建议我改成长连接,但是这个定时任务每天就跑三次,长连接好像不合适啊。

猜你喜欢

转载自blog.csdn.net/lcdxiangzi/article/details/79092401