Column 'username' in field list is ambiguous、邮件漏发等问题的分析及解决

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

问题1.Column 'username' in field list is ambiguous

### The error may involve com.fx.oa.module.per.leave.api.shared.domain.PositiveEntity.queryListForPage-Inline

### The error occurred while setting parameters

### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'username' in field list is ambiguous

; SQL []; Column 'username' in field list is ambiguous; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolat

  今天正式系统更新后,打开新建工作,页面报出500错误。打开日志有如上错误。负责处理问题的工程师跟我说,可能是有同事在测试系统数据和代码里都增加了一个名为userName的字段,但没有在正式系统数据库更新表结构导致的。我拿到日志信息,看到是ambiguous,这个单词的意思是username这个字段是不明确、有歧义的。这种错误往往是多个表之间关联查询,而表中有相同字段名称,未为该字段指定所属表引起的。在新建工作页面的底端,有查询办理历史的表格。查询历史时会先将所有任务拿出,由于任务的审批人存储的是用户名,需要进一步关联到用户表取出用户姓名,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT 
             task.processExecutionId,
             process. name  as  processDefineName,
             task.activityName,
             user .userName  as  createUserCode,
             task.status,
             task.description,
             task.finishTime,
             task.createTime
         FROM  T_BPM_PROCESS_TASK task
         LEFT  JOIN  T_BPM_PROCESS_EXECUTION execution  ON  task.processExecutionId = execution.id
         LEFT  JOIN  t_bpm_process_define process  ON  execution.processDefineId = process.id
         LEFT  JOIN  T_SYS_USER  user  ON  task.createUserCode =  user .userCode
         WHERE  task.processExecutionId = #{id}
         ORDER  BY  task.createTime  DESC , task.finishTime  DESC

  在这个版本上线里,我们新上线了高级查询的基于用户的管理权限控制,负责的杜工在t_bpm_process_define中新增加了两个字段,他仿照已经存在的roleCode、roleName,增加了userCode、userName两个字段,而这两个字段至少在档案和用户相关的表广泛被使用。其中这两个字段在我们的系统里就可以被看做是保留字,其他表尽量不要使用。我建议将这两个专用于高级查询的字段加上前缀,而不必修改sql。

表结构修改后该问题消失。

问题2.sql:截取中出现的问题

  本期OA在正式系统上线后,与moss系统并行了一段时间。在这段时间里oa的所有流程及表单均为测试,正式单据在moss里填写。所以我们在流程的显示名称在表单页面均添加了“(测试)”字样,而且页面中凡包含“(测试)”字样的表单,在填写和审批时都会提示“该表单是测试表单,请到moss里填写”。312号是OA表单正式启用,需要将所有的测试字样从系统里抹去。在测试字样添加的时候,由各流程负责同事在系统前端手动添加和保存。如果再在系统页面每张表单打开删除会非常麻烦。经过观察,我发现所有流程的显示名都包含(测试单据)或(测试字样),且几十个流程均未有在名称中包含以上字样。而在测试单据的htmltemplate中,均包含<span style="color:#ff0000;">(测试表单)</span>所以我写了以下sql:

1
2
3
update  t_bpm_process_define  set  name =SUBSTR( NAME  FROM  FOR  INSTR( name , "(测试单据)" )-1)  where  INSTR( name , "(测试单据)" )!=0;
update  t_bpm_form_define  set  template= REPLACE (template,  '(测试单据)' , '' ) where  INSTR(template, '(测试单据)' )!=0;
update  t_bpm_form_define  set  html= REPLACE (html,  '<span style="color:#ff0000;">(测试表单)</span>' , '' ) where  INSTR(html, '<span style="color:#ff0000;">(测试表单)</span>' )!=0;

  执行后,表单倒是没有问题,但第一句的执行出现了可怕的现象,很多流程名称是空的。

第一句中我使用的是字符串的截取,第二、第三句都是替换部分字符串。我最初想可能跟这个有关,实际也确实有关,如果我也用replace函数是没有问题的,原因很简单,如果文本中不包含目标字符串肯定是不会替换的。但用字符串截取从逻辑上也讲得通,为什么会出现这么可怕的结果呢?

  原因就在于我们update没有使用表内联,sql在执行的时候根本没有什么数据去关联它到底该修改哪条数据。

  如果我们将第一条数据修改成这样,就没有问题了:

1
update  t_bpm_process_define a,( select  id, name  from  t_bpm_proces_define  where   INSTR( name , "(测试单据)" )!=0) )b  set  a. name =SUBSTR( NAME  FROM  FOR  INSTR( name , "(测试单据)" )-1)  where  a.id = b.id;

问题3.由于我们公司使用的邮件服务器是Zimbra服务器,由云计算部门购买和维护。OA中的提醒邮件也是通过Zimbra往外发送。对于一些某时段的大批量邮件,比如逾期工作和考勤异常都是在某个时间点上由quartz触发,同时会发出数百封以至上千封邮件。可能对成熟的商用邮件服务器这点压力算不上什么,但对于Zimbra可能已经吃不消了。在云计算和IT的同事协助下,由我对邮件服务器进行了测试,测试用例如下:


测试用例1:100封,总用时约:16min;实收97封,失败3次,3次错误信息均为:javax.mail.MessagingException: Could not connect to SMTP host


测试用例2100封,总用时约:16min;实收100封,失败2次,错误同上。加失败重发机制,失败后等待10s重发,最多重发3次;


测试用例3:每发一封,停留10s,总用时32min;实收100封,失败1次,错误同上;重发机制同用例2.

  关于MessagingException的问题:

  我看了一下几种解释:1.网络;2.防火墙;3.服务器的自我保护,比如防止大批量发送时挂掉或者垃圾邮件,我觉得第三种解释靠谱一些。

后来又做了一些其他压力强度的测试,而且针对MessagingException的错误,一步步跟踪代码,也进行了相关分析

  具体错误信息如下:

javax.mail.MessagingException:   Could   not   connect   to   SMTP   host:   mail.cn.phicomm.com,   port:   25; 
    nested   exception   is: 
                java.net.SocketException:   Software   caused   connection   abort:   connect 
                at   com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1282) 
                at   com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:37 
0) 
                at   javax.mail.Service.connect(Service.java:297) 
                at   javax.mail.Service.connect(Service.java:156) 
                at   javax.mail.Service.connect(Service.java:105) 

  我通读了一下代码,发现是这样的,首先会连接生成serverSocket

1
2
3
4
5
if  (serverSocket !=  null )
         openServer();  // only happens from connect(socket) else
                         // openServer(host, port);
     else
         openServer(host, port);

  以下是openServer中的代码:

1
2
3
4
5
6
7
8
9
10
if  (debug) 
             out.println( "DEBUG SMTP: got bad greeting from host \"" 
             server +  "\", port: " 
             port +  ", response: " 
             r +  "\n" ); 
             throw  new  MessagingException(  "Got bad greeting from SMTP host: "  + server + 
             ", port: " 
             port +  ", response: " 
             r); 
         }

  而debug是一个全局变量,是session的一个属性,其值

Since the debug setting can be turned on only after the Session has been created

  也就是说session未建立就会报MessagingException这个错误。所以我进一步怀疑,我们的发送邮件代码每次都会去重连认证,这个也是代码的问题之一,所以我加了session失效才重连。

  接下来又进行了一次测试,用例如下:

用例1.代码修改如下

1
2
3
4
if  (session ==  null  || session.getDebug()) {
         System.out.println( "第"  + j +  "次重连" );
         session = Session.getDefaultInstance(prop, auth);
     }

结果:没有失败

用例2.仍用1的代码,

结果:但失败1次,失败后未重新获得session,可见失败后session仍有效;

用例3.代码修改如下:

1
2
3
4
5
6
7
8
9
if  (session ==  null  || session.getDebug()) {
             // 如果需要身份验证,创建一个账号密码验证器
             if  (mail.isValidate()) {
                 auth =  new  MailAuthenticator(mail.getUserName(),
                         mail.getPassword());
             }
             System.out.println( "第"  + j +  "次重连" );
             session = Session.getDefaultInstance(prop, auth);
         }

结果:有1次失败,失败后未重连。

  通过以上测试,是否每次重新获得session对效率 没有影响,对异常的发生也没有影响。异常报出后,session仍有效,并且可以重发。

  经过三轮测试,其实我们可以发现重发机制已经可以保证邮件的完全送达。

重发的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
          * Temporary mechanism: automatic resend mail
          * @author chao.gao
          * @date 2015-2-4 上午9:27:59
          * @param mail
          * @return
          */
         public  static  boolean  sendHtmlMail(BasicMail mail){
             
             if (sendHtmlMail_(mail)){
                 return  true ;
             else {
                 int  i =  0 ;
                 while (!sendHtmlMail_(mail) && i <  3 ){               
                     try 
                         i++;
                         Thread.sleep( 1000 * 60 );
                     catch  (InterruptedException e) {
                         LOGGER.error( "resend mail error" , e);   
                     }
                 }
                 return  true ;
             }
         }

  加入重发机制运行了一段时间,未再发现类似的漏发现象。








     本文转自 gaochaojs 51CTO博客,原文链接:http://blog.51cto.com/jncumter/1620095,如需转载请自行联系原作者



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
Apache 索引
精进Hudi系列|Apache Hudi索引实现分析(五)之基于List的IndexFileFilter
精进Hudi系列|Apache Hudi索引实现分析(五)之基于List的IndexFileFilter
17 0
|
29天前
Cause: java.sql.SQLIntegrityConstraintViolationException: Column ‘id‘ in field list is ambiguous
Cause: java.sql.SQLIntegrityConstraintViolationException: Column ‘id‘ in field list is ambiguous
18 0
|
5月前
|
容器
List源码模拟与分析
List源码模拟与分析
|
8月前
|
JSON Java 应用服务中间件
TypeToken分析(json字符串- list对象)
TypeToken分析(json字符串- list对象)
71 0
|
存储 算法 安全
初阶C++——STL——string类、vector类和list类(使用方法+模拟实现+测试+思路分析)
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本--所有STL实现版本的始祖。
312 0
初阶C++——STL——string类、vector类和list类(使用方法+模拟实现+测试+思路分析)
|
JavaScript 前端开发 云计算
PIE-engine 教程 ——云计算当中的list列表案例分析(for循环list)
PIE-engine 教程 ——云计算当中的list列表案例分析(for循环list)
114 0
PIE-engine 教程 ——云计算当中的list列表案例分析(for循环list)
|
云计算
PIE-engine 教程 ——云计算当中的map()映射函数list列表映射案例分析
PIE-engine 教程 ——云计算当中的map()映射函数list列表映射案例分析
94 0
PIE-engine 教程 ——云计算当中的map()映射函数list列表映射案例分析
|
安全 Java 容器
深入浅出分析 Collection 中的 List 接口(下)
在前面的文章集合系列中,我相信大部分朋友对 Java 容器整体架构都有了初步的了解,那么本文主要是想详细的介绍以下 List 接口实现类之间的区别!
深入浅出分析 Collection 中的 List 接口(下)
|
存储 安全 Java
深入浅出分析 Collection 中的 List 接口(上)
在前面的文章集合系列中,我相信大部分朋友对 Java 容器整体架构都有了初步的了解,那么本文主要是想详细的介绍以下 List 接口实现类之间的区别!
深入浅出分析 Collection 中的 List 接口(上)
List中subList方法抛出异常java.util.ConcurrentModificationException原理分析
List中subList方法抛出异常java.util.ConcurrentModificationException原理分析
146 0
List中subList方法抛出异常java.util.ConcurrentModificationException原理分析