tomcat与nginx反向代理

一、在linux上部署运行多个tomcat

1、以前的我们

虽然说是在linux上,但是windows上也是同样的道理,只不过我们服务器都是选用linux罢了。

原先,自己有多个项目需要部署在linux上时,我的做法(新手的做法)是:在linux上只有一个tomcat服务器,我们把多个项目如project-1.warproject-2.warproject-3.war(一般都是.war包的形式)都传输到这个tomcat的webapps/目录下;在启动tomcat后,tomcat自动解压war包成文件夹,然后我们通过地址+项目名的方法来访问项目。

比如:192.168.1.1:8080/project-1/index.jsp192.168.1.1:8080/project-2/index.jsp等形式。

缺点: 作为新手来说,这只是一个过渡的时期。我们发现,如果我们有时候想要重启服务器或关闭服务器(修改配置、项目之类的),所有的项目就都暂时无法访问了。而且tomcat每次启动都要重新加载所有的项目。简而言之,十分地不方便。

2、学会部署运行多个tomcat

我们可以运行多个tomcat,每一个tomcat都使用不同的端口号,这样我们就能随心所欲地部署我们的web项目了。当然,这里可能有多种搭配。如:单tomcat单项目,单tomcat多项目,多tomcat单项目,多tomcat多项目等。重要的是:使用多个tomcat可以让我们借助不同端口号来独立分隔不同的项目,个人觉得比较条理清楚

2.1、多个tomcat运行单项目

下面讲解一下如何部署多个tomcat来运行同一个项目。假设我们的工作目录是/opt/,我们下载传输tomcat-xxx.zip到该目录下,解压unzip tomcat-xxx.zip后,重命名mv tomcat-1,这个就是我们的第一个tomcat服务器了。然后我们再复制一个cp -a tomcat-1 tomcat-2,这样就得到了第2个tomcat服务器。

接下来我们要配置这2个tomcat的端口,这样他们才能运行时端口号不冲突。下面的内容参考自网络,大家分享的都是差不多的。

1、打开配置文件,配置环境变量:vim /etc/profile

2、在文件的最后几行加入配置信息:

1
2
3
4
5
6
7
8
9
10
11
# tomcat-1 config
CATALINA_1_BASE=/opt/tomcat-1
CATALINA_1_HOME=/opt/tomcat-1
TOMCAT_1_HOME=/opt/tomcat-1
export CATALINA_1_BASE CATALINA_1_HOME TOMCAT_1_HOME

# tomcat-2 config
CATALINA_2_BASE=/opt/tomcat-2
CATALINA_2_HOME=/opt/tomcat-2
TOMCAT_2_HOME=/opt/tomcat-2
export CATALINA_2_BASE CATALINA_2_HOME TOMCAT_2_HOME

这里就是配置了我们自己的tomcat所在路径

然后,我们要刷新文件使其生效:source /etc/profile

3、对tomcat进行相应的配置

我们先来到第一个tomcat下cd /opt/tomcat-1/,然后编辑第一个需要配置的文件:vim /bin/catalina.sh

我们找到下面的内容:# OS specific support. $var _must_ be set to either true or false.

然后在下面增加如下代码:

1
2
export CATALINA_BASE=$CATALINA_1_BASE
export CATALINA_HOME=$CATALINA_1_HOME

接着,我们编辑第二个需要配置的文件vim /conf/server.xml:找到下面3条信息

1
2
3
4
5
6
7
8
<Server port="8005" shutdown="SHUTDOWN">                

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

我们需要修改这3个端口号的值,以防止多个tomcat之间端口冲突。比如改成下面的端口号。

1
2
3
4
5
6
7
8
9
<Server port="9005" shutdown="SHUTDOWN">                

<!-- tomcat访问端口 -->
<Connector port="9080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="9009" protocol="AJP/1.3" redirectPort="8443" />

4、这样,第1个tomcat就已经配置好了。我们这时候可以把项目project-1.war传输到/opt/tomcat-1/webapps/目录下,然后运行这个tomcat/bin/startup.sh。接着我们访问192.168.1.1:9080/project-1/index.jsp就能看到项目了。

5、小插曲:

  • 可能会出现无法执行startup.sh文件的情况,提示没有权限,我们需要赋予执行权限cd /opt/tomcat-1/bin/chmod u+x *.sh即可。
  • 记得要开放linux对应的端口号,我用的是阿里云,所以就在控制台进行开发,你也可以使用ufw软件来进行开放。

第2个tomcat服务器的配置、运行的步骤和上面是一致的,只是选用的端口号不能重复,在配置完之后,我们就有2个tomcat服务器来运行同一个web项目了。

比如说:192.168.1.1:9080/project-1/index.jsp192.168.1.1:10080/project-1/index.jsp

2.2、想的再远一点,别轻易满足

其实上面这种多tomcat单个项目的方式,我们称之为tomcat集群。当然,上面的还很粗糙,只是一个小demo。

问题1:指明不同的端口号访问(9080、10080)也太蠢了吧!

的确很蠢,所以我们要慢慢过渡学习。接下来我们学习用nginx来进行反向代理。


二、使用nginx进行反向代理

nginx的安装

在上面的教程安装完成之后,如何启动呢?我建议把nginx的目录加到环境变量中。

/etc/profile 中加入:

export NGINX_HOME=/usr/local/nginx
export PATH=$PATH:$NGINX_HOME/sbin

这样,就能直接使用nginx -t等命令了。

在安装完成后,启动nginx,访问我们的地址192.168.1.1就可以看到nginx的欢迎页面了。

曾经的一个bug: 遇到的情况是,无论如何修改配置都不能使其生效!通过nginx -t可以看到配置文件的路径:

nginx-1

那一次就是我找错了配置文件。也可以手动加载配置文件来启动:nginx -t -c /usr/local/nginx/conf/nginx.conf来先检查,然后读取配置文件启动。

nginx常用的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 检查配置文件
nginx -t

# 启动
nginx

# 停止
nginx -s stop

# 重新加载配置文件启动
nginx -s reload

# 指定配置文件启动
nginx -c /usr/local/nginx/conf/nginx.conf

# 查看nginx版本
nginx -v

# 摘自网络
nginx -s stop 快速关闭Nginx,可能不保存相关信息,并迅速终止web服务。
nginx -s quit 平稳关闭Nginx,保存相关信息,有安排的结束web服务。
nginx -s reload 因改变了Nginx相关配置,需要重新加载配置而重载。
nginx -s reopen 重新打开日志文件。
nginx -c filename 为 Nginx 指定一个配置文件,来代替缺省的。
nginx -t 不运行,而仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件。
nginx -v 显示 nginx 的版本。
nginx -V 显示 nginx 的版本,编译器版本和配置参数。

1、先练个手,为不同端口配置虚拟主机

1
2
3
4
5
6
7
8
# 找到安装的nginx
whereis nginx

# 进入安装目录
cd /usr/local/nginx/

# 编辑nginx配置文件
vim conf/nginx.conf

我们先找到下面这些信息:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root html;
index index.html index.htm;
}

上面的配置,意思是:

nginx监听服务器本地的80端口(建议把localhost改成自己的ip,更清晰),对外部访问的/进行代理,所以我们访问192.168.1.1就会看到nginx的欢迎页面。

之前我们不是觉得加上端口号9080、10080很蠢吗,现在来改造一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 虚拟主机
server {
listen 80;
server_name yeziqiduo.top;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root html;
index index.html index.htm;
}

location /tomcat-1/ {
proxy_pass http://yeziqiduo.top:9080/xmlconfig/;
}

location /tomcat-2/ {
proxy_pass http://yeziqiduo.top:10080/xmlconfig/;
}

我们把localhost改成了自己的域名(当然你也可以用ip地址),然后添加了2个location的配置,意思是nginx监听到指定的server_name匹配到的location时,进行请求代理,即:yeziqiduo.top/tomcat-1的请求被代理给了我们设置的http://yeziqiduo.top:9080/xmlconfig/。第2个location的意思是一样的。

示意图如下:

nginx-2

浏览器监听请求转发(重定向):可以明显看到先是301的永久重定向,请求被转发给了下一个url。

nginx-3

这个练手,让我们明白了可以用nginx来映射请求url和服务器上的真实url。

2、再练下手,为不同的二级域名配置虚拟主机

如果我们使用主域名+项目名的url(yeziqiduo.top/tomcat-1yeziqiduo.top/tomcat-2),看起来还是太low了啊。我觉得,用二级域名来代表不同的项目岂不是很爽吗?比如说:book.yeziqiduo.topmovie.yeziqiduo.top,就可以用来分别表示book项目和movie项目。

首先,我们要对我们的域名(yeziqiduo.top)添加2条A类型的解析记录,让book.yeziqiduo.top指向我们的ip地址。同理movie也是。

然后,我们再来编辑nginx的配置文件,(/usr/local/nginx/conf/nginx.conf.default是默认文件)我们可以添加多个server段来配置基于域名的虚拟主机。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 第一个虚拟主机
server {
listen 80;
server_name book.yeziqiduo.top;

location / {
proxy_pass http://yeziqiduo.top/book/;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

# 第二个虚拟主机
server {
listen 80;
server_name movie.yeziqiduo.top;

location / {
proxy_pass http://yeziqiduo.top/movie/;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

这样,我们就可以通过2个二级域名的地址来访问服务器上的2个不同项目了。

nginx-4

这种方式,是我们比较常用的方式,因为2级域名更加直观。毫无疑问,这种方式把第一种方式给碾压了。

3、正题来了,单项目的tomcat集群实现

当一个项目访问的人数多了之后,可能单个tomcat就支撑不住并发量了。这时候,我们希望有多台tomcat可以提供服务,理想的情况如下图:

nginx-5

在前面的2次练手后,我们可以很容易想明白。服务器端我们部署运行多个tomcat来实现单项目的集群。然后借助nginx来对请求进行代理,nginx依据某种策略把这些请求分发给不同的tomcat来处理。

为了方式调试,我们让tomcat-1和tomcat-2下的book项目有一点不同,就是主页index的显示不一样,这样才知道是哪个tomcat提供的服务。

我们来编辑配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 配置上游服务器集群
upstream book_cluster {
server yeziqiduo.top:9080;
server yeziqiduo.top:10080;
}

# 虚拟主机
server {
listen 80;
server_name book.yeziqiduo.top;

location / {
# 如果服务器出错,则代理给下一台服务器
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_pass http://book_cluster/xmlconfig/;
proxy_set_header Host book.yeziqiduo.top;
proxy_set_header X-Forwarded-For $remote_addr;
}

access_log logs/book.yeziqiudo.top_access.log;

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

要注意,upstream只能配置地址+端口,不能加上项目路径。我们将项目路径配置在proxy_pass字段,紧跟着集群地址后加上/xmlconfig/来指定这个tomcat集群的项目。

我们在浏览器多次访问,刷新,可以看到不同的tomcat提供的服务。

nginx-6

nginx-7

相信看着,应该很激动了。到这里,我们接触到了比较粗浅的负载均衡。

问题:tomcat集群下,nginx如何选择策略来代理请求?

nginx的upstream目前支持4种方式的分配
1、轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、按权重分配weight
weight和访问比率成正比,用于后端服务器性能不均的情况。 例如:

1
2
3
4
upstream bakend {
server yeziqiduo.top:9080 weight=10;
server yeziqiduo.top:10080 weight=10;
}

3、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 例如:

1
2
3
4
5
upstream bakend {
ip_hash;
server yeziqiduo.top:9080;
server yeziqiduo.top:10080;
}

4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。

1
2
3
4
5
upstream backend {
server yeziqiduo.top:9080;
server yeziqiduo.top:10080;
fair;
}

5、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。

1
2
3
4
5
6
upstream backend {
server yeziqiduo.top:9080;
server yeziqiduo.top:9080;
hash $request_uri;
hash_method crc32;
}

4、想一想,现在的问题又来了!

1.现在我们只有一个服务器,如果并发量巨大,一台服务器上的单项目tomcat集群也是撑不住的。所以我们会来到分布式架构,演变为单项目多服务器集群的形式。(横向拓展远远优于硬件的纵向拓展)

nginx-8

2.接着问题1,现在来到了分布式。那么新的问题就是:如何保持用户的session一致性?如何保证文件资源(如上传、下载)的一致性?

3.分布式带来的问题不少,现在,单项目的tomcat集群又演变成了微服务架构。将一个大型的项目拆分,各个模块都独立运行提供服务,比如说拆分出单点登录系统、OSS(对象存储服务)等,能够解决一些问题2中的一些麻烦。

三、使用nginx强制http转https

首先我们需要https的证书,免费提供https证书的网站有freesslletsencrypt、以及阿里云这3个网站。借助阿里云的单域名ssl证书,可以得到一个.key文件(私钥)和.pem文件(证书)。阿里云的ssl部分有一些配置的具体过程。在nginx的配置文件中,配置如下。对yeziqiduo.top启用了ssl即https连接,2个文件需要复制到linux中并指明路径。

nginx-9

然后我们想要强制http转成https连接,nginx配置如下:借助return重定向为https。(实现的方式还有其他几种)

nginx-10

由于阿里云提供的免费ssl证书只支持单域名,所有我们按照自己的需求申请多个证书并一一配置就可以了。

1、https的详细了解

这部分内容,网上的博客分析地比较全面和透彻,看到好的文章多看看理解了才行。

下面自己梳理一下一些关键的名词https的连接、传输过程。

首先,我们知道申请得到的ssl文件:一个是私钥(private key),另一个是证书(certificate)。我先讲一下什么是证书吧!借助Firefox可以查看网站的证书信息,重要的内容有:证书编号,过期时间,所有者信息,所有者公钥。

1.下面讲解一下证书的生成过程:

一个概念就是数字证书就好比网站的身份证,CA颁发给网站的证书就好比是一张张可信任的身份证。

nginx-11

上面就是CA机构生成证书的过程,可以看到,证书中包含的内容有3部分:证书编号的数字签名值,网站的公钥,网站的信息。

2.https的连接

https的连接,就是在tcp层和http层之间加了一层ssl层,所以需要先建立ssl连接,然后才开始http连接与通信。下面讲解一下,客户端如何与网站进行通信连接的建立。

当客户端请求网站时,网站将证书发送给客户端,客户端如何判断发送的证书内容没有修改呢?这样我才能使用该证书的公钥进行通信!

nginx-12

这个过程就是证书生成的逆过程。需要指出的是:CA的公钥哪里来的呢? 操作系统和浏览器会自己维护为数不多的CA机构列表。所以CA机构的公钥是在我们本地的。客户端使用同样的哈希方法(这个信息放在网站信息中)计算得到证书编号,同时使用CA公钥对数字签名值进行解密得到真实的证书编号,2者一对比,相等则说明该证书没有被篡改,可以信任并且使用其公钥。

1、如果证书被人修改,因为它没有CA的私钥,所以只能篡改网站公钥或网站信息这2部分的内容。客户端计算2个证书编号后就能知道信息是否被篡改。

2.如果证书被CA信任的其他网站劫持,发送过来的是被信任的网站的证书呢?客户端还会判断证书中网站信息里的域名是否和自己请求的域名一致,这样就能知道是否被中间人劫持了。

证书验证通过之后,还要做更重要的事情!

客户端生成随机数,并使用网站的公钥进行加密,发送给网站(中间人没有私钥,无法篡改);网站收到密文后使用私钥进行解密得到随机数,并回复客户端。这个过程就是在协商后面的http通信所要使用的对称加密的密文。协商完成后,双方后面就开始进行http通信了,通信的内容都要使用密文进行对称加密(中间人不知道对称加密的密文,无法篡改),这样内容的安全性就得到了保证。

2、总结一下https的过程

HTTPS要使客户端与服务器端的通信过程得到安全保证,必须使用的对称加密算法,但是协商对称加密算法的过程,需要使用非对称加密算法来保证安全,然而直接使用非对称加密的过程本身也不安全,会有中间人篡改公钥的可能性,所以客户端与服务器不直接使用公钥,而是使用数字证书签发机构颁发的证书来保证非对称加密过程本身的安全。这样通过这些机制协商出一个对称加密算法,就此双方使用该算法进行加密解密。从而解决了客户端与服务器端之间的通信安全问题。

先使用非对称加密方式通信,验证网站身份以及取得公钥。然后双方协商对称加密的密文。后面双方的http通信就使用密文进行对称加密。

下面是参考的博文。

https博文列表:

1.也许,这样理解HTTPS更容易

2.图解 HTTPS:Charles 捕获 HTTPS 的原理

3.阿里云技术专家金九:Tengine HTTPS原理解析、实践与调试

4.HTTPS 原理详解

5.HTTPS工作原理

6.HTTPS 原理详解

3、tcp的3次握手4次挥手

HTTPS工作原理和TCP握手机制

四、nginx的学习书籍

《精通nginx》、《实战nginx,取代apache的高性能服务器》

五、nginx的配置文件

nginx.conf文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#user  nobody;
# 工作进程数, 1.5*cpu核心数~2.0*cpu核心数
worker_processes 1;

# 错误日志
error_log logs/error.log;

# 记录主进程ID的文件
pid logs/nginx.pid;


events {
# 使用网络IO模型,提高性能
use epoll;
# 一个工作进程worker process能处理的最大并发连接数
worker_connections 1024;
}


http {
# 其他配置
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;

# 连接超时时长
keepalive_timeout 65;

# 开启gzip压缩
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml;

# 第一个虚拟主机
server {
listen 80;
server_name yeziqiduo.top www.yeziqiduo.top;

location / {
root html;
index index.html index.htm;
}

# 图片缓存30天
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}
# css、js缓存1小时
location ~ .*\.(js|css|)?$ {
expires 1h;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

# 配置上游服务器集群
upstream book_cluster {

# 最少连接数
least_conn;
# 默认轮询round-robin
# ip-hash

server yeziqiduo.top:9080;
server yeziqiduo.top:10080;
# 维持http连接的个数
keepalive 32;
}

# 第二个虚拟主机
server {
listen 80;
server_name book.yeziqiduo.top;

location / {
# 引入配置文件
include proxy.conf

# http1.1才能维持连接
proxy_http_version 1.1;
proxy_set_header Connection "";

# 如果服务器出错,则代理给下一台服务器
proxy_next_upstream http_502 http_504 error timeout invalid_header;
# 反向代理,设置上游服务器
proxy_pass http://book_cluster/xmlconfig;
proxy_set_header Host book.yeziqiduo.top;
proxy_set_header X-Forwarded-For $remote_addr;
}

access_log logs/book.yeziqiudo.top_access.log;

# 错误文件配置
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

# 第三个虚拟主机
server {
listen 80;
server_name movie.yeziqiduo.top;

location / {
root html;
index index.html index.htm;
}

# 错误文件配置,外部网站
error_page 500 https://yeziqiduo.top:9080/xmlconfig/500.html;
}

# 第四个虚拟主机
server {
listen 80;
server_name zstuhelper.yeziqiduo.top;
location / {
proxy_pass http://mcrd.zstu.edu.cn/ZstuHelper/;
}
}

# HTTPS server
server {
listen 443 ssl;
server_name www.yeziqiduo.top;

ssl on;
ssl_certificate /usr/local/nginx/cert/1526572949495.pem;
ssl_certificate_key /usr/local/nginx/cert/1526572949495.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

location / {
root html;
index index.html index.htm;
}
}

server {
listen 443 ssl;
server_name yeziqiduo.top;

ssl on;
ssl_certificate /usr/local/nginx/cert/215028086470218.pem;
ssl_certificate_key /usr/local/nginx/cert/215028086470218.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

location / {
root html;
index index.html index.htm;
}
}

}

proxy.conf文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 该配置文件可以重用
# 下面的配置信息是nginx代理请求时连接上游服务器的参数
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 30;
proxy_send_timeout 15;
proxy_read_timeout 15;
proxy_send_lowat 12000;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
最近的文章

Queue接口的实现类

queue作为队列,java在实现的时候,直接实现了双端队列deque。这样双端队列就囊括了队列、双端队列、堆栈这3种角色的功能。 所以我们在使用的时候使用的是Deque接口的实现类,当然Deque接口继承自Queue接口。 Deque接口的实现类我们记住,Deque接口所能代表的数据结构:队 …

Queue接口 继续阅读
更早的文章

日期(Date)与时间(Time)

在mysql中,与日期、时间相关的数据类型有:DATE、TIME、DATETIME、TIMESTAMP 这4种。 基本介绍DATE DATE就是日期,日期就是形如YYYY-MM-DD 格式的字符串,它的范围是:1000-01-01-9999-12-31 。官网上讲,允许使用strings和numb …

date与time, mysql 继续阅读