本篇用以記錄開發中遇到的各類問題,有些是功力不夠,有些是經驗不足,有些是機制不了解,特整理如下,備忘以用。
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初始化的正确進行。