遇到的問題:系統時間與數據庫時間不一致,系統時間是8:20,存到數據庫裏是0:20。mysql
第一直覺是時區不一樣致使的。sql
先看一段代碼:數據庫
輸出結果:併發
2011-11-25 10:33:21oracle
1322188401796高併發
2011-11-25 07:33:21sqlserver
1322188401796性能
這說明,時間的顯示是由時區決定的,時間所表示的距標準時間毫秒數是絕對的,不會隨時區不一樣而改變。理解這一點很重要。測試
那麼數據庫裏的時間也應該有個時區概念,那究竟是如何處理的呢?一直這麼認爲的,時間在數據庫裏實際存的是毫秒數。那咱們在客戶端看到的時間必定是通過數據庫格式化之後的。spa
但結果不徹底是這樣的,下面咱們要討論數據庫中的兩個時間類型 datetime 和 timestamp 。
網上有文稱
datetime - 存儲日期和時間部分,精確到秒,沒有時區信息
timestamp - 時間戳,存儲日期、時間和時區信息,秒值精確到小數點後6位
注意這裏的時間戳,在sqlserver中根本就不是時間,他只記錄相對時間的前後,不記錄具體時間。我認爲應該叫作數據版本號。
首先在sqlserver中測試:
select getdate()
執行結果跟想像的同樣,操做系統的時區如何修改,他都能隨之變化,他確定得到了系統的時區信息,而後對當前毫秒數格式化。
把系統時區恢復到GMT+8:00,建立一個測試表,並插入兩條數據
create table TEST_TIMEZONE(
tid int,
time1 datetime ,
time2 datetime
);
insert into TEST_TIMEZONE values(1,getdate(),getdate());
insert into TEST_TIMEZONE values(2,getdate(),getdate());
select * from TEST_TIMEZONE;
這時數據庫查詢結果爲
1 2011-11-25 10:47:23.750 2011-11-25 10:47:23.750
2 2011-11-25 10:47:27.513 2011-11-25 10:47:27.513
如今修改系統時區爲GMT+5:00,再插入兩條數據,並修改第一條數據
insert into TEST_TIMEZONE values(3,getdate(),getdate());
insert into TEST_TIMEZONE values(4,getdate(),getdate());
update TEST_TIMEZONE set time1=getdate() where tid=1;
select * from TEST_TIMEZONE;
這時數據庫查詢結果爲
1 2011-11-25 07:50:20.373 2011-11-25 10:47:23.750
2 2011-11-25 10:47:27.513 2011-11-25 10:47:27.513
3 2011-11-25 07:50:15.920 2011-11-25 07:50:15.920
4 2011-11-25 07:50:18.500 2011-11-25 07:50:18.500
由於datetime沒有時區信息,只有年月日時分秒,因此保存的是幾點就是幾點,兩次操做差了3個小時。
select t.*,t.time2-t.time1 from TEST_TIMEZONE t where t.tid=1
咱們再看時間戳類型,sqlserver一個表只能有一個時間戳列,並且時間戳列不用操做,在數據行插入或更新時自動更新。
新建測試表
create table TEST_TIMEZONE2(
tid int,
time1 timestamp
);
insert into TEST_TIMEZONE2(tid) values(1);
insert into TEST_TIMEZONE2(tid) values(2);
insert into TEST_TIMEZONE2(tid) values(3);
select * from TEST_TIMEZONE2;
查詢結果:
1 0x000000000000200A
2 0x000000000000200B
3 0x000000000000200C
update TEST_TIMEZONE2 set tid=4 where tid=3;
select * from TEST_TIMEZONE2;
查詢結果:
1 0x000000000000200A
2 0x000000000000200B
4 0x000000000000200E
這個時間戳主要用在處理併發問題上,作爲數據是否已被修改的憑證,能夠提升併發性能。 再次明確sqlserver的時間戳不是具體時間。
恢復一下時區到GMT+8:00,都不知道如今幾點了。
接下來,在mysql作個測試:
select now()
修改系統時區對查詢結果沒有影響,這與sqlserver不一樣。修改時區後,重啓mysql,再執行有效果了。說明mysql在啓動時記錄了系統時區,而不是實時的讀取系統時區。
恢復時區到GMT+8:00,新建 表
create table TEST_TIMEZONE(
tid int,
time1 datetime ,
time2 timestamp ,
time3 timestamp
);
插入數據
insert into TEST_TIMEZONE(tid) values(1);
insert into TEST_TIMEZONE(tid) values(2);
insert into TEST_TIMEZONE values(3,now(),now(),now());
insert into TEST_TIMEZONE values(4,now(),now(),now());
select * from TEST_TIMEZONE
查詢結果
Mysql容許多個timestamp列,但只有第一列會自動更新,默認值 爲
CURRENT_TIMESTAMP。
恢復時區到GMT+5:00,重啓動mysql,執行查詢
結果說明datetime的時間不隨系統時區而變化,timestamp會隨系統時區變化而變化,也sqlserver徹底不一樣。Mysql在timestamp字段記錄的是毫秒數,而且按初始的系統時區格式化後顯示。
另外對oracle如今沒有測試環境。
結論:
Datatime類型只保存年月日時分秒信息,不含時區。
Timestamp時間戳,不一樣數據庫有不一樣的實現,不要用作業務列,更不能做爲索引或鍵使用,他會自動被更新。