天天看點

開發中疑難雜怪各類問題整理

本篇用以記錄開發中遇到的各類問題,有些是功力不夠,有些是經驗不足,有些是機制不了解,特整理如下,備忘以用。

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初始化的正确進行。

繼續閱讀