在一個沒有互聯網公司上班節奏的互聯網公司上班,是一種什么樣的體驗?錢多活少少加班。
但是不要太羨慕我,因為,這家公司要撐不多久了。據總裁說,撐到年末,生則還罷,死則好散。剛畢業就進入一家走下坡路,到今日奄奄一息的公司,我也算是“走運”啦。感恩的是自己沒有被裁掉,并且在這節奏不快的日子遇到好老大、好同事,做項目,不斷學習著、進步著。
前幾天看到得到招有代碼潔癖的工程師,我聯想到一起合作過幾周的同事。他差不多就是有代碼潔癖的人,注釋寫得……我說不明白,就是一切都很規范。我還寫不了多高明的代碼,至少做到規范吧。
本周總結就從代碼規范之打日志開始:
1. 代碼規范-日志打印
打日志的作用之一是方便排查問題(也有注釋的作用,我還沒想到其他作用……)。不然報個錯、拋個異常,你都不知道是什么原因導致的,是傳參錯了,還是邏輯錯了?不明所以會很抓狂。
首先,日志的打印格式是在Spring配置文件中定義的,例如:
<Pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} -%5p ${PID:-} [%15.15t] %-40.40logger{39} : %m%n
</Pattern>
這里不詳細解釋其中參數的含義了(因為我還不懂==!)
其次,在源文件中注意在關鍵位置打日志
最基本的,要打日志的位置:入參,出參,異常信息……
注意日志要打得有信息含量。舉例沒有信息含量的日志:
log.info("交易成功。"); // 這對于我看前后的問題沒有幫助好吧,至少打印一下返回什么消息了吧。
比較有信息量的日志:
log.info("交易成功, 返回的消息為:{}", msg.toString());
另外,定義打日志的規范,每個方法定義自己的日志前綴。什么意思?我們一般會打印日志生成的類的名字,如果再追加方法名,能將日志粒度細化,更容易定位問題。出現問題了,你一看方法名,能大概知道程序執行到哪個環節出問題了。
我現在打日志的套路:
public void myMethod(String aStr) {
? ? // 日志前綴:方法名
? ? String logPrefix = Thread.currentThread().getStackTrace()[1].getMethodName() +"(): ";?
? ? log.info("{}我是一行日志:{}", logPrefix, aStr);
? ? // 其他代碼
}
2. SQLException: Unknown error 1205
這周在測代碼,到了更新表那步的時候,長時間不返回,拋了一個異常。拋異常不怕,怕的是你告訴我它是“Unknown error”。好吧,有用的信息是執行SQL語句的時候出現問題了,錯誤碼是1205,現象是程序執行到一個位置長時間(好幾秒的樣子)不往下進行,最后拋了異常,debug結束。
從異常信息來看是MySQL數據庫出現問題了,去Mysql直接執行這條sql也出現同樣的現象,長時間不返回,最后報了一個1205。這種情況,要么是鎖等待,要么是有沒提交的事務,導致其他SQL語句無法執行。
(1)檢查是否存在鎖等待
select * from information_schema.innodb_lock_waits; -- 查看是否有鎖等待
show full processlist; -- 查看所有運行著的進程,是否有跟鎖有關的進程
(2)查看未提交事務
SELECT * FROM information_schema.INNODB_TRX; -- 查看未提交的事務
SELECT trx_mysql_thread_id FROM information_schema.INNODB_TRX; -- 查看事務的線程id
kill some_id; -- 停掉事務,kill的是trx_mysql_thread_id
在我這個問題場景中沒有鎖等待,但查出了未提交事務。我kill掉這個事務之后,SQL語句就可以執行了。至于這個事務是怎么冒出來的,我也不知道==!
如果拋的異常帶有lock wait的信息,那就是有鎖等待了。
3. 接著聊Mysql
順著Mysql接著碼一下這2個月以來自己寫過的關于索引、事件、存儲過程的SQL語句。這部分沒什么,就是Mysql的語法,如果你很熟,此部分可以跳過:
(1)索引操作
-- 加索引
alter table TABLE_NAME add index idx_name (COLUMN_NAME);
-- 刪索引
drop index idx_name?on TABLE_NAME;
-- 查看索引
show index from TABLE_NAME;
加索引的講究以后再說(這個我還是知道一點的)。
(2)事件調度器
Mysql的事件調度器,作用類似linux下的crontab,java中的scheduler。可以定時執行某項任務。
-- 查看事件調度器
SHOW VARIABLES LIKE 'event_scheduler';
-- 打開事件調度器
SET GLOBAL event_scheduler = ON;
-- 刪除事件調度器
DROP EVENT IF EXISTS event_name;
-- 創建事件調度器
CREATE EVENT event_name ON SCHEDULE EVERY 1 DAY STARTS '2017-09-13 00:00:00' ENABLE DO update table_name set column_name = 0;
-- 修改事件調度器
ALTER EVENT event_name?ON SCHEDULE EVERY 1 DAY;
事件調度器的時間格式這里就不介紹了~~
4. 存儲過程
對!細心的你可能發現了,3沒有介紹存儲過程。對!我放到這里啦~
這里要講,在Mysql中創建存儲過程,以及如何在Mybatis中調用存儲過程。
(1)Mysql創建存儲過程
drop procedure if exists procedure_name; -- 刪除存儲過程
delimiter // -- 修改結束符為"http://"
-- 創建存儲過程
CREATE PROCEDURE procedure_name(OUT result INT) -- OUT 指定返回參數
BEGIN
update table_name set column_name = column_name+1;
SELECT column_name from table_name;
END;//
delimiter ; --把結束符改回";"
call procedure_name(@a); -- 調用存儲過程,測一下
(2)在Mybatis中調用存儲過程
dao.xml中的定義
<selectid="getId" parameterType="java.util.Map" statementType="CALLABLE" resultType="java.lang.Integer">
{call procedure_name(#{res, jdbcType=INTEGER, mode=OUT})}
</select>
dao.java中方法聲明
Integer getId(@Param("res")Integer res);
service.java中調用
getId(null); // 因為傳入的是返回參數,所以傳null
本周總結了打印日志的規范,解決一個Mysql 1205問題,回顧Mysql索引、事件、存儲過程的使用。小白在持續進步中...
希望本文對你也有一丟丟的幫助^^