java中的jpa_在JPA中处理Java的LocalDateTime

java中的jpa

几天前,我在处理JPA中的LocalDateTime属性时遇到问题。 在这篇博客文章中,我将尝试创建一个样本问题来说明该问题以及我使用的解决方案。

考虑以下实体,该实体为特定公司的员工建模–

@Entity
@Getter
@Setter
public class Employee {@Id@GeneratedValueprivate Long id;private String name;private String department;private LocalDateTime joiningDate;
}

我使用的是Spring Data JPA,因此创建了以下存储库–

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {}

我想找到在特定日期加入公司的所有员工。 为此,我从
JpaSpecificationExecutor

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>,JpaSpecificationExecutor<Employee> {}

并写了如下查询

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class EmployeeRepositoryIT {@Autowiredprivate EmployeeRepository employeeRepository;@Testpublic void findingEmployees_joiningDateIsZeroHour_found() {DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime joiningDate = LocalDateTime.parse("2014-04-01 00:00:00", formatter);Employee employee = new Employee();employee.setName("Test Employee");employee.setDepartment("Test Department");employee.setJoiningDate(joiningDate);employeeRepository.save(employee);// Query to find employeesList<Employee> employees = employeeRepository.findAll((root, query, cb) ->cb.and(cb.greaterThanOrEqualTo(root.get(Employee_.joiningDate), joiningDate),cb.lessThan(root.get(Employee_.joiningDate), joiningDate.plusDays(1))));assertThat(employees).hasSize(1);}
}

以上测试顺利通过。 但是,以下测试失败了(应该通过了)–

@Test
public void findingEmployees_joiningDateIsNotZeroHour_found() {DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime joiningDate = LocalDateTime.parse("2014-04-01 08:00:00", formatter);LocalDateTime zeroHour = LocalDateTime.parse("2014-04-01 00:00:00", formatter);Employee employee = new Employee();employee.setName("Test Employee");employee.setDepartment("Test Department");employee.setJoiningDate(joiningDate);employeeRepository.save(employee);List<Employee> employees = employeeRepository.findAll((root, query, cb) ->cb.and(cb.greaterThanOrEqualTo(root.get(Employee_.joiningDate), zeroHour),cb.lessThan(root.get(Employee_.joiningDate), zeroHour.plusDays(1))));assertThat(employees).hasSize(1);
}

与之前的测试唯一不同的是,在先前的测试中,我将零小时作为加入日期,而在这里,我使用了上午8点。 起初,我觉得很奇怪。 只要将员工的入职日期设置为一天的零小时,测试似乎就会通过,但是如果将其设置为任何其他时间,则测试都会失败。
为了调查问题,我打开了Hibernate日志记录,以查看实际查询和发送到数据库的值,并在日志中注意到了类似的内容–

2017-03-05 22:26:20.804 DEBUG 8098 --- [           main] org.hibernate.SQL:selectemployee0_.id as id1_0_,employee0_.department as departme2_0_,employee0_.joining_date as joining_3_0_,employee0_.name as name4_0_fromemployee employee0_whereemployee0_.joining_date>=?and employee0_.joining_dateHibernate:selectemployee0_.id as id1_0_,employee0_.department as departme2_0_,employee0_.joining_date as joining_3_0_,employee0_.name as name4_0_fromemployee employee0_whereemployee0_.joining_date>=?and employee0_.joining_date2017-03-05 22:26:20.806 TRACE 8098 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARBINARY] - [2014-04-01T00:00]2017-03-05 22:26:20.807 TRACE 8098 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARBINARY] - [2014-04-02T00:00]

显然,JPA 并未joinDate属性视为日期或时间,而是视为VARBINARY类型。 这就是与实际日期比较失败的原因。

我认为这不是一个很好的设计。 它没有抛出UnsupportedAttributeException之类的东西,而是默默地尝试将值转换为其他值,从而导致随机比较失败(不是完全随机)。 除非您有很强的自动化测试套件,否则在应用程序中很难找到这种类型的错误,幸运的是,我的情况是这样。

现在回到问题。 JPA无法正确转换LocalDateTime的原因非常简单。 JPA规范的最新版本(即2.1)是在Java 8之前发布的,因此它无法处理新的Date and Time API。

为了解决该问题,我创建了一个自定义转换器实现,该实现将LocalDateTime转换为
将java.sql.Timestamp保存到数据库之前,反之亦然。 那解决了问题–

@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {@Overridepublic Timestamp convertToDatabaseColumn(LocalDateTime localDateTime) {return Optional.ofNullable(localDateTime).map(Timestamp::valueOf).orElse(null);}@Overridepublic LocalDateTime convertToEntityAttribute(Timestamp timestamp) {return Optional.ofNullable(timestamp).map(Timestamp::toLocalDateTime).orElse(null);}
}

每当我尝试保存LocalDateTime属性时,上述转换器将自动应用。 我还可以使用来显式标记要显式转换的属性
javax.persistence.Convert注释–

@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime joiningDate;

完整的代码可以在Github上找到 。

翻译自: https://www.javacodegeeks.com/2017/03/dealing-javas-localdatetime-jpa.html

java中的jpa

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

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

相关文章

修改value_Python | 快速修改或命名N个文件夹名称,你会吗?

#欢迎交流&#xff1a;shuilinggan163.com#工作中&#xff0c;经常会遇到需要修改或新建很多文件的文件命&#xff0c;是一件重复且头疼的事情&#xff0c;下面一组Python代码&#xff0c;轻松教你快速实现&#xff01;程序一&#xff1a;根据文件(SSSSSS)新建并命名空文件夹im…

linux离线安装python3.7教程_Linux傻瓜式七步完美安装Python3.7

1 安装依赖包yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel gcc2 下载解压Python3.7# 1 首先切换到桌面cd /home# 2 下载wget http://www.python.org/f…

IntelliJ IDEA for Mac在MacOS模式下打开系统设置(偏好设置)的快捷键(Preferences Shortcut)

快捷键快捷键符号英文名称功能说明Command ,⌘,Open Settings dialog打开IDEA系统设置

gwt格式_GWT HTTP请求替代方案

gwt格式由于多种原因 &#xff0c;许多GWT用户放弃了RPC机制&#xff0c;这是GWT提供的调用后端的标准方法。 他们发现&#xff0c;在GWT RequestBuilder与其他可能不适合其应用程序模型的外部库之间迷失了自己。 这篇文章的目的是要通过GWT中众所周知的HTTP / Rest库来尝试使情…

簇的局部变量中布尔类型_java基础2(变量、常量、数据类型)

一、注释&#xff08;1&#xff09;什么是注释&#xff1f;解释说明的文字&#xff08;注释的内容不会被编译&#xff09;&#xff08;2&#xff09;注释的作用①对代码的解释说明 ②便于后期维护&#xff08;3&#xff09;注释的分类:①单行注释 //单行注释作用域:只在当前行有…

python生成海报_生成海报(前端 | python)

我最近没有摸鱼&#xff0c;一直都在工作。只不过目前需要爬一点数据 python 做的&#xff0c;之后看机会分享一下。忙着忙着老大说要生成海报&#xff0c;有个活动要给每个用户来个分享图。想法PS 批处理&#xff1f;脚本&#xff1f; 能甩出去的活都甩出去&#xff0c;机智如…

数位进制转换详解

文章目录进制进制转换二进制和十进制互相转换十进制 → 二进制十进制正整数 → 二进制十进制负整数 → 二进制十进制负小数 → 二进制十进制小数 → 二进制二进制 → 十进制二进制负整数 → 十进制二进制的正整数 → 十进制二进制小数 → 十进制二进制的负小数 → 十进制八进制…

java agent_如何脚踏实地构建Java Agent

java agent在构建Plumbr的多年中&#xff0c;我们遇到了许多具有挑战性的问题。 在其他方面&#xff0c;使Plumbr Java Agent可靠地执行而不会危及客户的应用程序&#xff0c;是一个特别棘手的问题。 从实时系统中安全地收集所有需要的遥测会带来很多问题。 其中一些非常简单&a…

python中链表和数组_数据结构笔记(一):数组、链表|python基础教程|python入门|python教程...

https://www.xin3721.com/eschool/pythonxin3721/(一)数组数组(Array)是一种线性表数据结构。它用一组连续的内存空间&#xff0c;来存储一组具有相同类型的数据。1、数组支持随机访问&#xff0c;根据下标随机访问的时间复杂度为 O(1)。通过 a[i]_address a[0]_address i*元…

旋转散点图_聚类分析的结果如何用散点图展示出来?

SPSS系统聚类输出的树状图广受用户喜爱&#xff0c;二阶聚类也可以输出一系列美观的可视化图形用来观察聚类效果&#xff0c;但我们发现Kmeans均值聚类没有提供可视化程度高的图形&#xff0c;那怎么办&#xff0c;我们自己来制作。数据小兵推荐使用3D散点图全方位观察K均值聚类…

async 打包异常_重新打包流中的异常

async 打包异常Java 8已有两年历史&#xff0c;但是仍然存在社区尚未为其开发好的解决方案库的用例&#xff0c;甚至边缘用例。 如何处理流管道中的检查异常就是这样一个问题。 Stream操作接受的功能接口不允许实现抛出已检查的异常&#xff0c;但是我们可能要调用许多方法。 显…

补码基础

关于补码&#xff0c;有如下比较有趣的演化过程: 假如计算机中使用 4 位的二进制表示数据&#xff0c;如图-2&#xff0c;最多能表示 0 到 15(10 进制)&#xff0c;之后有牛人做了 一个细微改动&#xff0c;如图-3&#xff0c;将所有二进制以 1 开头的数(大于 7 的数)放到 0 之…

身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」

作者&#xff1a;沫沫 政采云前端团队转发链接&#xff1a;https://mp.weixin.qq.com/s/fRDpXixnLIy9c0Uh2tMezQ前言近些年来&#xff0c;随着生物识别技术的逐渐成熟&#xff0c;基于深度学习的人脸识别技术取得了突破性进展&#xff0c;准确率显著提高。现阶段&#xff0c;人…

打开 谷歌浏览器exe_专治各种网银不服:两步开启微软Edge浏览器IE兼容模式

此前微软已经预告过Microsoft Edge将支持IE模式&#xff0c;即可以在该浏览器下使用IE模式加载某些特定的需要的网站。不过在后续更新中微软又突然改口不再面向普通用户提供此功能&#xff0c;而企业级用户若要使用还需要管理员提前配置。现在这款浏览器的正式版已经发布&#…

java单例枚举_Java增强枚举的用例

java单例枚举Brian Goetz在消息“ 增强枚举-用例 ”中写道&#xff1a;“我们希望就现在实现的功能[ 增强枚举 ]获得用户反馈。” 他陈述了他的消息的第一个目的&#xff1a;“开始工作&#xff0c;这是一些通用枚举可能有用的典型用例。” 所提供的两个示例中的第一个示例是重…

爱python网_Python

一、PIL库简介1.安装PIL库PIL库是Python的第三方库&#xff0c;需要手动通过pip工具安装。可通过cmd命令&#xff1a;pip install pillow 进行安装。(注意&#xff1a;出现pip不是内部处理命令时需要配置一下环境)。2.PIL库的功能PIL库支持图像存储、显示和处理&#xff0c;它…

python计算互信息_互信息公式及概述

在概率论和信息论中&#xff0c;两个随机变量的互信息(Mutual Information&#xff0c;简称MI)或转移信息(transinformation)是变量间相互依赖性的量度。不同于相关系数&#xff0c;互信息并不局限于实值随机变量&#xff0c;它更加一般且决定着联合分布 p(X,Y) 和分解的边缘分…

队列和消息队列_消息队列概述[幻灯片]

队列和消息队列昨天&#xff0c;我进行了一次演讲&#xff0c;探讨了使用消息队列的所有方面。 我以前曾写过“您可能不需要消息队列” –现在的结论有些细微差别&#xff0c;但我仍然坚持简单性的观点。 演讲探讨了使用消息队列的各种好处和用例&#xff0c;并讨论了典型“消…

反码、原码、补码的观点阐述

我自己是不认可所谓的原码、反码的说法&#xff0c;但是很多人在计算负数的二进制时&#xff0c;都会使用反码和原码的概念&#xff0c;我这里就简单梳理下吧。 十进制2的二进制数&#xff08;按8位的二进制举例&#xff09;如下&#xff1a; 原码&#xff1a;0000 0010 补码&…

aspose word 获取标题_Word干货|多级标题的自动编号怎么添加?

在对Word文档进行排版时&#xff0c;大家普遍认为的一个难点就是对多级标题添加自动编号&#xff0c;本期Word妹与大家分享相关技巧的使用。1、添加样式选中文本&#xff0c;点击开始——样式——选择标题1&#xff0c;相同的样式则可以借用F4来实现。PS&#xff1a;以同样方式…