打好基础——Servlet——Server

在Servlet的生命周期中,客户端的请求会被转化为一个ServletRequest对象和一个ServletResponse对象,然后这两个对象会作为参数被传入到service()方法中。

service()方法会根据HTTP请求的类型(GET,POST,PUT,DELETE等)调用相应的方法(doGet(), doPost(), doPut(), doDelete()等)。

ServletRequestServletResponse是接口,而HttpServletRequestHttpServletResponse是这两个接口的实现,它们提供了处理HTTP请求的额外方法,比如获取HTTP头,cookies,session等。

service(ServletRequest req, ServletResponse res)javax.servlet.Servlet接口的一部分,所有Servlet都必须实现这个接口。

service(HttpServletRequest req, HttpServletResponse resp)是HttpServlet类的一个方法,这个方法会根据请求的类型调用doGet(), doPost(), doPut(), doDelete()等方法。

当这两个方法同时存在时,会首先执行service(ServletRequest req, ServletResponse res)。这个方法会将ServletRequest和ServletResponse对象转型为HttpServletRequest和HttpServletResponse对象,然后调用service(HttpServletRequest req, HttpServletResponse resp)


当客户端的请求来到Servlet容器,容器会首先调用service(ServletRequest req, ServletResponse res),这个方法再调用service(HttpServletRequest req, HttpServletResponse resp)


会话跟踪。

会话跟踪(Session tracking)是网络程序设计中的一项重要技术,它是在用户多次访问网站或应用程序时保持特定用户信息的一种方式。在HTTP这种无状态协议下,服务器需要一种机制来识别同一用户多次请求的关联性,会话跟踪技术就是这样一种机制。

以下是一些常用的会话跟踪技术:

  1. Cookie技术:这是一种在客户端保存用户信息的技术,服务器在需要的时候发送一个Cookie到用户的浏览器,浏览器在下次访问同一服务器时将此Cookie发送回服务器,从而服务器可以知道此次请求与之前的请求是否来自同一用户。
  2. URL重写:这是一种在客户端不接受Cookie时的备选方案。通过将会话ID添加到URL中,可以让服务器识别出这是同一个用户的多次请求。
  3. 隐藏域:在HTML表单中,可以添加隐藏字段来存储用户的会话信息,当用户提交表单时,服务器可以从隐藏域中获取会话信息。
  4. HttpSession:这是Java Servlet API中的一个接口,它提供了一种在服务器端保存用户信息的方式,服务器可以为每个用户创建一个HttpSession对象,当用户的请求到达服务器时,服务器可以通过用户的请求获取用户的HttpSession对象。
  5. IP跟踪:基于用户的IP地址来跟踪用户的会话,但是由于很多用户使用动态IP或者在同一个局域网中,这种方式并不可靠。
  6. Web存储:HTML5引入了两种新的Web存储技术,即本地存储(localStorage)和会话存储(sessionStorage)。这两种存储方式允许你在用户的浏览器中保存更大量的数据,而且有着比Cookie更好的安全性和性能。
  7. JWT (JSON Web Token):这是一种在网络上传输信息的方式,可以将用户的会话信息打包成一个token,然后将这个token传给用户。当用户下次访问服务器时,只需要带上这个token,服务器就可以知道用户的会话信息。

以上就是一些常见的会话跟踪技术,具体使用哪种技术取决于应用的需求和环境。


重点说下其中的四个技术:Cookie技术、HttpSesion、Web存储、JWT(JSON Web Token)

Cookie技术

Cookie是由W3C组织提出,最早由netscape社区发展的一种机制。

网页交互是通过HTTP协议传输数据的,而Http协议是无状态的协议。无状态的协议是什么意思呢?一旦数据提交完后,浏览器和服务器的连接就会关闭,再次交互的时候需要重新建立新的连接

服务器无法确认用户的信息,于是乎,W3C就提出了:给每一个用户都发一个通行证,无论谁访问的时候都需要携带通行证,这样服务器就可以从通行证上确认用户的信息。通行证就是Cookie。

Cookie的流程:浏览器访问服务器,如果服务器需要记录该用户的状态,就使用response向浏览器发送一个Cookie,浏览器会把Cookie保存起来。当浏览器再次访问服务器的时候,浏览器会把请求的网址连同Cookie一同交给服务器

Cookie具有不可跨域名性。浏览器判断一个网站是否能操作另一个网站的Cookie的依据是域名。所以一般来说,当我访问baidu的时候,浏览器只会把baidu颁发的Cookie带过去,而不会带上google的Cookie。

Cookie存储的方式类似于Map集合Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie

Cookie的隐私安全机制决定Cookie是不可跨域名的。也就是说www.baidu.com和www.google.com之间的Cookie是互不交接的。即使是同一级域名,不同二级域名也不能交接,也就是说:www.goole.com和www.image.goole.com的Cookie也不能访问


HttpSesion

Session比Cookie使用方便,Session可以解决Cookie解决不了的事情【Session可以存储对象,Cookie只能存储字符串。】。

Session有着request和ServletContext类似的方法。其实Session也是一个域对象。Session作为一种记录浏览器状态的机制,只要Session对象没有被销毁,Servlet之间就可以通过Session对象实现通讯

Session在用户第一次访问服务器Servlet,jsp等动态资源就会被自动创建,Session对象保存在内存里,这也就为什么可以直接使用request对象获取得到Session对象。如果访问HTML,IMAGE等静态资源Session不会被创建。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,无论是否对Session进行读写,服务器都会认为Session活跃了一次

由于会有越来越多的用户访问服务器,因此Session也会越来越多。为了防止内存溢出,服务器会把长时间没有活跃的Session从内存中删除,这个时间也就是Session的超时时间

Session的超时时间默认是30分钟。但可以修改。

服务器是如何实现一个session为一个用户浏览器服务的?换个说法:为什么服务器能够为不同的用户浏览器提供不同session?

HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session依据Cookie来识别是否是同一个用户。

简单来说:Session 之所以可以识别不同的用户,依靠的就是Cookie

该Cookie是服务器自动颁发给浏览器的,不用我们手工创建的。该Cookie的maxAge值默认是-1,也就是说仅当前浏览器使用,不将该Cookie存在硬盘中

上面说了Session是依靠Cookie来识别用户浏览器的。如果我的用户浏览器禁用了Cookie了呢?绝大多数的手机浏览器都不支持Cookie,那我的Session怎么办?Java Web提供了解决方法:URL地址重写

如何去理解面向对象的逻辑。

人是怎么认识事物的

Yourdon 在《面向对象的分析》一书中提到,人类认识事物是遵循分类学的原理,分类学主要包含三点:区分对象及其属性;区分整体对象及其组成部分;不同对象类的形成及区分。

分类与分层的两种思维

我们面对的现实世界是非常复杂的,应对复杂事物的有一个重要的方法即是抽象,抽象在实际应用过程中,又体现在两种方法上:分层和分类

分类即是将有差异的事物归类到不同的分组中,正如我们常听到的”物以类聚、人以群分”的道理一样,产生分类的原因有两点:一点是事物间的关联紧密程度,不需要将所有的事物都耦合在一起;另一点是人掌握事物是有局限的,只能掌握少量的要点,比如 5~7 个要点,超过了容易忘记。

想象有一个仓库,用来存放世间万物。各种东西被分类放到货物架上,架子有三层的架子,有五层的架子。同类物品被分到同一个架子上。

分层是通过不同的视角看事物,每一层的关注点是不一样的,这种关注点不同是由自己的视角造成的,比如我们理解计算机,并不需要深入到二进制电信号去理解计算机。层次特性在软件设计中我们经常遇到,比如计算机体系结构、TCP 七层协议等,层次特性有一个特点:越往上越具体、越往下越抽象,越往上的内容越不稳定,也即是容易变化。

分层用来将关注点分离。越在架子底层的东西越抽象,也越稳定。越在架子顶层的东西越具体,但也越不稳定。

问题域到解空间的映射

我们把需要解决的问题称之为问题域,或者问题空间,把解决方案称之为解空间。正向上一小节中提到的事物有层次特性,不同的人理解的事物是站在各自理解的视角,这样大家的理解、沟通并不一致的。如果我们看到的问题空间是表层的,那么基于浅层次理解设计出来的方案就会不稳定,可能下次有一个小变化导致方案需要重新设计。

我们可以把一个软件划分成三层:场景、功能和实体,场景层是经常会变的,比如发放优惠券场景就非常多,比如有天降红包领取优惠、分享有礼领取优惠券、新人注册领取优惠券等,这种场景的更迭随着业务的调整变化得非常快,因此场景层是不稳定的。功能支撑某一些的场景集合,对比场景,功能相对而言稳定些,就像前面提到的发放优惠券场景,本质就是给用户发放优惠券,只需要提供发放优惠券的功能即可,至于哪些场景来调用它并不关注,但功能还是基于场景的集合抽象出来的,如果场景场景类型变化了,功能也就随之变化,比如担保交易和预售交易就不一样。实体是稳定的,以担保交易和预售交易为例,它的订单模型大致是一样的,只是新增加了一些信息而已。

因此,我们希望从问题空间到解空间,大家看到的、理解的是一致的,而且看到的是问题的本质而非表象,往往场景、功能是不稳定的,而面向过程又是以功能驱动的,所以在易变化的场景下,它面临的问题就比较多。比较稳定的是问题空间中的实体对象,所以面向对象分析是现实的需要。面向过程和面向对象是两个不同的视角的分析方法:面向过程是一种归纳的分析方法,由外到内的过程;面向对象是一种演绎的分析方法,由内到外的过程。

三个一致性

软件开发会经历需要分析、概要设计、详细设计、编码、测试、上线主要阶段,我们不希望每块是割裂的,比如分析做完之后,做设计阶段又要重新去做分析的工作,那么这里面就涉及到一致性的问题,即需求到分析的一致性、分析到设计的一致性、设计到编码的一致性。这样做的好处可以保证无信息失真,因此我们急需求一种分析设计方法能做到这一点,面向对象分析与设计就能做到,因此全流程是以对象作为分析与设计的目标,在最终编码中也都是对象。

打好基础——Servlet——发展和重要性。

Servlet 是Java编程语言的一部分,主要用于创建基于Web的应用程序。Servlet API 为服务器端的Java程序开发提供了一种平台无关的方式,这是在1990年代中期的互联网创新浪潮中产生的需求。

因此,Servlet 是由 Sun Microsystems(如今的Oracle Corporation)开发并在Java 2 Platform, Enterprise Edition(J2EE)中发布的,使得开发者能够开发动态Web内容。

Servlet 的首次发布(1.0版)发生在1997年,随后其核心API经历了一系列的升级和改进,包括添加对不同的HTTP方法的支持,改进会话管理,和提高安全性等等。

  1. Servlet 2.0(1999年):在这个版本中,Servlet API添加了对HTTP 1.1的支持,提供了更好的会话管理,并增加了对分布式环境的支持。
  2. Servlet 2.1(2000年):主要增加了对Internationalization和JavaServer Pages(JSP)的支持。
  3. Servlet 2.2(2000年):添加了对Web应用程序归档(WAR)文件的支持,进一步改善了会话管理。
  4. Servlet 2.3(2001年):增强了对J2EE集成的支持,包括对事件监听器的支持。
  5. Servlet 2.4(2003年):为了提高Servlet的灵活性和兼容性,改进了生命周期和错误处理,添加了对JSP 2.0和Java 1.4的支持。
  6. Servlet 2.5(2005年):主要增加了对Java 1.5的支持,并改进了部署描述符。
  7. Servlet 3.0(2009年):添加了对注解的支持,异步处理,和安全性改进等等。
  8. Servlet 3.1(2013年):增加了对非阻塞I/O的支持,提高了安全性和可扩展性。
  9. Servlet 4.0(2017年):在这个版本中,Servlet API添加了对HTTP/2的支持,进一步改进了安全性。

Servlet在Web开发中的重要性在于它提供了一种在服务器端执行Java代码的机制,这允许开发者动态地生成Web页面,处理表单数据,和管理会话等等。尽管如今有一些新的框架和技术,如Spring Boot和Node.js,已经取代了Servlet在某些领域的地位,但Servlet仍然在许多传统和企业级的Java Web应用中发挥着关键作用。


在 Spring Boot 的 Web 应用程序中,确实使用了 Servlet 技术。实际上,Spring MVC,这是 Spring 框架的一个核心组件,基于 Servlet API。


需要学Servlet,不要跳过Servlet去学框架

首先需要知道Tomcat。因为Tomcat是一个Web服务器(同时也是Servlet容器)。通过它我们可以很方便地接收和返回到请求(如果不用Tomcat,那我们需要自己写Socket来接收和返回请求)。Jetty和Tomcat是一个类型的东西,也是Servlet容器。

把Tomcat比喻成服务员(比如麦当劳服务员),吧Servlet比喻成服务(提供汉堡、提供薯条、提供可乐)。服务员接收请求(我要一个汉堡)和返回响应(服务员给出一个汉堡)。Web服务器(Servlet容器)就是这样一个服务员的角色。

Tomact的核心技术是Socket,而Servlet是可以使用Tomact作为容器。

为什么SQL中的分组GROUP BY需要使用SUN()或MAX()等聚合函数?

+------+---------+-------+
| id   | revenue | month |
+------+---------+-------+
| 1    | 8000    | Jan   |
| 2    | 9000    | Jan   |
| 3    | 10000   | Feb   |
| 1    | 7000    | Feb   |
| 1    | 6000    | Mar   |
+------+---------+-------+

上面这个表格,如果使用GROUP BY id会被分为三组。

+------+---------+-------+
| id   | revenue | month |
+------+---------+-------+
| 1    | 8000    | Jan   |
| 1    | 7000    | Feb   |
| 1    | 6000    | Mar   |
+------+---------+-------+

+------+---------+-------+
| id   | revenue | month |
+------+---------+-------+
| 2    | 9000    | Jan   |
+------+---------+-------+

+------+---------+-------+
| id   | revenue | month |
+------+---------+-------+
| 3    | 10000   | Feb   |
+------+---------+-------+

此时在第一组中,有三条记录,也就是说有三个revenue。那么此时select id,revenue就无法判定应该取哪一个revenue,所以这样的操作在标准SQL中是不允许的,只能通过聚合函数来处理。

唯一ID的解决办法。

生成唯一ID的方式有多种,以下是一些常用的方法:

  1. UUID (Universally Unique Identifier): UUID是由128位长的数字组成的,通常由32个字符表示,并分为五段显示。UUID的主要优点是生成快速简单,而且不依赖任何系统的数据库。缺点是UUID相对较长,存储和检索都比较耗费资源。
  2. 数据库序列: 大多数关系数据库都支持自增长字段或者序列,如MySQL的AUTO_INCREMENT,Oracle的sequence等,可以保证在数据库范围内的唯一性。
  3. 分布式ID生成器: 对于分布式系统,可以使用一些专门的分布式ID生成器,如Twitter的Snowflake算法,Instagram使用的分布式生成器等。这些生成器通常会包含时间戳、机器标识、序列号等部分,以保证全局的唯一性。
  4. Redis的INCR和INCRBY命令: Redis提供了原子性的INCR和INCRBY命令,可以将key对应的value增加指定的整数。可以利用这个特性来实现ID生成。
  5. 自定义规则生成:在一些应用场景下,我们可能会根据业务需求,采用自定义规则生成唯一ID。例如,订单编号可能会包含日期时间、用户ID、序列号等信息。

注意,选择哪种生成唯一ID的方式需要根据业务需求和系统环境来定。需要考虑ID的长度、生成的性能、是否需要有序、是否容易碰撞等因素。


UUID由于太长,占用存储空间,索引效率不高。虽然生成的UUID具有极高的唯一性,但如果你需要在全球范围内保证唯一性,例如在分布式系统中,你还需要注意UUID可能会在极低概率下发生冲突。

数据库序列较为方便,但容易泄露用户信息。

折中的方式是使用雪花算法。

在Spring框架中,有多种方法可以获取配置文件中的值。

使用@value

在Spring框架中,@Value注解用于为类的字段、方法参数或方法返回值注入值。这些值可以是字面量、环境变量、系统属性或者配置文件中的属性。

1、注入字面量

@Value("Hello World")
private String greeting;

这个例子中,@Value将直接把字面量”Hello World”注入到字段greeting中。

2、注入环境变量或系统属性

@Value("#{systemProperties['java.home']}")
private String javaHome;

这个例子中,@Value将把系统属性java.home的值注入到字段javaHome中。

3、注入配置文件中的属性

@Value("${app.database.url}")
private String databaseUrl;

这个例子中,@Value将把application.propertiesapplication.yml配置文件中的app.database.url属性的值注入到字段databaseUrl中。

4、注入使用SpEL表达式计算的值

@Value("#{T(java.lang.Math).PI}")
private double pi;

这个例子中,@Value将把SpEL表达式T(java.lang.Math).PI计算的值(即π的值)注入到字段pi中。

SpEL 是 Spring Expression Language(Spring 表达式语言)的缩写。它是一种强大的表达式语言,由 Spring 框架提供,并集成到许多 Spring 组件中。

5、注入方法参数

@Bean
public MyBean myBean(@Value("${app.bean.name}") String beanName) {
    return new MyBean(beanName);
}

这个例子中,@Value将把配置文件中的app.bean.name属性的值注入到myBean方法的参数beanName中。

注意,如果使用@Value注入配置文件中的属性,你需要确保配置文件已被Spring加载,通常,Spring Boot应用会自动加载application.propertiesapplication.yml文件。另外,你可以使用:指定一个默认值,如果配置文件中没有给定属性的值,就会使用这个默认值,例如:@Value("${app.database.url:jdbc:h2:mem:testdb}")

使用 @ConfigurationProperties

在Spring Boot中,@ConfigurationProperties注解用于从application.properties或application.yml配置文件中读取配置项,并自动赋值给带有该注解的类的实例属性。

@Configuration
@ConfigurationProperties(prefix="myapp")
public class MyAppProperties {

    private String name;
    private String description;

    // Getters and setters are required
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

在上述示例中,定义了一个类MyAppProperties,并添加了@Configuration@ConfigurationProperties(prefix="myapp")注解。这样,该类的实例将被Spring Boot自动配置,并会将配置文件中以”myapp.”为前缀的配置项的值赋给相应的属性。

假设application.properties文件中有如下配置:

myapp.name=My Application
myapp.description=A sample application

那么,Spring Boot将自动创建MyAppProperties的实例,并将”myapp.name”的值(”My Application”)赋给name属性,将”myapp.description”的值(”A sample application”)赋给description属性。

需要注意的是,使用@ConfigurationProperties的类必须有getter和setter方法,因为Spring使用这些方法来读取和设置属性的值。另外,类必须被Spring管理,可以使用@Component@Configuration等注解标记类以使其成为Spring的bean。

@ConfigurationProperties注解提供了以下优点:

  1. 类型安全:属性值会根据字段的类型进行自动转换,如果类型不匹配,Spring Boot在启动时就会报错,这有助于发现潜在的问题。
  2. 集合支持:可以方便地将配置项的值绑定到集合类型(如List、Set、Map)的字段。
  3. 配置文件中的属性值支持复杂的嵌套结构,这在使用@Value注解时是不支持的。
  4. 提供了丰富的元数据支持,例如在IDE中,可以有自动完成和文档提示等功能,有助于提高开发效率。
  5. 支持验证:可以在使用@ConfigurationProperties的类上添加JSR 303的验证注解,如@NotNull@Min@Max等,来对配置项的值进行校验。

使用 Environment 对象

Spring框架的 Environment 接口是Spring 3.1中引入的,用于封装应用程序的环境属性。它提供了访问应用程序环境的所有配置的方式,包括系统环境变量、系统属性、JNDI变量、Servlet上下文参数、配置文件参数等。

你可以将 Environment 对象注入到你的bean中,然后使用它的方法(如 getProperty())来获取这些属性的值。下面是一个示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @Autowired
    private Environment env;

    public void doSomething() {
        String javaHome = env.getProperty("java.home");
        String appDatabaseUrl = env.getProperty("app.database.url");
        
        // use the properties...
    }
}

在这个例子中,Environment 对象被注入到 MyBean 类中,然后在 doSomething() 方法中使用 getProperty() 方法获取了两个属性的值:系统属性 “java.home” 和配置文件中的 “app.database.url”。

注意 getProperty() 方法返回的是一个 String 类型的值,如果你知道属性值的类型,你可以使用 Environment 的其他方法来获取特定类型的值,如 getProperty(key, Integer.class)

另外,你可以使用 containsProperty() 方法来检查一个属性是否存在,使用 getRequiredProperty() 方法来获取一个必需的属性(如果属性不存在,这个方法会抛出一个异常)。

请注意,Environment 对象在获取配置文件参数时,并不支持 @ConfigurationProperties 提供的类型安全配置绑定、复杂类型和列表的注入等高级特性。

打好基础——数据库——SQL的一些细节

<>和!=

在SQL中,<>!= 都表示不等于,并且它们的功能在大多数情况下是相同的。然而,它们的使用可能会因数据库系统的不同而有所差异。

<> 是 SQL 标准中定义的不等于运算符,所以它在所有遵循 SQL 标准的数据库系统中都应该被接受。

另一方面,尽管 != 在许多数据库系统中(如 MySQL,SQL Server,SQLite 等)都被接受,但它并不是 SQL 标准的一部分。在一些数据库系统中,如 Oracle,!= 并不被接受,只接受 <> 作为不等于运算符。

因此,通常建议使用 <>,因为它有更广泛的兼容性。但如果你知道你的代码只会在接受 != 的数据库系统上运行,那么使用 != 也是可以的。


is null和= null

在SQL中,IS NULL= NULL具有根本性的不同,这主要源于如何处理NULL值的方式。

  • IS NULL:在SQL中,IS NULL用于检查字段是否为NULL。例如,SELECT * FROM table WHERE column IS NULL;会返回所有在”column”列中值为NULL的行。
  • = NULL:在SQL中,你可能期望= NULLIS NULL具有相同的行为,但实际上不是这样的。根据SQL的标准,任何与NULL进行比较的操作(包括=)都应返回未知,而不是真或假。所以,SELECT * FROM table WHERE column = NULL;实际上不会返回任何行,即使存在具有NULL值的行。

这就是为什么在SQL中,如果你想要检查一个字段是否为NULL,你应该使用IS NULL,而不是= NULL。同样地,如果你想要检查一个字段是否不为NULL,你应该使用IS NOT NULL,而不是!= NULL<> NULL

打好基础——Servlet——学习路线

Servlet是Java Web开发的基础,用于理解服务器端处理,以下是一个可能的学习路线:

  1. 基础Java知识:在开始学习Servlet之前,你需要熟悉Java基础知识,包括面向对象的概念,类,接口,异常处理,集合框架等。
  2. 理解Web应用的基本工作原理:学习如何客户端和服务器交互,理解HTTP请求和响应模型,学习HTML,CSS和一些基本的JavaScript,了解Web服务器的工作方式等。
  3. 学习Servlet API:理解Servlet接口和其生命周期,如何配置和部署Servlet(包括使用web.xml和注解),如何处理HTTP请求(GET,POST等)。
  4. HTTP Session和Cookies管理:理解什么是HTTP无状态协议,如何使用session和cookie在HTTP请求之间保持状态。
  5. Servlet过滤器和监听器:学习如何使用Servlet过滤器来拦截请求,并处理响应,如何使用监听器监听和响应事件。
  6. 理解JavaServer Pages (JSP):虽然现在许多开发已经转向了诸如Spring MVC这样的框架,但理解JSP和它如何与Servlet交互仍然是非常有价值的。
  7. 学习数据库交互:学习如何从Servlet中连接和查询数据库,如何使用JDBC,理解数据库连接池。
  8. 理解线程安全性:由于Servlet是多线程的,因此需要理解在Servlet中如何正确地处理线程安全性。
  9. 深入学习其他相关技术:当你掌握了Servlet的基础知识后,你可能还想了解更多的相关技术,如Spring,Spring MVC,Hibernate等。

每个步骤都需要大量的实践,所以尝试在每个主题中做一些小项目。学习Servlet需要一段时间,但随着你的技能的提高,你将能够更好地理解Java Web开发,并可以进一步学习更复杂的框架和工具。

打好基础——数据库——常用函数

日期函数

month(date):筛选月份

year(date):筛选年份

datediff(a.date, b.date) = 1 。

  • 计算两个日期之间的差值,以天数为单位。
  • 这个条件要求a.dateb.date之间的差值为1天。换句话说,a.dateb.date晚了1天。

timestampdiff(day, a.date, b.date) = -1

  • 计算两个时间戳之间的差值,可以指定不同的时间单位。
  • 这个条件要求a.dateb.date之间的差值为-1天。换句话说,a.dateb.date早了1天。

文本函数

substring_index(FIELD, sep, n)可以将字段FIELD按照sep分隔:

(1).当n大于0时取第n个分隔符(n从1开始)之后的全部内容;

(2).当n小于0时取倒数第n个分隔符(n从-1开始)之前的全部内容;

例如:180cm,75kg,27,male,可以先用substring_index(profile, ‘,’, 3)取出”180cm,75kg,27″,然后用substring_index(profile, ‘,’, -1)取出27。

当然也可以用substring_index(substring_index(profile, “,”, -2), “,”, 1)取出27。

窗口函数