面试题:数据库日期类型字段,需要兼容不同数据库,应该如何选择?

当设计一个产品,其中很多地方要把日期类型保存到数据库中,如果产品有兼容不同数据库产品的需求,那么,应当怎样设计呢?

当然,首先想到的是,使用数据库的 Date 或 DateTime 类型,可是看看不同数据库这些类型间的区别吧,真让人望而止步。

MySQL 数据库:

它们分别是 date、datetime、time、timestamp 和 year。

  • date :“yyyy-mm-dd”格式表示的日期值
  • time :“hh:mm:ss”格式表示的时间值
  • datetime:“yyyy-mm-dd hh:mm:ss”格式
  • timestamp:“yyyymmddhhmmss”格式表示的时间戳值
  • year:“yyyy”格式的年份值。

范围:

  • date “1000-01-01” 到 “9999-12-31” 3字节
  • time “-838:59:59” 到 “838:59:59” 3字节
  • datetime “1000-01-01 00:00:00” 到 “9999-12-31 23:59:59” 8字节
  • timestamp 19700101000000 到 2037 年的某个时刻 4字节
  • year 1901 到 2155 1 字节

Oracle 数据库:

Date 类型的内部编码为12

长度:占用7个字节

数据存储的每一位到第七位分别为:世纪,年,月,日,时,分,秒

TIMESTAMP是支持小数秒和时区的日期/时间类型。对秒的精确度更高

TIMESTAMP WITH TIME ZONE 类型是 TIMESTAMP 的子类型,增加了时区支持,占用13字节的存储空间,最后两位用于保存时区信息

INTERVAL 用于表示一段时间或一个时间间隔的方法。在前面有多次提过。INTERVAL有两种类型.

  • YEAR TO MONTH 能存储年或月指定的一个时间段.
  • DATE TO SECOND 存储天,小时,分钟,秒指定的时间段.

sql server:

datetime 和 smalldatetime

  • datetime数据类型所占用的存储空间为8个字节,其中前4个字节用于存储1900年1月1日以前或以后的天数,数值分正负,正数表示在此日期之后的日期,负数表示在此日期之前的日期;后4个字节用于存储从此日零时起所指定的时间经过的毫秒数。
  • smalldatetime数据类型使用4个字节存储数据。其中前2个字节存储从基础日期1900年1月1日以来的天数,后两个字节存储此日零时起所指定的时间经过的分钟数。
  • smalldatetime数据类型与datetime数据类型相似,但其日期时间范围较小,从1900年1月1日到2079年6月6日。此数据类型精度较低,只能精确到分钟,其分钟个位为根据秒数四舍五入的值,即以30秒为界四舍五入。
    如果没有兼容多种数据库这个要求,我会毫不犹豫的使用数据库的 Date 类型。

因为如果使用 Java 框架产生代码,对数据库中定义为 Date 类型的字段,甚至能在页面上产生出JS的时间选择框,的确能节省很多开发时间。而兼容不同数据库,就希望产品在由一种数据库,迁移到另外一种数据库时,尽可能小的代价,使用了 Date,看来就很困难了。

有一个疑问,不知道目前流行的ORM对这个处理得是不是好?因为工作不怎么涉及这方面,所以不大了解。

在之前的设计开发中,因为有支持多种数据库这种需求,所以首先否定了日期时间这样的类型。

曾经使用过毫秒数(Java 的 System.currentTimeMillis())这种方式,但是选用这个方式,考虑的不是使用起来是否方便或者数据迁移,而是考虑到下面的原因:

Java 取到的毫秒数是对时间点的一种准确描述。定义如下:java.lang.System.currentTimeMillis(),它返回从 UTC 1970 年 1 月 1 日午夜开始经过的毫秒数。

我们可以看到,这个定义,保证了这个时间值能够被后续设计开发的人员正确和准确的理解,能够为所有的应用正确理解,能够在所有时区上正确反映为正常的时间形式。

当时的产品设计是有海外客户的,所以当时的设计,在数据库里保存的,应该是一个“准确的时间”。例如“20120926080000”实际上并没有严格的表示出时间,因为北京时间2012年9月26日8点和格林威治时间2012年9月26日8点显然是不一样的。

虽然我们都是在一个确切的时区里,例如中国都是使用东八区时间,但是需要考虑的是:

  • 有些产品是可能有海外客户的
  • 产品所运行的机器,时区的设置未必都是东八区。

在这种情况下,如果数据库里的时间不准确,会给程序运行带来问题。这种方式最大的缺点在于:

  • 不方便对时间进行分组查询,比如按月统计、按季 统计
  • DBA在维护时,不能直观的根据返回的行结果,看到简单明了的结果(看到的是毫秒数)

使用这种方式的特点是牺牲一点易用性和可理解性(不易于维护和理解),满足了查询结果的直观性和准确性要求,同时最大限度考虑运行效率。为了解决这个问题,我设计了一个辅助的措施,就是建立一个数据库函数来进行时间转换,把毫秒数的时间转为制定时区和格式的时间串,DBA 在维护时可以使用。测试了 Oracle 和 DB2 上,都可以这样。例如之前的查询的时候为:

SELECT username,user_addtime from userinfo

这个查询显示的是毫秒数,使用内置函数后写成:

SELECT username,date2str(user_addtime) from userinfo

这样返回的就是东八区、预先定义好格式的字符串了。

在之后的设计里,还使用过 YYYYMMDDHHmmSST 格式,其中的“T”指时区,加入时区,带来的影响有:

  • 日期时间字段就不能在使用数值来存储了,字符串比数字存储和检索的效率都要低。
  • 应用程序需要加上额外的处理

带来的好处是:

  • 便于 DBA 维护
  • 到什么时候,即便没有看到数据库设计文档,都能看明白并准确理解数据库中一条信息中,这个字段保存到确切信息

使用这种方式的特点是牺牲一点效率,满足了查询结果的直观性和准确性要求。

总结一下,字段类型的选择,还是根据场景的需要来选择,从功能、效率要求、持续开发的要求、维护的要求几个方面综合考虑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/158850.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wincc定时器功能介绍

1定时器功能介绍 WinCC中定时器的使用可以使WinCC按照指定的周期或者时间点去执行任务,比如周期执行变量归档、在指定的时间点执行全局脚本或条件满足时打印报表。WinCC已经提供了一些简单的定时器,可以满足大部分定时功能。但是在有些情况下&#xff0c…

Python 基础语法 Hello, World!

Python 基础语法 import concurrent.futures import threading import timedef switch_case(argument):switch {1: "这是第一种情况",2: "这是第二种情况",3: "这是第三种情况"}return switch.get(argument, "这是默认情况")def my_…

【计算机网络】多路复用的三种方案

文章目录 1. selectselect函数select的工作特性select的缺点 2. pollpoll函数poll与select的对比 3. epollepoll的三个接口epoll的工作原理epoll的优点LT和ET模式epoll的应用场景 🔎Linux提供三种不同的多路转接(又称多路复用)的方案&#xf…

6、信息打点——Web架构篇语言中间件数据库系统源码获取

1、信息搜集搜集哪些东西? 架构信息收集,主要包括:操作系统、开发语言、中间件容器、数据库类型、第三方软件等; web源码信息收集,CMS开源?闭源?售卖?自主研发? 进行web…

【python FastAPI】fastapi中如何限制输入参数,如何让docs更好看,如何自定义错误码json返回

原则: 输入输出都基于BaseModel依靠JSONResponse制定返回错误的json信息依靠装饰器中app.post制定responses字典从而让docs文档更丰富 import uvicorn from pydantic import BaseModel, Field from fastapi import FastAPI, HTTPException from fastapi.middleware…

Python之pyc文件的生成与反编译

目录 1、什么是pyc文件 2、手动生成pyc文件 3、pyc文件的执行 4、pyc文件的反编译 1、什么是pyc文件 pyc文件(PyCodeObject)是Python编译后的结果。当python程序运行时,编译的结果是保存于PyCodeObject,程序运行结束后&#x…

(动手学习深度学习)第13章 实战kaggle竞赛:狗的品种识别

文章目录 1. 导入相关库2. 加载数据集3. 整理数据集4. 图像增广5. 读取数据6. 微调预训练模型7. 定义损失函数和评价损失函数9. 训练模型 1. 导入相关库 import os import torch import torchvision from torch import nn from d2l import torch as d2l2. 加载数据集 - 该数据…

编程中的各种常见的文件编码有哪些?

在计算机编程中,常见的文件编码有很多种。下面是一些常见的文件编码: UTF-8(Unicode Transformation Format - 8-bit): 它是一种变长字符编码,能够表示世界上几乎所有的字符,是最常用的 Unicode…

java抽象类和static

抽象类 并不是所有的类都是用来描绘对象的, 如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类. 抽象类 使用abstract 修饰类抽象类不能被实例化。在抽象类当中,可以有抽象方法,或者 非抽象方法!什么是抽象方法,一个方…

基于野马算法优化概率神经网络PNN的分类预测 - 附代码

基于野马算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于野马算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于野马优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神经网络的光滑…

【FPGA】Verilog:计数器 | 异步计数器 | 同步计数器 | 2位二进制计数器的实现 | 4位十进制计数器的实现

目录 Ⅰ. 实践说明 0x00 计数器(Counter) 0x01 异步计数器(Asynchronous Counter)

深度学习中的图像融合:图像融合论文阅读与实战

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 abs 介绍图像融合概念,回顾sota模型,其中包括数字摄像图像融合,多模态图像融合, 接着评估一些代表方法 介绍一些常见应用,比如RGBT目标跟踪,…

鸿蒙4.0开发笔记之DevEco Studio启动时不直接打开原项目(二)

1、想要在DevEco Studio启动时不直接打开关闭前的那个项目,可以在设置中进行。 有两个位置可以进入“设置”,一个是左上角的File>Settings,二是右上方的设置图标。 2、进入Settings界面以后,选择Appearance&Behavior下面…

Java Stream中的API你都用过了吗?

公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享。 在本教程中,您将通过大量示例来学习 Java 8 Stream API。 Java 在 Java 8 中提供了一个新的附加包,称为 java.util.stream。该包由类、接口和枚举组成&#x…

AIGC创作系统ChatGPT网站系统源码,支持最新GPT-4-Turbo模型

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统,支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

万宾科技智能井盖的效果怎么样?

日常出行过程中,人们最不想看到交通拥堵或者道路维修等现象,因为这代表出行受到影响甚至会导致不能按时赴约等。所以城市路面的安全和稳定,是市民朋友非常关心的话题。骑行在路上的时候,如果经过井盖时发出异常声响,骑…

Apache配置文件详解

引言: Apache是一种功能强大的Web服务器软件,通过配置文件可以对其行为进行高度定制。对于初学者来说,理解和正确配置Apache的配置文件是非常重要的。本文将详细解释Apache配置文件的各个方面,并给出一些入门指南,帮助读者快速上手。 1、主配置文件(httpd.conf): 主…

jQuery【菜单功能、淡入淡出轮播图(上)、淡入淡出轮播图(下)、折叠面板】(五)-全面详解(学习总结---从入门到深化)

目录 菜单功能 淡入淡出轮播图(上) 淡入淡出轮播图(下) 折叠面板 菜单功能 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><…

这是大学生就业网站最基础的布局。

<!DOCTYPE html> <html> <head> <title>大学生就业网站</title> <style> /* Reset default margin and padding */ *, *::before, *::after { margin: 0; padding: 0; box-s…