mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-06-25 02:27:10 +08:00
[docs update]完善 MySQL时间类型数据存储建议
This commit is contained in:
parent
1cca70a215
commit
bfc4e45d5d
@ -30,9 +30,11 @@ icon: "java"
|
||||
|
||||

|
||||
|
||||
这本书被很多人称之为 Java 领域的圣经(_感觉有点过了~~~_)。不太推荐编程初学者阅读,有点劝退的味道,稍微有点基础后阅读更好。
|
||||
另外,这本书的作者去年新出版了[《On Java》](https://book.douban.com/subject/35751619/),我更推荐这本,内容更新,介绍了 Java 的 3 个长期支持版(Java 8、11、17)。
|
||||
|
||||
我第一次看的时候还觉得有点枯燥,那时候还在上大二,看了 1/3 就没看下去了。
|
||||

|
||||
|
||||
毕竟,这是市面上目前唯一一本介绍了 Java 的 3 个长期支持版(Java 8、11、17)的技术书籍。
|
||||
|
||||
**[《Java 8 实战》](https://book.douban.com/subject/26772632/)**
|
||||
|
||||
@ -40,13 +42,19 @@ icon: "java"
|
||||
|
||||
Java 8 算是一个里程碑式的版本,现在一般企业还是用 Java 8 比较多。掌握 Java 8 的一些新特性比如 Lambda、Stream API 还是挺有必要的。这块的话,我推荐 **[《Java 8 实战》](https://book.douban.com/subject/26772632/)** 这本书。
|
||||
|
||||
**[《Java编程的逻辑》](https://book.douban.com/subject/30133440/)**
|
||||
|
||||

|
||||
|
||||
一本非常低调的好书,相比于入门书来说,内容更有深度。适合初学者,同时也适合大家拿来复习 Java 基础知识。
|
||||
|
||||
## Java 并发
|
||||
|
||||
**[《Java 并发编程之美》](https://book.douban.com/subject/30351286/)**
|
||||
|
||||

|
||||
|
||||
_这本书还是非常适合我们用来学习 Java 多线程的。这本书的讲解非常通俗易懂,作者从并发编程基础到实战都是信手拈来。_
|
||||
这本书还是非常适合我们用来学习 Java 多线程的,讲解非常通俗易懂,作者从并发编程基础到实战都是信手拈来。
|
||||
|
||||
另外,这本书的作者加多自身也会经常在网上发布各种技术文章。这本书也是加多大佬这么多年在多线程领域的沉淀所得的结果吧!他书中的内容基本都是结合代码讲解,非常有说服力!
|
||||
|
||||
@ -64,14 +72,12 @@ _这本书还是非常适合我们用来学习 Java 多线程的。这本书的
|
||||
|
||||
这本书的质量也是非常过硬!给作者们点个赞!这本书有统一的排版规则和语言风格、清晰的表达方式和逻辑。并且每篇文章初稿写完后,作者们就会互相审校,合并到主分支时所有成员会再次审校,最后再通篇修订了三遍。
|
||||
|
||||
在线阅读:[https://redspider.gitbook.io/concurrent/](https://redspider.gitbook.io/concurrent/) 。
|
||||
在线阅读:<https://redspider.gitbook.io/concurrent/>。
|
||||
|
||||
**[《Java 并发实现原理:JDK 源码剖析》](https://book.douban.com/subject/35013531/)**
|
||||
|
||||

|
||||
|
||||
这本书是 2020 年新出的,所以,现在知道的人还不是很多。
|
||||
|
||||
这本书主要是对 Java Concurrent 包中一些比较重要的源码进行了讲解,另外,像 JMM、happen-before、CAS 等等比较重要的并发知识这本书也都会一并介绍到。
|
||||
|
||||
不论是你想要深入研究 Java 并发,还是说要准备面试,你都可以看看这本书。
|
||||
@ -122,12 +128,12 @@ _这本书还是非常适合我们用来学习 Java 多线程的。这本书的
|
||||
|
||||
非常重要!非常重要!特别是 Git 和 Docker。
|
||||
|
||||
- **IDEA**:熟悉基本操作以及常用快捷。你可以通过 GitHub 上的开源教程 [《IntelliJ IDEA 简体中文专题教程》](https://github.com/judasn/IntelliJ-IDEA-Tutorial) 来学习 IDEA 的使用。
|
||||
- **Maven**:强烈建议学习常用框架之前可以提前花几天时间学习一下**Maven**的使用。(到处找 Jar 包,下载 Jar 包是真的麻烦费事,使用 Maven 可以为你省很多事情)。
|
||||
- **Git**:基本的 Git 技能也是必备的,试着在学习的过程中将自己的代码托管在 Github 上。你可以看看这篇 Github 上开源的 [《Git 极简入门》](https://snailclimb.gitee.io/javaguide/#/docs/tools/Git) 。
|
||||
- **Docker**:学着用 Docker 安装学习中需要用到的软件比如 MySQL ,这样方便很多,可以为你节省不少时间。你可以看看这篇 Github 上开源的 [《Docker 基本概念解读》](https://snailclimb.gitee.io/javaguide/#/docs/tools/Docker) 、[《一文搞懂 Docker 镜像的常用操作!》](https://snailclimb.gitee.io/javaguide/#/docs/tools/Docker-Image)
|
||||
- **IDEA**:熟悉基本操作以及常用快捷。相关资料: [《IntelliJ IDEA 简体中文专题教程》](https://github.com/judasn/IntelliJ-IDEA-Tutorial) 。
|
||||
- **Maven**:强烈建议学习常用框架之前可以提前花几天时间学习一下**Maven**的使用。(到处找 Jar 包,下载 Jar 包是真的麻烦费事,使用 Maven 可以为你省很多事情)。相关阅读:[Maven核心概念总结](https://javaguide.cn/tools/maven/maven-core-concepts.html)。
|
||||
- **Git**:基本的 Git 技能也是必备的,试着在学习的过程中将自己的代码托管在 Github 上。相关阅读:[Git核心概念总结](https://javaguide.cn/tools/git/git-intro.html)。
|
||||
- **Docker**:学着用 Docker 安装学习中需要用到的软件比如 MySQL ,这样方便很多,可以为你节省不少时间。相关资料:[《Docker - 从入门到实践》](https://yeasy.gitbook.io/docker_practice/) 。
|
||||
|
||||
除了这些工具之外,我强烈建议你一定要搞懂 GitHub 的使用。一些使用 GitHub 的小技巧,你可以看[《GitHub 小技巧》](https://snailclimb.gitee.io/javaguide/#/docs/tools/Github%E6%8A%80%E5%B7%A7)这篇文章。
|
||||
除了这些工具之外,我强烈建议你一定要搞懂 GitHub 的使用。一些使用 GitHub 的小技巧,你可以看[Github实用小技巧总结](https://javaguide.cn/tools/git/github-tips.html)这篇文章。
|
||||
|
||||
## 常用框架
|
||||
|
||||
@ -191,7 +197,7 @@ SpringBoot 解析,不适合初学者。我是去年入手的,现在就看了
|
||||
|
||||

|
||||
|
||||
2022 年 3 月刚刚出版的一本书。这本书分为上下两篇,上篇通过一个即时聊天系统的实战案例带你入门 Netty,下篇通过 Netty 源码分析带你搞清 Netty 比较重要的底层原理。
|
||||
2022 年 3 月出版的一本书。这本书分为上下两篇,上篇通过一个即时聊天系统的实战案例带你入门 Netty,下篇通过 Netty 源码分析带你搞清 Netty 比较重要的底层原理。
|
||||
|
||||
## 性能调优
|
||||
|
||||
|
@ -164,7 +164,7 @@ Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗
|
||||
- `NULL` 会影响聚合函数的结果。例如,`SUM`、`AVG`、`MIN`、`MAX` 等聚合函数会忽略 `NULL` 值。 `COUNT` 的处理方式取决于参数的类型。如果参数是 `*`(`COUNT(*)`),则会统计所有的记录数,包括 `NULL` 值;如果参数是某个字段名(`COUNT(列名)`),则会忽略 `NULL` 值,只统计非空值的个数。
|
||||
- 查询 `NULL` 值时,必须使用 `IS NULL` 或 `IS NOT NULLl` 来判断,而不能使用 =、!=、 <、> 之类的比较运算符。而`''`是可以使用这些比较运算符的。
|
||||
|
||||
看了上面的介绍之后,相信你对另外一个高频面试题:“为什么MySQL不建议使用NULL作为列默认值?”也有了答案。
|
||||
看了上面的介绍之后,相信你对另外一个高频面试题:“为什么MySQL不建议使用 `NULL` 作为列默认值?”也有了答案。
|
||||
|
||||
## MySQL 基础架构
|
||||
|
||||
|
@ -5,28 +5,26 @@ tag:
|
||||
- MySQL
|
||||
---
|
||||
|
||||
我们平时开发中不可避免的就是要存储时间,比如我们要记录操作表中这条记录的时间、记录转账的交易时间、记录出发时间等等。你会发现时间这个东西与我们开发的联系还是非常紧密的,用的好与不好会给我们的业务甚至功能带来很大的影响。所以,我们有必要重新出发,好好认识一下这个东西。
|
||||
|
||||
这是一篇短小精悍的文章,仔细阅读一定能学到不少东西!
|
||||
我们平时开发中不可避免的就是要存储时间,比如我们要记录操作表中这条记录的时间、记录转账的交易时间、记录出发时间、用户下单时间等等。你会发现时间这个东西与我们开发的联系还是非常紧密的,用的好与不好会给我们的业务甚至功能带来很大的影响。所以,我们有必要重新出发,好好认识一下这个东西。
|
||||
|
||||
## 不要用字符串存储日期
|
||||
|
||||
我记得我在大学的时候就这样干过,而且现在很多对数据库不太了解的新手也会这样干,可见,这种存储日期的方式的优点还是有的,就是简单直白,容易上手。
|
||||
和绝大部分对数据库不太了解的新手一样,我在大学的时候就这样干过,甚至认为这样是一个不错的表示日期的方法。毕竟简单直白,容易上手。
|
||||
|
||||
但是,这是不正确的做法,主要会有下面两个问题:
|
||||
|
||||
1. 字符串占用的空间更大!
|
||||
2. 字符串存储的日期效率比较低(逐个字符进行比对),无法用日期相关的 API 进行计算和比较。
|
||||
|
||||
## Datetime 和 Timestamp 之间抉择
|
||||
## Datetime 和 Timestamp 之间的抉择
|
||||
|
||||
Datetime 和 Timestamp 是 MySQL 提供的两种比较相似的保存时间的数据类型。他们两者究竟该如何选择呢?
|
||||
Datetime 和 Timestamp 是 MySQL 提供的两种比较相似的保存时间的数据类型,可以精确到秒。他们两者究竟该如何选择呢?
|
||||
|
||||
**通常我们都会首选 Timestamp。** 下面说一下为什么这样做!
|
||||
下面我们来简单对比一下二者。
|
||||
|
||||
### DateTime 类型没有时区信息
|
||||
### 时区信息
|
||||
|
||||
**DateTime 类型是没有时区信息的(时区无关)** ,DateTime 类型保存的时间都是当前会话所设置的时区对应的时间。这样就会有什么问题呢?当你的时区更换之后,比如你的服务器更换地址或者更换客户端连接时区设置的话,就会导致你从数据库中读出的时间错误。不要小看这个问题,很多系统就是因为这个问题闹出了很多笑话。
|
||||
**DateTime 类型是没有时区信息的(时区无关)** ,DateTime 类型保存的时间都是当前会话所设置的时区对应的时间。这样就会有什么问题呢?当你的时区更换之后,比如你的服务器更换地址或者更换客户端连接时区设置的话,就会导致你从数据库中读出的时间错误。
|
||||
|
||||
**Timestamp 和时区有关**。Timestamp 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间,说简单点就是在不同时区,查询到同一个条记录此字段的值会不一样。
|
||||
|
||||
@ -98,28 +96,32 @@ SET GLOBAL time_zone = '+8:00';
|
||||
SET GLOBAL time_zone = 'Europe/Helsinki';
|
||||
```
|
||||
|
||||
### DateTime 类型耗费空间更大
|
||||
### 占用空间
|
||||
|
||||
Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间。但是,这样同样造成了一个问题,Timestamp 表示的时间范围更小。
|
||||
|
||||
- DateTime:1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
|
||||
- Timestamp:1970-01-01 00:00:01 ~ 2037-12-31 23:59:59
|
||||
|
||||
> Timestamp 在不同版本的 MySQL 中有细微差别。
|
||||
|
||||
## 再看 MySQL 日期类型存储空间
|
||||
|
||||
下图是 MySQL 5.6 版本中日期类型所占的存储空间:
|
||||
下图是 MySQL 日期类型所占的存储空间(官方文档传送门:<https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html>):
|
||||
|
||||

|
||||
|
||||
可以看出 5.6.4 之后的 MySQL 多出了一个需要 0 ~ 3 字节的小数位。DateTime 和 Timestamp 会有几种不同的存储空间占用。
|
||||
在 MySQL 5.6.4 之前,DateTime 和 Timestamp 的存储空间是固定的,分别为 8 字节和 4 字节。但是从 MySQL 5.6.4 开始,它们的存储空间会根据毫秒精度的不同而变化,DateTime 的范围是 5~8 字节,Timestamp 的范围是 4~7 字节。
|
||||
|
||||
为了方便,本文我们还是默认 Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间。
|
||||
### 表示范围
|
||||
|
||||
## 数值型时间戳是更好的选择吗?
|
||||
Timestamp 表示的时间范围更小,只能到 2038 年:
|
||||
|
||||
很多时候,我们也会使用 int 或者 bigint 类型的数值也就是时间戳来表示时间。
|
||||
- DateTime:1000-01-01 00:00:00.000000 ~ 9999-12-31 23:59:59.499999
|
||||
- Timestamp:1970-01-01 00:00:01.000000 ~ 2038-01-19 03:14:07.499999
|
||||
|
||||
### 性能
|
||||
|
||||
由于 TIMESTAMP 需要根据时区进行转换,所以从毫秒数转换到 TIMESTAMP 时,不仅要调用一个简单的函数,还要调用操作系统底层的系统函数。这个系统函数为了保证操作系统时区的一致性,需要进行加锁操作,这就降低了效率。
|
||||
|
||||
DATETIME 不涉及时区转换,所以不会有这个问题。
|
||||
|
||||
为了避免 TIMESTAMP 的时区转换问题,建议使用指定的时区,而不是依赖于操作系统时区。
|
||||
|
||||
## 数值时间戳是更好的选择吗?
|
||||
|
||||
很多时候,我们也会使用 int 或者 bigint 类型的数值也就是数值时间戳来表示时间。
|
||||
|
||||
这种存储方式的具有 Timestamp 类型的所具有一些优点,并且使用它的进行日期排序以及对比等操作的效率会更高,跨系统也很方便,毕竟只是存放的数值。缺点也很明显,就是数据的可读性太差了,你无法直观的看到具体时间。
|
||||
|
||||
@ -149,12 +151,19 @@ mysql> select FROM_UNIXTIME(1578707612);
|
||||
|
||||
## 总结
|
||||
|
||||
MySQL 中时间到底怎么存储才好?Datetime?Timestamp? 数值保存的时间戳?
|
||||
MySQL 中时间到底怎么存储才好?Datetime?Timestamp?还是数值时间戳?
|
||||
|
||||
好像并没有一个银弹,很多程序员会觉得数值型时间戳是真的好,效率又高还各种兼容,但是很多人又觉得它表现的不够直观。这里插一嘴,《高性能 MySQL 》这本神书的作者就是推荐 Timestamp,原因是数值表示时间不够直观。下面是原文:
|
||||
并没有一个银弹,很多程序员会觉得数值型时间戳是真的好,效率又高还各种兼容,但是很多人又觉得它表现的不够直观。
|
||||
|
||||
《高性能 MySQL 》这本神书的作者就是推荐 Timestamp,原因是数值表示时间不够直观。下面是原文:
|
||||
|
||||
<img src="https://oss.javaguide.cn/github/javaguide/%E9%AB%98%E6%80%A7%E8%83%BDmysql-%E4%B8%8D%E6%8E%A8%E8%8D%90%E7%94%A8%E6%95%B0%E5%80%BC%E6%97%B6%E9%97%B4%E6%88%B3.jpg" style="zoom:50%;" />
|
||||
|
||||
每种方式都有各自的优势,根据实际场景才是王道。下面再对这三种方式做一个简单的对比,以供大家实际开发中选择正确的存放时间的数据类型:
|
||||
每种方式都有各自的优势,根据实际场景选择最合适的才是王道。下面再对这三种方式做一个简单的对比,以供大家实际开发中选择正确的存放时间的数据类型:
|
||||
|
||||
| 类型 | 存储空间 | 日期格式 | 日期范围 | 是否带时区信息 |
|
||||
| ------------ | -------- | ------------------------------ | ------------------------------------------------------------ | -------------- |
|
||||
| DATETIME | 5~8字节 | YYYY-MM-DD hh:mm:ss[.fraction] | 1000-01-01 00:00:00[.000000] ~ 9999-12-31 23:59:59[.999999] | 否 |
|
||||
| TIMESTAMP | 4~7字节 | YYYY-MM-DD hh:mm:ss[.fraction] | 1970-01-01 00:00:01[.000000] ~ 2038-01-19 03:14:07[.999999] | 是 |
|
||||
| 数值型时间戳 | 4字节 | 全数字如1578707612 | 1970-01-01 00:00:01之后的时间 | 否 |
|
||||
|
||||

|
||||
|
@ -33,9 +33,9 @@ ClassFile {
|
||||
u2 super_class;//父类
|
||||
u2 interfaces_count;//接口数量
|
||||
u2 interfaces[interfaces_count];//一个类可以实现多个接口
|
||||
u2 fields_count;//Class 文件的字段属性数量
|
||||
u2 fields_count;//字段数量
|
||||
field_info fields[fields_count];//一个类可以有多个字段
|
||||
u2 methods_count;//Class 文件的方法数量
|
||||
u2 methods_count;//方法数量
|
||||
method_info methods[methods_count];//一个类可以有个多个方法
|
||||
u2 attributes_count;//此类的属性表中的属性数
|
||||
attribute_info attributes[attributes_count];//属性表集合
|
||||
@ -156,7 +156,7 @@ Java 类的继承关系由类索引、父类索引和接口索引集合三项确
|
||||
### 字段表集合(Fields)
|
||||
|
||||
```java
|
||||
u2 fields_count;//Class 文件的字段的个数
|
||||
u2 fields_count;//字段数量
|
||||
field_info fields[fields_count];//一个类会可以有个字段
|
||||
```
|
||||
|
||||
@ -181,7 +181,7 @@ Java 类的继承关系由类索引、父类索引和接口索引集合三项确
|
||||
### 方法表集合(Methods)
|
||||
|
||||
```java
|
||||
u2 methods_count;//Class 文件的方法的数量
|
||||
u2 methods_count;//方法数量
|
||||
method_info methods[methods_count];//一个类可以有个多个方法
|
||||
```
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user