天天看点

开发中疑难杂怪各类问题整理

本篇用以记录开发中遇到的各类问题,有些是功力不够,有些是经验不足,有些是机制不了解,特整理如下,备忘以用。

1.关于微信公众号程序的 js脚本 变更不生效问题

      变更微信公众号所用的js脚本,不生效。后在引用处添加 js版本号,可以正常变更。疑微信存在 js的缓存机制,但过期时间不了解。 

     具体修改如下:

在网页引用js处添加版本号      xxxxxxxx.js?v=20190609   

   建议: 如果变更所体现的结果不明显,加入一段易于查看是否发生了文件更新的标识为好。

2.开发环境正常,而测试环境不符合开发环境预期的问题排查

主要从以下几个角度:

1)二者文件是否一致

 建议: 如果变更所体现的结果不明显,加入一段易于查看是否发生了文件更新的标识为好。

2)二者运行环境是否一致(包括但不限于jdk版本,服务器编码)

如:UTF-8 汉字占3个或4个字节,但 GBK编码占2个字节,如果报文按照长度截取,若编码格式不正确,可能会造成报文不完整

建议:linux使用echo $LANG 或 locale 查看编码

3)数据库配置是否一致 

如:系统参数,连接参数等是否缺失,是否符合该环境要求

4)个别插件造成的影响

如:密码框等

3.java.net.UnkownHostException: ibatis.apache.org   (或java.net.UnkownHostException: mybatis.org)

排查时可全局搜索 ibatis.apache.org ,可将问题定位在配置文件引用dtd约束处。如果主机没有联网,那么需要将约束改为本地目录。dtd约束文件可在 jar包 /builder/xml/ 文件夹下找到

4.CannotAcquireResourceException

com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.    查看是否缺少数据库连接驱动包,如 ojdbc6 / mysql-connector-java

5.查看jar包版本号

jar包根目录\META-INF\MANIFEST.MF

6.Resource路径下资源文件未找到

排查:1.Resource文件是否编译到项目空间 classes 文件夹下。如未编译,在项目的构建路径中,检查源代码页签下,resource文件夹的“排除”(Excluded)是否为 **,如是,将其改为 “无”(None)

           2.资源文件路径书写是否正确

7.Junit测试只能有一个无参构造(可省略不写,有默认),但不能多

8.关于静态变量的依赖注入

直接对静态变量采用常规@Autowired方式不能完成注入。

解决办法:生成这一变量的setter方法,去掉setter的static属性,将@Autowired加在setter方法上。此种方式简单高效,不做他解。

private static Person person;

@Autowired
public void setPerson(Person person) {
	MyThread.person = person;
}
           

9.Junit测试多线程程序的简易方式

Junit不支持多线程测试,@Test方法体执行结束后,程序即终止,子线程死活不论。

解决办法:打开调试配置,勾选最下方的  “在测试后保持Junit运行”即可,程序无需改动,简单高效。

10. Spring不能管理多线程运行类中的Bean注入

有A,B两个类,现要在A中以多线程方式运行多个B,B中需要注入MessageDao。

Class A{


  public void method{
    
    new Thread(new B()).start();

  }

}


Class B implements Runnable{


  @Autowired
  private MessageDao messageDao; 


}
           

messageDao不能够正常注入。

我个人的解决方案:新建一个类C,作为B的父类,将MessageDao 作为父类静态变量声明并注入(参见第8条)。注意:将变量声明为B类的静态变量,或其父类C的非静态变量均不可。

11.在第10条的条件下,使用ThreadLocal做线程间的数据隔离。创建子线程运行B时需要传递参数完成B的构造,但是在子线程运行时拿不到A类(主线程)构建B时传递的参数。

Class A{


  public void method{
    
    String param = "参数";
    
    new Thread(new B(param)).start();

  }

}


Class B implements Runnable{

  private static ThreadLocal localParam = new ThreadLocal();


  public B(){

  }

  public B(String param){
    localParam.set(param);
  }


}
           

调试时发现,main线程运行A,各个子线程运行B。ThreadLocal以 线程-值 的形式将数据保存在ThreadLocalMap中,由于main调用的构造器,导致子线程并不能以各自名称取得对应的构造数据。解决办法:使用InheritableThreadLocal,实现主线程和子线程的数据传递。

private static InheritableThreadLocal localParam = new InheritableThreadLocal();
           

12.线程池的优势和简单使用

线程池的好处:1.减小创建销毁线程的开销  2.任务到来即可取用线程,无需等待  3.可以管理线程相关的参数(比如线程数(并发数)),调优

简单使用:Executors静态工厂方法  newFixedThreadPool  或  newCachedThreadPool 创建 ExectorService对象。

ExectorService exectorService = Executors.newFixedThreadPool(10);

exectorService.execute(new Thread());

exectorService.shutdown();
           

newFixedThreadPool  是定容的线程池,便于控制线程数(并发数)(理解成出水管),高于并发数的会在队列中等待(进水管),如果并发处理较慢(出水慢),而请求激增(进水快),队列无限增长,可能导致OOM

newCachedThreadPool  自动扩容(自动收缩)的线程池,并发可无限增长,很容易OOM

二者底层使用

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

调优可自定义参数。

13.线程池和ThreadLocal组合使用时,由于线程复用导致脏数据问题

由于线程池的线程复用,比如newFixedThreadPool (size:10)处理13条数据,那么势必有3个线程实现复用,而第一次初始化线程时数据已经绑定完毕了,复用时不重新绑定,导致第11,12,13条数据丢失。

使用Ali开源包 transmittable-thread-local-2.6.1.jar  。

简单使用:

Class A{


  public void method{
    
    String param = "参数";
    
    ExectorService exectorService = Executors.newFixedThreadPool(10);

    exectorService.execute(TtlRunnable.get(new B(param)));

    exectorService.shutdown();

  }

}


Class B implements Runnable{

 private static InheritableThreadLocal localParam = new TransmittableThreadLocal();


  public B(){

  }

  public B(String param){
    localParam.set(param);
  }


}
           

14. Mybatis报sql未正确结束 

检查mapper.xml中sql语句结尾是否有  分号

15.服务器报错但是由于某些原因无法查看报错信息,可用Chrome的开发者工具,Network中查看响应信息,可能有报错信息

16.百度搜 “我的ip”  即可查看手机或PC端IP ,可能有助于运维查询日志

17.调试时改变变量值,可能导致Mybatis调用数据库时不能正确获取mapper中的sql语句

18.JUnit测试所用注解

@ContextConfiguration(location="classpath:applicationContext.xml")
@Runwith(SpringJUnit4ClassRunner.class)
publice class A{

    @Test
    public void method(){

    }

}
           

19.使用maven的clean命令,可能会导致jdk根目录下lib目录中文件丢失

20.SpringMVC的@requestParam注解只能获取get请求拼接的参数或表单形式提交的post请求参数

21.vue打包时会将标签的src属性当做静态资源处理,添加静态资源目录前缀

22.如Base64Encoder类不能导入,可在jre构建路径中删除jre环境重新添加

23.Mapped Statements collection does not contain value for ...(某sql的id)  原因:

       1.未在Mybatis的mapper配置文件中引入该sql所在的xml配置文件

       2.mapper中的xml文件名或路径不对,导致不能正常引入xml

      3.该sql的id是否存在,是否正确

      4.多个xml配置文件的命名空间是否重复

24.在页面加载函数中调用微信扫一扫功能未能实现,为页面按钮添加绑定事件,在事件中可以调起。

25.在Listener中无法注入@Service的问题。

Listener的生命周期由servlet容器管理,Listener由servletContext实例化并调用其contextInitialized方法初始化,但是Service由Spring容器(WebApplicationContext)管理,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例。可以使用Spring提供的工具类WebApplicationContextUtils获得bean。

Service service= WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()).getBean(ServiceImpl.class);
           

Spring上下文绑定在容器上下文ServletContext上,使用工具类WebApplicationContextUtils从ServletContext上获取Spring的上下文WebApplicationContext,再调用getBean()方法获取以完成初始化的bean实例。

注:ContextLoaderListener必须先于自定义的Listener初始化(web.xml中的顺序),保证Spring容器初始化和bean初始化的正确进行。

继续阅读