Skip to content

Commit

Permalink
[docs update]完善 MySQL时间类型数据存储建议
Browse files Browse the repository at this point in the history
  • Loading branch information
Snailclimb committed Jul 22, 2023
1 parent 1cca70a commit bfc4e45
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 42 deletions.
30 changes: 18 additions & 12 deletions docs/books/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,31 @@ icon: "java"

![《Java 编程思想》-豆瓣](https://oss.javaguide.cn/github/javaguide/books/image-20220424103124893.png)

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

我第一次看的时候还觉得有点枯燥,那时候还在上大二,看了 1/3 就没看下去了。
![](https://oss.javaguide.cn/github/javaguide/books/on-java/6171657600353_.pic_hd.jpg)

毕竟,这是市面上目前唯一一本介绍了 Java 的 3 个长期支持版(Java 8、11、17)的技术书籍。

**[《Java 8 实战》](https://book.douban.com/subject/26772632/)**

![《Java 8实战》-豆瓣](https://oss.javaguide.cn/github/javaguide/books/image-20220424103202625.png)

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编程的逻辑》](https://oss.javaguide.cn/github/javaguide/books/image-20230721153650488.png)

一本非常低调的好书,相比于入门书来说,内容更有深度。适合初学者,同时也适合大家拿来复习 Java 基础知识。

## Java 并发

**[《Java 并发编程之美》](https://book.douban.com/subject/30351286/)**

![《Java 并发编程之美》-豆瓣](https://oss.javaguide.cn/github/javaguide/books/image-20220424112413660.png)

_这本书还是非常适合我们用来学习 Java 多线程的。这本书的讲解非常通俗易懂,作者从并发编程基础到实战都是信手拈来。_
这本书还是非常适合我们用来学习 Java 多线程的,讲解非常通俗易懂,作者从并发编程基础到实战都是信手拈来。

另外,这本书的作者加多自身也会经常在网上发布各种技术文章。这本书也是加多大佬这么多年在多线程领域的沉淀所得的结果吧!他书中的内容基本都是结合代码讲解,非常有说服力!

Expand All @@ -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/)**

![《Java 并发实现原理:JDK 源码剖析》-豆瓣](https://oss.javaguide.cn/github/javaguide/books/0b1b046af81f4c94a03e292e66dd6f7d.png)

这本书是 2020 年新出的,所以,现在知道的人还不是很多。

这本书主要是对 Java Concurrent 包中一些比较重要的源码进行了讲解,另外,像 JMM、happen-before、CAS 等等比较重要的并发知识这本书也都会一并介绍到。

不论是你想要深入研究 Java 并发,还是说要准备面试,你都可以看看这本书。
Expand Down Expand Up @@ -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)这篇文章。

## 常用框架

Expand Down Expand Up @@ -191,7 +197,7 @@ SpringBoot 解析,不适合初学者。我是去年入手的,现在就看了

![](https://oss.javaguide.cn/github/javaguide/open-source-project/image-20220503085034268.png)

2022 年 3 月刚刚出版的一本书。这本书分为上下两篇,上篇通过一个即时聊天系统的实战案例带你入门 Netty,下篇通过 Netty 源码分析带你搞清 Netty 比较重要的底层原理。
2022 年 3 月出版的一本书。这本书分为上下两篇,上篇通过一个即时聊天系统的实战案例带你入门 Netty,下篇通过 Netty 源码分析带你搞清 Netty 比较重要的底层原理。

## 性能调优

Expand Down
2 changes: 1 addition & 1 deletion docs/database/mysql/mysql-questions-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 基础架构

Expand Down
59 changes: 34 additions & 25 deletions docs/database/mysql/some-thoughts-on-database-storage-time.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间,说简单点就是在不同时区,查询到同一个条记录此字段的值会不一样。

Expand Down Expand Up @@ -98,28 +96,32 @@ SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
```

### DateTime 类型耗费空间更大
### 占用空间

下图是 MySQL 日期类型所占的存储空间(官方文档传送门:<https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html>):

Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间。但是,这样同样造成了一个问题,Timestamp 表示的时间范围更小。
![](https://oss.javaguide.cn/github/javaguide/FhRGUVHFK0ujRPNA75f6CuOXQHTE.jpeg)

- 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
在 MySQL 5.6.4 之前,DateTime 和 Timestamp 的存储空间是固定的,分别为 8 字节和 4 字节。但是从 MySQL 5.6.4 开始,它们的存储空间会根据毫秒精度的不同而变化,DateTime 的范围是 5~8 字节,Timestamp 的范围是 4~7 字节。

> Timestamp 在不同版本的 MySQL 中有细微差别。
### 表示范围

## 再看 MySQL 日期类型存储空间
Timestamp 表示的时间范围更小,只能到 2038 年:

下图是 MySQL 5.6 版本中日期类型所占的存储空间:
- 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

![](https://oss.javaguide.cn/github/javaguide/FhRGUVHFK0ujRPNA75f6CuOXQHTE.jpeg)
### 性能

可以看出 5.6.4 之后的 MySQL 多出了一个需要 0 ~ 3 字节的小数位。DateTime 和 Timestamp 会有几种不同的存储空间占用
由于 TIMESTAMP 需要根据时区进行转换,所以从毫秒数转换到 TIMESTAMP 时,不仅要调用一个简单的函数,还要调用操作系统底层的系统函数。这个系统函数为了保证操作系统时区的一致性,需要进行加锁操作,这就降低了效率

为了方便,本文我们还是默认 Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间
DATETIME 不涉及时区转换,所以不会有这个问题

## 数值型时间戳是更好的选择吗?
为了避免 TIMESTAMP 的时区转换问题,建议使用指定的时区,而不是依赖于操作系统时区。

很多时候,我们也会使用 int 或者 bigint 类型的数值也就是时间戳来表示时间。
## 数值时间戳是更好的选择吗?

很多时候,我们也会使用 int 或者 bigint 类型的数值也就是数值时间戳来表示时间。

这种存储方式的具有 Timestamp 类型的所具有一些优点,并且使用它的进行日期排序以及对比等操作的效率会更高,跨系统也很方便,毕竟只是存放的数值。缺点也很明显,就是数据的可读性太差了,你无法直观的看到具体时间。

Expand Down Expand Up @@ -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之后的时间 ||

![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/总结-常用日期存储方式.jpg)
8 changes: 4 additions & 4 deletions docs/java/jvm/class-file-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -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];//属性表集合
Expand Down Expand Up @@ -156,7 +156,7 @@ Java 类的继承关系由类索引、父类索引和接口索引集合三项确
### 字段表集合(Fields)

```java
u2 fields_count;//Class 文件的字段的个数
u2 fields_count;//字段数量
field_info fields[fields_count];//一个类会可以有个字段
```

Expand All @@ -181,7 +181,7 @@ Java 类的继承关系由类索引、父类索引和接口索引集合三项确
### 方法表集合(Methods)

```java
u2 methods_count;//Class 文件的方法的数量
u2 methods_count;//方法数量
method_info methods[methods_count];//一个类可以有个多个方法
```

Expand Down

0 comments on commit bfc4e45

Please sign in to comment.