JDBC操作MySQL5日期类型字段的问题解决方法

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介:
由于日期数据的特殊性和多样性,以及不同的数据库、编程语言对日期的定义和处理方式差别,导致了日期处理的复杂性,和多样性。
 
流行的Hibernate、iBatis等持久化框架从中解决了各种Java日期与数据库日期之间操作的细节问题,JDBC操作数据库日期的问题已经被淡化了。但是对于纯JDBC开发者来说,这些问题不可小觑。
 
下面以MySQL5和Java5为基础,说明Java处理数据库日期的一些问题及解决方案。
 
认识MySQL的日期类型:
列类型
”值
DATETIME
'0000-00-00 00:00:00'
DATE
'0000-00-00'
TIMESTAMP
00000000000000
TIME
'00:00:00'
YEAR
0000
从零值类型,也可以清晰看出日期的格式,再次,并不想讨论所有的数据类型,二是针对前三种常用类型做以分析。
 
MySQL日期类型的一些说明:
当你需要同时包含日期和时间信息的值时则使用DATETIME类型。MySQL以'YYYY-MM-DD HH:MM:SS'格式检索和显示DATETIME值。 
当你只需要日期值而不需要时间部分时应使用DATE类型。MySQL用'YYYY-MM-DD'格式检索和显示DATE值。 
TIMESTAMP列类型的属性不固定,取决于MySQL版本和服务器运行的SQL模式。 
TIMESTAMP列的显示格式与DATETIME列相同。换句话说,显示宽度固定在19字符,并且格式为YYYY-MM-DD HH:MM:SS。 

在一定程度上,可以将一个日期类型的值分配给一个不同的日期类型。但是,值可能会更改或丢失一些信息: 

·                 如果你为一个DATETIME或TIMESTAMP对象分配一个DATE值,结果值的时间部分被设置为'00:00:00',因为DATE值未包含时间信息。 

·                 如果你为一个DATE对象分配一个DATETIME或TIMESTAMP值,结果值的时间部分被删除,因为DATE值未包含时间信息。 

·                 记住尽管可以使用相同的格式指定DATETIME、DATE和TIMESTAMP值,不同类型的值的范围却不同。例如,TIMESTAMP值不能早于1970或晚于2037。这说明一个日期,例如'1968-01-01',虽然对于DATETIME或DATE值是有效的,但对于TIMESTAMP值却无效,如果分配给这样一个对象将被转换为0。 

当指定日期值时请注意某些缺陷: 

·                 指定为字符串的值允许的非严格格式可能会欺骗。例如,值'10:11:12'由于‘:’间割符看上去可能象时间值,但如果用于日期上下文值则被解释为年'2010-11-12'。值'10:45:15'被转换为'0000-00-00'因为'45'不是合法月。 

·                 在非严格模式,MySQL服务器只对日期的合法性进行基本检查:年、月和日的范围分别是1000到9999、00到12和00到31。任何包含超出这些范围的部分的日期被转换成'0000-00-00'。请注意仍然允许你保存非法日期,例如'2002-04-31'。要想确保不使用严格模式时日期有效,应检查应用程序。
 
 
问题:
对于JDBC写入MySQL数据库类型发生时分秒丢失的问题。
从数据库读出日期,时分秒丢失问题。
增删改查日期类型字段发生传参等错误的问题。
 
对于以上的问题,是非常普遍的。这里从数据库日期类型的精度需求入手,以MySQL5为蓝本,以JDBC为访问手段,研究日期的操作。
 
环境:
Java5
mysql-noinstall-5.1.40-win32.zip
mysql-connector-java-5.1.10.zip
 
一、要求最高精度的日期数据,timestamp类型,这种日期类型带最高精度,但与数据库设置有关系,一般默认即可。
 
 
建表SQL
create  database    

use testdb; 

drop  table  if  exists testdate; 

create  table testdate ( 
    id  bigint(20)  not  null auto_increment, 
    code  varchar(20)  default  null
    crdate  timestamp  not  null  default  current_timestamp
     primary  key (id) 
) engine=myisam auto_increment=122  default charset=latin1;
 
测试结论:
  ----------插入----------------------------------- 
   //对于插入,静态SQL,字符串型的日期格式是正确的 
  String sql_1 =  "insert into testdate(code,crdate) values ('x',CURRENT_TIMESTAMP)";    
  String sql_2 =  "insert into testdate(code,crdate) values ('y','2009-11-09 13:00:23')";    

   //对于插入,预定义SQL,java.sql.Timestamp型的日期格式参数是正确的 
  String sql =  "insert into testdate(code,crdate) values ('z',?)";    
  PreparedStatement pstmt = conn.prepareStatement(sql);    
  pstmt.setTimestamp(1,  new Timestamp(System.currentTimeMillis()));    

   //对于插入,预定义SQL,java.lang.String型的日期格式参数是正确的 
  String sql =  "insert into testdate(code,crdate) values ('w',?)";    
  PreparedStatement pstmt = conn.prepareStatement(sql);    
  pstmt.setString(1,  "2009-11-09 13:00:23");    

  ----------更新----------------------------------- 
   //对于更新,静态SQL,字符串型的日期格式是正确的 
  String sql =  "update testdate set crdate = '2009-12-12 13:33:15' where code = 'z'";    

   //对于更新,预定义SQL,java.lang.String型的日期格式参数是正确的 
  String sql =  "update testdate set crdate = ? where code = 'z'";    
  PreparedStatement pstmt = conn.prepareStatement(sql);    
  pstmt.setString(1,  "2009-12-12 13:33:15");    

  ----------查询----------------------------------- 

   //对于查询,静态SQL(两种写法),java.lang.String型的日期格式参数是正确的 
  String sql =  "select * from testdate where crdate > '2009-11-09 13:00:23' and crdate < '2009-11-10 13:00:23'";    
  String sql =  "select * from testdate where date_format(crdate, '%Y-%c-%e %T') between '1900-2-1 00:00:00' and '2010-2-5 00:00:00'"
  Statement stmt = conn.createStatement();    
  ResultSet rs = stmt.executeQuery(sql);    
   while (rs.next()) {    
    System.out.println( ">>> id=" + rs.getLong( "id") +  "; code=" + rs.getString( "code") +  "; crdate=" + rs.getTimestamp( "crdate"));    
  }    


   //但对于查询,预定义SQL,java的字符串和Timestamp类型参数都是错误的,不能执行,会提示语法错误。 
   //但别的数据库就另当别论了。 
  pstmt.setString(1, "2009-11-09 13:00:23"); 
  pstmt.setString(2, "2009-11-10 13:00:23"); 
  pstmt.setTimestamp(1, new Timestamp(sf.parse( "2009-11-09 13:00:23").getTime())); 
  pstmt.setTimestamp(2, new Timestamp(sf.parse( "2009-11-10 13:00:23").getTime()));
 
可以看出,字符串类型还是支持比较好。在SQL和Java语言之间都能良好的支持。
 
二、要求高精度的日期数据,选择datetime类型,这种日期格式带时分秒,用的较多。
 
对于上面表的crdate类型改下即可。
测试结论是:
  ----------插入----------------------------------- 
   //对于插入,静态SQL,字符串型的日期格式是正确的 
  String sql_1 =  "insert into testdate(code,crdate) values ('x',CURRENT_TIMESTAMP)";    
  String sql_2 =  "insert into testdate(code,crdate) values ('y','2009-11-09 13:00:23')";    

   //对于插入,预定义SQL,java.sql.Timestamp型的日期格式参数是正确的 
  String sql =  "insert into testdate(code,crdate) values ('z',?)";    
  PreparedStatement pstmt = conn.prepareStatement(sql);    
  pstmt.setTimestamp(1,  new Timestamp(System.currentTimeMillis()));    

   //对于插入,预定义SQL,java.lang.String型的日期格式参数是正确的 
  String sql =  "insert into testdate(code,crdate) values ('w',?)";    
  PreparedStatement pstmt = conn.prepareStatement(sql);    
  pstmt.setString(1,  "2009-11-09 13:00:23");    

  ----------更新----------------------------------- 
   //对于更新,静态SQL,字符串型的日期格式是正确的 
  String sql =  "update testdate set crdate = '2009-12-12 13:33:15' where code = 'z'";    

  ----------查询----------------------------------- 

   //对于查询,静态SQL(两种写法),java.lang.String型的日期格式参数是正确的 
  String sql =  "select * from testdate where crdate > '2009-11-09 13:00:23' and crdate < '2009-11-10 13:00:23'";    
  String sql =  "select * from testdate where date_format(crdate, '%Y-%c-%e %T') between '1900-2-1 00:00:00' and '2010-2-5 00:00:00'"
  Statement stmt = conn.createStatement();    
  ResultSet rs = stmt.executeQuery(sql);    
   while (rs.next()) {    
    System.out.println( ">>> id=" + rs.getLong( "id") +  "; code=" + rs.getString( "code") +  "; crdate=" + rs.getTimestamp( "crdate"));    
  }    
 
三、对于date类型,因为不带时分秒,用的较少。
 
四、JDBC操作timestamp和datetime时候应该注意的问题
 
1、JDBC读取时候,应该选择getTimestamp()方法来读取,这样才能保持数据精度。
如果选择了getDate读取,则自动丢弃时分秒,造成精度下降。
 
2、JDBC读取的数据保存为java类型时候,应该定义为java.util.Date,这样可以保持原有的精度,如果设置成java.sql.Date,则造成时分秒丢失。
 
3、java.sql.Date是Java历史的垃圾,尽量避免使用。
 
4、在执行预定义SQL的时候,java.lang.String参数似乎是更好的方式。
 
本文也许是此同类问题的一个开始话题,仅仅演示了MySQL中的高精度日期类型操作一些正确方法,并非全部,但这些结论仅仅局限于MySQL5.


本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/224370,如需转载请自行联系原作者
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
Python
Python 采集109个中国风风格PPT
Python 采集109个中国风风格PPT
247 3
|
8月前
|
并行计算 监控 调度
150%训练效率提升:感知检测小模型训练优化方法
本文章基于业务实践,总结有关感知检测小模型在不同算力卡上的训练方法,为有智能驾驶的场景提供可行的借鉴方法。
|
10月前
|
设计模式 Prometheus 监控
并发设计模式实战系列(20):扇出/扇入模式(Fan-Out/Fan-In)(完结篇)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第二十章,废话不多说直接开始~
316 0
|
10月前
|
人工智能 自然语言处理 搜索推荐
AI 零成本搭建个人网站,小白 3 步搞定!通义灵码智能体+MCP 新玩法
通过AI技术,即使不编写代码也能高效开发项目。从生成诗朗诵网页到3D游戏创建,这些令人惊叹的操作如今触手可及。经过摸索,我利用AI成功上线了个人站点:https://koi0101-max.github.io/web。无需一行代码,借助强大的工具即可实现创意,让开发变得简单快捷!
3092 72
|
8月前
|
算法 关系型数据库 Java
Springboot集成PostGIS完成路径规划
因为公司里需要做关于林区防火方面的项目,需要完成着火后山区路径的导航,但.....某德的功能似乎只能到达山区的边上,后边的路就需要自己完成导航了。搞了一个周终于有所效果了,也遇见了很多的坑,在此记录一下,希望以后不要踩坑。需要上述的环境才能进行路径导航,环境的搭建可以参阅
260 5
|
JSON 前端开发 Java
如何封装接口返回结构?
本文详细探讨了API接口返回结构统一化的必要性及其带来的优势,如降低开发的心智负担、减少前端开发难度和提高代码可维护性等。同时也分析了其潜在的缺点,例如灵活性降低和开发成本增加等问题。文章进一步讨论了在Spring Boot中实现统一接口返回结构的具体方法和技术细节,包括如何处理HTTP状态码、返回单个字符串的情况以及如何封装无返回值的接口等。此外,还介绍了如何利用Spring Boot的`ResponseBodyAdvice`和`@RestControllerAdvice`等特性来自动包装控制器方法的返回值及异常处理,以达到更加一致和标准化的接口响应结构。
364 3
如何封装接口返回结构?
|
机器人 Shell Python
ROS2教程05 ROS2服务
这篇文章是关于ROS2(Robot Operating System 2)服务的教程,涵盖了服务的概念、特性、命令行工具的使用,以及如何编写服务的服务器和客户端代码,并提供了测试服务通信机制的示例。
621 4
ROS2教程05 ROS2服务
|
API Android开发 Kotlin
Android实战经验分享之如何获取状态栏和导航栏的高度
在Android开发中,掌握状态栏和导航栏的高度对于优化UI布局至关重要。本文介绍两种主要方法:一是通过资源名称获取,简单且兼容性好;二是利用WindowInsets,适用于新版Android,准确性高。文中提供了Kotlin代码示例,并对比了两者的优缺点及适用场景。
1658 1
|
Python
Python函数式编程:你真的懂了吗?理解核心概念,实践高阶技巧,这篇文章带你一次搞定!
【8月更文挑战第6天】本文介绍了Python中的函数式编程,探讨了高阶函数、纯函数、匿名函数、不可变数据结构及递归等核心概念。通过具体示例展示了如何利用`map()`和`filter()`等内置函数处理数据,解释了纯函数的一致性和可预测性特点,并演示了使用`lambda`创建简短函数的方法。此外,文章还强调了使用不可变数据结构的重要性,并通过递归函数实例说明了递归的基本原理。掌握这些技巧有助于编写更清晰、模块化的代码。
286 3

热门文章

最新文章