mysql数据库时间突然是12小时制_为什么存入mysql数据库中的timestamp,晚了13或14个小时...
#?為什么存入mysql數(shù)據(jù)庫中的timestamp,晚了13個小時
##?查看數(shù)據(jù)庫時區(qū)
```
show?variables?like?'%time_zone%';
select?@@global.system_time_zone;
select?@@global.time_zone;
可以得到默認(rèn)數(shù)據(jù)庫時區(qū):
system_time_zone?|?CST?|
time_zone?|?SYSTEM|
```
##?CST時區(qū):4個含義
>CST可以為如下4個不同的時區(qū)的縮寫:
>1,美國中部時間:Central?Standard?Time?(USA)?UT-6:00?,又美國從“3月11日”至“11月7日”實(shí)行夏令時,美國中部時間改為?UT-05:00
>2,澳大利亞中部時間:Central?Standard?Time?(Australia)?UT+9:30
>3,中國標(biāo)準(zhǔn)時間:China?Standard?Time?UT+8:00
>4,古巴標(biāo)準(zhǔn)時間:Cuba?Standard?Time?UT-4:00
>PS:即中國標(biāo)準(zhǔn)時間UT+8,和美國UT-5,中間相差13個小時
##?查看java程序運(yùn)行的本地時區(qū)
```
TimeZone.getDefault();//得到"Asia/Shanghai"
```
##?debug與源碼分析:
>1,測試發(fā)現(xiàn),客戶端到j(luò)ava程序端的時間戳是正確的,即通過mybatis寫入數(shù)據(jù)庫之前時間戳是正確的
>2,**從mybatis一路跟蹤:mybatis?SqlTimestampTypeHandler.setNonNullParameter()->mybatis?PreparedStatement.setTimestamp-》mysql-connector preparedStatement.setTimestamp()-》preparedStatement.setTimestampInternal()-》TimeUtil.changTimestamp(),通過計算本地時區(qū)和數(shù)據(jù)庫時區(qū)差值,得到數(shù)據(jù)的時間戳,再轉(zhuǎn)成SimpleDateFormat.format?yyyy-MM-dd?HH:mm:ss格式的時間戳日期字符串,寫入數(shù)據(jù)庫**
>3,問題:java運(yùn)行的本地時區(qū)是"Asia/Shanghai",那mysql-connector得到的數(shù)據(jù)庫時區(qū)是什么樣的?連接數(shù)據(jù)庫的時候,mysql-connector會獲取數(shù)據(jù)庫的時區(qū)信息,如上數(shù)據(jù)庫時區(qū)查詢,得到SYSTEM,CST
##?mysql-connector獲取數(shù)據(jù)庫時區(qū)
>1,CST?的時區(qū)是一個很混亂的時區(qū),在與?MySQL?協(xié)商會話時區(qū)時,Java?會誤以為是?CST?-0500,而非?CST?+0800
```
private?void?configureTimezone()?throws?SQLException?{
String?configuredTimeZoneOnServer?=?(String)?this.serverVariables
.get("timezone");
if?(configuredTimeZoneOnServer?==?null)?{
configuredTimeZoneOnServer?=?(String)?this.serverVariables
.get("time_zone");
if?("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer))?{
configuredTimeZoneOnServer?=?(String)?this.serverVariables
.get("system_time_zone");//得到CST,mysql-connector以為的CST是美國的CST-5:00
}
}
...
}
```
>2,TimeZone.getTimeZone(canonicalTimezone)得到CST,mysql-connector以為的CST是美國的CST-5:00,{"CST",?"America/Chicago"}
>3,mysql-connector?ZoneInfoFile?class時區(qū)簡寫和時區(qū)對應(yīng)關(guān)系
```
{{"ACT",?"Australia/Darwin"},
{"AET",?"Australia/Sydney"},
{"AGT",?"America/Argentina/Buenos_Aires"},
{"ART",?"Africa/Cairo"},
{"AST",?"America/Anchorage"},
{"BET",?"America/Sao_Paulo"},
{"BST",?"Asia/Dhaka"},
{"CAT",?"Africa/Harare"},
{"CNT",?"America/St_Johns"},
{"CST",?"America/Chicago"},
{"CTT",?"Asia/Shanghai"},
{"EAT",?"Africa/Addis_Ababa"},
{"ECT",?"Europe/Paris"},
{"IET",?"America/Indiana/Indianapolis"},
{"IST",?"Asia/Kolkata"},
{"JST",?"Asia/Tokyo"},
{"MIT",?"Pacific/Apia"},
{"NET",?"Asia/Yerevan"},
{"NST",?"Pacific/Auckland"},
{"PLT",?"Asia/Karachi"},
{"PNT",?"America/Phoenix"},
{"PRT",?"America/Puerto_Rico"},
{"PST",?"America/Los_Angeles"},
{"SST",?"Pacific/Guadalcanal"},
{"VST",?"Asia/Ho_Chi_Minh"}};
```
##?如何解決
###?一,修改數(shù)據(jù)庫時區(qū)
```
set?global?time_zone?=?'+8:00';//設(shè)置全局時區(qū)為東八區(qū)
set?time_zone?=?'+8:00';?//
flush?privileges;//刷新權(quán)限使設(shè)置立即生效
```
###?二,添加jdbc參數(shù):serverTimezone=GMT%2B8
```
db?useUnicode=true&characterEncoding=UTF-8&useAffectedRows=true&useTimezone=true&serverTimezone=GMT%2B8
```
##?會有什么問題
>1,因為老數(shù)據(jù)是基于CST-5:00,得到的時間戳日期字符串(yyyy-MM-dd?HH:mm:ss.SSS),寫入數(shù)據(jù)庫中,改了數(shù)據(jù)庫時區(qū)或修改了JDBC的時區(qū)配置,會導(dǎo)致舊數(shù)據(jù)比以前慢13個小時
##?那舊數(shù)據(jù)怎么辦
>1,創(chuàng)建一個mybatis?TimstampTypehandler專門處理timestamp類型,將某個時間以前的時間戳加上13個小時的時間戳間隔,即可
```
@MappedJdbcTypes(JdbcType.TIMESTAMP)
@MappedTypes(Timestamp.class)
public?class?TimestampHandler?extends?SqlTimestampTypeHandler?{
@Override
public?void?setNonNullParameter(PreparedStatement?ps,?int?i,?Timestamp?parameter,?JdbcType?jdbcType)
throws?SQLException?{
ps.setTimestamp(i,?parameter);
}
@Override
public?Timestamp?getNullableResult(ResultSet?rs,?String?columnName)
throws?SQLException?{
//TimeZone?tz=TimeZone.getDefault();
//TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
Timestamp?timestampTemp=rs.getTimestamp(columnName);
long?lt=timestampTemp.getTime();
long?timestampSplit=1590249600000L;//2020-05-24?00:00:00的毫秒時間戳
if(timestampSplit>lt){
Timestamp?timestamp=new?Timestamp(lt+13*60*60*1000);
return?timestamp;
}else{
return?timestampTemp;
}
}
@Override
public?Timestamp?getNullableResult(ResultSet?rs,?int?columnIndex)
throws?SQLException?{
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
Timestamp?timestampTemp=rs.getTimestamp(columnIndex);
long?lt=timestampTemp.getTime();
long?timestampSplit=1590249600000L;//2020-05-24?00:00:00的毫秒時間戳
if(timestampSplit>lt){
Timestamp?timestamp=new?Timestamp(lt+13*60*60*1000);
return?timestamp;
}else{
return?timestampTemp;
}
}
@Override
public?Timestamp?getNullableResult(CallableStatement?cs,?int?columnIndex)
throws?SQLException?{
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
Timestamp?timestampTemp=cs.getTimestamp(columnIndex);
long?lt=timestampTemp.getTime();
long?timestampSplit=1590249600000L;//2020-05-24?00:00:00的毫秒時間戳
if(timestampSplit>lt){
Timestamp?timestamp=new?Timestamp(lt+13*60*60*1000);
return?timestamp;
}else{
return?timestampTemp;
}
}
}
```
##?多人開發(fā),timestamp時間戳使用規(guī)約
>1,接口參數(shù)涉及時間,都用時間戳,精確到秒或毫秒,全項目統(tǒng)一
>2,時間戳參數(shù)直接入庫,不要在代碼層再做一次SimpleDateFormat.format?yyyy-MM-dd?HH:mm:ss.SSS轉(zhuǎn)換,這樣會附加本地時區(qū),導(dǎo)致時間戳失效,mysql?connector在入庫前對timestamp類型做了本地時區(qū)和數(shù)據(jù)庫時區(qū)差值計算的
總結(jié)
以上是生活随笔為你收集整理的mysql数据库时间突然是12小时制_为什么存入mysql数据库中的timestamp,晚了13或14个小时...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql丢失链接_MySQL远程连接丢
- 下一篇: mysql 5.5主从同步_MySQL5