公交司机解决PSQLException

最近遇到了一个bug,是关于JPA语句的问题,其实代码很简单,就是使用NamedQuery数据库中符合条件的数据进行更新操作,代码如下(其实不想贴代码) 

@NamedQuery(name = "customer.updateSentToBusinessCheckByCustomerIds", 
query = "update Customer as c set c.sentToBusinessCheck = true where c.id in :customerIds")})


很简单就是in 后面传递一个list的参数,根据这个list当中的数值进行条件更新,因为数据量小的时候比如几百、几千还是没有问题的,但是一旦list中的数据变大之后,准确的说是超过三万多就不行了(你知道为什么是三万多吗,或者这么问你知道为什么数值是32767吗),生产上我们这里的list是五万多记录,于是会报如下错误(其实真的不想贴代码):

Internal Exception: org.postgresql.util.PSQLException: An I/O error occured while sending to the backend.


Error Code: 0
Call: UPDATE CUSTOMER SET SENTTOBUSINESSCHECK = ?, ENTITYVERSION = (ENTITYVERSION + ?) 
WHERE
 (ID IN (?,?,?,?,?,?,?,?,?,?......)bind => [60102 parameters bound]

最快速的解决问题的办法——Google(你知道为啥不用百度吗?),从网上找到一篇文章(轻击这里)重点引用如下。(请注意,具体的解决办法不重要,重要的是作者解决问题的思路和行动意识。)  

Not a very concrete message, right? When I first saw this exception I waskind of baffled and disaffected. But after narrowing down the problem in adebug session and looking at the PostgreSQL JDBCdriver’s source code the cause was obvious: the PostgreSQLclient/backend protocol dictates that the number of parameters be send from theclient to the Postgres backend as a 2 byte integer (aaah, now the above message actually makes sense). You’llfind details of the protocol here if you’re brave (my 2-byte friend is definedin the Parse message).  

这下明白了,出现异常的原始是因为JPA实现的时候允许的最大的参数数目是有上限的(废话~)。文章最后也说了解决办法,一旦当参数超过上限这个时候就应该把参数分别传递,在这里就是将list分别传递到JPA语句中进行更新操作。最终代码如下(真的,真的不想贴代码) 

    ......
        emMain.createNamedQuery("customer.updateSentToBusinessCheckByCustomerIds").setParameter("customerIds",customerIds);
        int size=customerIds.size();
        if(size>30000){
            List<Long> customerIdsSplit=new ArrayList<Long>();
            for(int i=0;i<size;i++){
                customerIdsSplit.add(customerIds.get(i));
                if(customerIdsSplit.size()==30000){
                    updateList(customerIdsSplit);
                    customerIdsSplit.clear();
                }
            }
            updateList(customerIdsSplit);
        }else{
            updateList(customerIds);
        }
    ......    

    private void updateList(List<Long> customerIdsSplit) {
        Query query = emMain.createNamedQuery("customer.updateSentToBusinessCheckByCustomerIds")
                     .setParameter("customerIds",customerIdsSplit);
        query.executeUpdate();
    }

关于解决问题的东西到此结束了,但是以上都不是本文的重点,有几点感触比较深刻的。

1. 篇博客自己很喜欢,代码很少重在思路。

2. 看源码,是90%问题的解决之道,前提是时间允许。

3. 一切有因有果(这里指那三万多这个数字是有他的来头的)。

后记

都说程序员,或者软件行业是是需要高智商的,我不这么认为,论据如下:解决完这个问题之后想起来每天都能听到公交车司机咆哮的那句话,“上不去的乘客等下一辆吧!后面跟着一辆呢!!后面的那辆马上就到了!!!”这不就是人太多坐不下然后就需要分批运送么,和上面的问题解决思路是一样的啊!如此可见公交车司机和程序员(或者说工程师)的职位对智商要求是一样的。最后的最后,附图一张聊表心意。

公交司机解决PSQLException_第1张图片

(在车上拍的,当时算了一下,不禁心中一惊)

你可能感兴趣的:(公交司机解决PSQLException)