Spring Data JPA 从入门到精通~实际工作的应用场景

在实际工作中,有哪些场景会用到自定义 Repository 呢,这里列出几种实际在工作中的应用案例。

1. 逻辑删除场景

可以用到上面说的两种实现方式,如果有框架级别的全局自定义 Respository 那就在全局实现里面覆盖默认 remove 方法,这样就会统一全部只能使用逻辑删除。但是一般是自定义一个特殊的删除Respository,让大家去根据不同的domain业务逻辑去选择使用此接口即可。

2. 当有业务场景要覆盖 SimpleJpaRepository 默认实现的时候

这种一般是具体情况具体分析的,一般实现特殊化的自定义 Respository 即可。

3. UUID 与 ID 的情况

经常在实际生产中会有这样的场景,对外暴露的是 UUID 查询方法,而对内呢暴露的是 Long 类型的 ID,这时候我们就可以自定义一个 FindByIDOrUUID 的底层实现方法,在自定义的 Respository 接口里面。

4. 使用 Querydsl

Spring Data JPA 里面还帮我们做了 QuerydslJpaRepository 用来支持 Querydsl 的查询方法,当我们引入 Querydsl 的时候 Spring 就会自动帮我们把 SimpleJpaRepository 的实现切换到 QuerydslJpaRepository 的实现。

5. 动态查询条件

由于 Data JPA 里面的 query method 或者 @query 注解不支持动态查询条件,正常情况下将动态条件写在 manager 或者 service 里面。这个时候如果是针对资源的操作,并且和业务无关的查询的时候可以放在自定义 Repository 里面(有个缺点就是不能使用 SimpleJpaRepository,里面的很多优秀的默认是实现方法,在实际工作中还是放在 service 和 manager 中多一些,只是给大家举个例子,知道有这么回事就行)。实例如下:

//我们假设要根据条件动态查询订单
public interface OrderRepositoryCustom {Page<Order> findAllByCriteria(OrderCriteria criteria); // 定义一个订单的定制化Repository查询方法,当然实际生产过程中,这里面可能不止一个方法。
}public class OrderRepositoryImpl implements OrderRepositoryCustom { @PersistenceContextEntityManager entityManager; /*** 一个动态条件的查询方法*/public List<Order> findAllByCriteria(OrderCriteria criteria) {// 查询条件列表final List<String> andConditions = new ArrayList<String>();final Map<String, Object> bindParameters = new HashMap<String, Object>();// 动态绑定参数和要查询的条件if (criteria.getId() != null) {andConditions.add("o.id = :id");bindParameters.put("id", criteria.getId());}if (!CollectionUtils.isEmpty(criteria.getStatusCodes())) {andConditions.add("o.status.code IN :statusCodes");bindParameters.put("statusCodes", criteria.getStatusCodes());}if (andConditions.isEmpty()) {return Collections.emptyList();}// 动态创建queryfinal StringBuilder queryString = new StringBuilder();queryString.append("SELECT o FROM Order o");// 动态拼装条件Iterator<String> andConditionsIt = andConditions.iterator();if (andConditionsIt.hasNext()) {queryString.append(" WHERE ").append(andConditionsIt.next());}while (andConditionsIt.hasNext()) {queryString.append(" AND ").append(andConditionsIt.next());}// 添加排序queryString.append(" ORDER BY o.id");// 创建 typed query.final TypedQuery<Order> findQuery = entityManager.createQuery(queryString.toString(), Order.class);// 绑定参数for (Map.Entry<String, Object> bindParameter : bindParameters.entrySet()) {findQuery.setParameter(bindParameter.getKey(), bindParameter.getValue());}//返回查询,结果。return findQuery.getResultList();}
}
//实际中此种就比较少用了,大家知道有这么回事,真是遇到特殊场景必须要用了,可以用此方法实现。

6. 扩展 JpaSpecificationExecutor 使其更加优雅

当我们动态查询的时候经常会出现下面的代码逻辑,写起来老是感觉有点不是特别优雅,且有点重复的感觉:

PageRequest pr = new PageRequest(page - 1, rows, Direction.DESC, "id");Page pageData = memberDao.findAll(new Specification() {@Overridepublic Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {List<Predicate> predicates = new ArrayList<>();if (isNotEmpty(userName)) {predicates.add(cb.like(root.get("userName"), "%" + userName + "%"));}if (isNotEmpty(realName)) {predicates.add(cb.like(root.get("realName"), "%" + realName + "%"));}if (isNotEmpty(telephone)) {predicates.add(cb.equal(root.get("userName"), telephone));}query.where(predicates.toArray(new Predicate[0]));return null;}}, pr);

使用了自定义的复杂查询,我们可以做到如下效果:

Page pageData = userDao.findAll(new MySpecification<User>().and(Cnd.like("userName", userName),Cnd.like("realName", realName),Cnd.eq("telephone", telephone)
).asc("id"), pr);

如果对 Spring MVC 比较熟悉的话,可以更进一步把其查询提交和规则直接封装到 HandlerMethodArgumentResolver 里面,把参数自动和规则匹配起来。

我们可以对如下代码进行参考,感觉实现的还不错,此段代码可以作参考,只是实现的还有点不完整,如下:

/*** 扩展Specification* @param <T>*/
public class MySpecification<T> implements Specification<T> {/*** 属性分隔符*/private static final String PROPERTY_SEPARATOR = ".";/*** and条件组*/List<Cnd> andConditions = new ArrayList<>();/*** or条件组*/List<Cnd> orConditions = new ArrayList<>();/*** 排序条件组*/List<Order> orders = new ArrayList<>();@Overridepublic Predicate toPredicate(Root<T> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {Predicate restrictions = cb.and(getAndPredicates(root, cb));restrictions = cb.and(restrictions, getOrPredicates(root, cb));cq.orderBy(getOrders(root, cb));return restrictions;}public MySpecification and(Cnd... conditions) {for (Cnd condition : conditions) {andConditions.add(condition);}return this;}public MySpecification or(Collection<Cnd> conditions) {orConditions.addAll(conditions);return this;}public MySpecification desc(String property) {this.orders.add(Order.desc(property));return this;}public MySpecification asc(String property) {this.orders.add(Order.asc(property));return this;}private Predicate getAndPredicates(Root<T> root, CriteriaBuilder cb) {Predicate restrictions = cb.conjunction();for (Cnd condition : andConditions) {if (condition == null) {continue;}Path<?> path = this.getPath(root, condition.property);if (path == null) {continue;}switch (condition.operator) {case eq:if (condition.value != null) {if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String) {if (!((String) condition.value).isEmpty()) {restrictions = cb.and(restrictions, cb.equal(path, condition.value));}} else {restrictions = cb.and(restrictions, cb.equal(path, condition.value));}}break;case ge:if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) {restrictions = cb.and(restrictions, cb.ge((Path<Number>) path, (Number) condition.value));}break;case gt:if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) {restrictions = cb.and(restrictions, cb.gt((Path<Number>) path, (Number) condition.value));}break;case lt:if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) {restrictions = cb.and(restrictions, cb.lt((Path<Number>) path, (Number) condition.value));}break;case ne:if (condition.value != null) {if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) {restrictions = cb.and(restrictions, cb.notEqual(path, condition.value));} else {restrictions = cb.and(restrictions, cb.notEqual(path, condition.value));}}break;case isNotNull:restrictions = cb.and(restrictions, path.isNotNull());break;}}return restrictions;}private Predicate getOrPredicates(Root<T> root, CriteriaBuilder cb) {// 相同的逻辑 Need TODOreturn null;}private List<javax.persistence.criteria.Order> getOrders(Root<T> root, CriteriaBuilder cb) {List<javax.persistence.criteria.Order> orderList = new ArrayList<>();if (root == null || CollectionUtils.isEmpty(orders)) {return orderList;}for (Order order : orders) {if (order == null) {continue;}String property = order.getProperty();Sort.Direction direction = order.getDirection();Path<?> path = this.getPath(root, property);if (path == null || direction == null) {continue;}switch (direction) {case ASC:orderList.add(cb.asc(path));break;case DESC:orderList.add(cb.desc(path));break;}}return orderList;}/*** 获取Path** @param path         Path* @param propertyPath 属性路径* @return Path*/private <X> Path<X> getPath(Path<?> path, String propertyPath) {if (path == null || StringUtils.isEmpty(propertyPath)) {return (Path<X>) path;}String property = StringUtils.substringBefore(propertyPath, PROPERTY_SEPARATOR);return getPath(path.get(property), StringUtils.substringAfter(propertyPath, PROPERTY_SEPARATOR));}/*** 条件*/public static class Cnd {Operator operator;String property;Object value;public Cnd(String property, Operator operator, Object value) {this.operator = operator;this.property = property;this.value = value;}/*** 相等** @param property* @param value* @return*/public static Cnd eq(String property, Object value) {return new Cnd(property, Operator.eq, value);}/*** 不相等** @param property* @param value* @return*/public static Cnd ne(String property, Object value) {return new Cnd(property, Operator.ne, value);}}/*** 排序*/@Getter@Setterpublic static class Order {private String property;private Sort.Direction direction = Sort.Direction.ASC;/*** 构造方法** @param property  属性* @param direction 方向*/public Order(String property, Sort.Direction direction) {this.property = property;this.direction = direction;}/*** 返回递增排序** @param property 属性* @return 递增排序*/public static Order asc(String property) {return new Order(property, Sort.Direction.ASC);}/*** 返回递减排序** @param property 属性* @return 递减排序*/public static Order desc(String property) {return new Order(property, Sort.Direction.DESC);}}/*** 运算符*/@Getter@Setterpublic enum Operator {/*** 等于*/eq(" = "),/*** 不等于*/ne(" != "),/*** 大于*/gt(" > "),/*** 小于*/lt(" < "),/*** 大于等于*/ge(" >= "), /*** 不为Null*/isNotNull(" is not NULL ");Operator(String operator) {this.operator = operator;}private String operator;}
}

7. 与之类似的解决方案还有 RSQL 的解决方案,可以参考Git_Hub上的此开源项目。

RSQL(RESTful Service Query Language)是 Feed Item Query Language (FIQL) 的超集,是一种 RESTful 服务的查询语言。这里我们使用 rsql-jpa 来实践,它依赖 rsql-parser 来解析 RSQL 语法,然后将解析后的 RSQL 转义到 JPA 的 Specification。

maven 的地址如下:

<dependency><groupId>com.github.tennaito</groupId><artifactId>rsql-jpa</artifactId><version>2.0.2</version>
</dependency>

GitHub 文档地址,详见这里。如果要立志做优秀的架构师,Spring Data JPA 的实现还是非常好的,包括开源的生态等也非常好。

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

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

相关文章

Linux IO - 同步,异步,阻塞,非阻塞

From&#xff1a;http://blog.csdn.net/historyasamirror/article/details/5778378 同步/异步&#xff0c;阻塞/非阻塞概念深度解析&#xff1a;http://blog.csdn.net/lengxiao1993/article/details/78154467 知乎上关于 阻塞和非阻塞、同步和异步 之间区别的生动解释。 htt…

java treeset比较,java中TreeSet的两种排序比较的方式

第一种是使得元素具有比较性第二种是让集合具有比较性具体代码步骤如下&#xff1a;import java.util.*;/** TreeSet&#xff1a;可以自动对对集合中的元素进行排序* 第一种比较方式* 步骤&#xff1a;* 1.让元素对象的类具有比较性&#xff0c;并实现Comparable接口* 2.对其中…

在 IE 中使用 HTML5 元素

一个HTML5范本 <html><head><style>blah {color:red;}</style></head><body><blah>Hello!</blah></body></html>一个简洁的 方法 让样式在 IE 中作用到未知的元素上——仅需 JS 创建此未知元素即可&#xff1a; &…

微软 AI 设计原则:成为弱者,再带来惊喜

来源&#xff1a;36Kr 作者&#xff1a;木木子编者按&#xff1a;AI设计的思路是什么&#xff1f;更完美&#xff1f;更能想用户之所想&#xff1f;本文作者Cliff Kuang在“The company studied personal assistants–human ones–to understand how to make a great machine…

vim 中的杀手级插件: vundle (vim 插件管理器)

From&#xff1a;http://zuyunfei.com/2013/04/12/killer-plugin-of-vim-vundle/ vundle.txt&#xff1a;https://github.com/VundleVim/Vundle.vim/blob/master/doc/vundle.txt Vundle 的具体介绍和配置&#xff1a;github repo&#xff1a;https://github.com/gmarik/vundl…

同步锁 php,python线程中同步锁详解

这篇文章主要为大家详细介绍了python线程中同步锁的相关资料&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下在使用多线程的应用下&#xff0c;如何保证线程安全&#xff0c;以及线程之间的同步&#xff0c;或者访问共享变量等问题是十分棘手的问题&a…

移动平均线分析法

移动平均线分析法是由道琼斯股价理论演变出来的一种股价趋势分析方法。其基本思想是消除股价随机波动的影响&#xff0c;以寻求股价波动的趋势。主要特点&#xff1a;1、追踪趋势&#xff1a;MA能够表示股价波动的趋势&#xff0c;并追踪这个趋势不轻易改变。2、滞后性&#xf…

Spring Data JPA 从入门到精通~Auditing及其事件详解

Auditing 及其事件详解 Auditing 翻译过来是审计和审核&#xff0c;Spring 的优秀之处在于帮我们想到了很多繁琐事情的解决方案&#xff0c;我们在实际的业务系统中&#xff0c;针对一张表的操作大部分是需要记录谁什么时间创建的&#xff0c;谁什么时间修改的&#xff0c;并且…

未来城市的无人机送货系统是怎样的?

来源&#xff1a; 资本实验室 作者&#xff1a;李鑫Siri通过移动应用下了一盒巴克拉拉面膜的订单&#xff0c;电商平台收到信息&#xff0c;发指令给最近的送货驳船。驳船上的无人机获取货物包裹后直接飞向Siri家。在不到8分钟的飞行后&#xff0c;无人机来到位于12层的Siri家…

Vim自动补全神器:YouCompleteMe

From&#xff1a;http://www.jianshu.com/p/d908ce81017a github 地址&#xff1a;https://github.com/Valloric/YouCompleteMe YouCompleteMe is a fast, as-you-type, fuzzy-search code completion engine for Vim. 参考&#xff1a; https://github.com/Valloric/YouCom…

故障树分析法MATLAB,故障树分析(FTA)方法及其基于VC的软件设计的研究

故障树分析法(FTA)是一种评价复杂系统可靠性与安全性的重要方法。经过近四十年的发展,FTA技术已经有相对成熟的理论,但是在FTA的组合爆炸困难(计算量随故障树规模指数增长)、相关底事件的FTA 等方面还有待于进一步的研究。而且随着系统复杂性的加大,系统所含部件愈来愈多,研究系…

Windows 7硬盘安装方法大全

Windows 7硬盘安装方法大全&#xff0c;共整理出四种方法该Windows 7硬盘安装方法大全介绍了Windows 7下安装高版本的Windows 7&#xff0c;Vista下硬盘安装Windows 7&#xff0c;xp下硬盘安装Windows7等方法&#xff01; 一、 windows 7 系统下全新安装高版Windows7&#xff1…

对比 | 欧洲、美国、中国智慧城市的不同实践路径

来源&#xff1a;《上海城市规划》2018年第1期《欧美智慧城市最新实践与参考》作者&#xff1a;刘杨 龚烁 刘晋媛随着ICT、大数据、物联网等各类新兴技术的不断发展&#xff0c;智慧城市的运营和实践也不断趋于成熟。通过整理欧美各大典型智慧城市的最新实践案例&#xff0c;总…

C++ 使用 TinyXml 解析 XML 文件

知乎 C解析xml有什么好用的轮子? &#xff1a;https://www.zhihu.com/question/32046606 TinyXML-2 的 github地址和帮助文档&#xff1a;https://github.com/leethomason/tinyxml2 tinyxml 下载地址&#xff1a;https://sourceforge.net/projects/tinyxml/ *Please Note*…

java1.8.0,jdk1.8.0版本

【实例简介】jdk1.8版本&#xff0c;亲测可用。望有需求人士放心使用&#xff0c;下载。【实例截图】【核心代码】31449426-2a86-4e86-9718-9b4327dbb178└── jdk-8u161-windows-x64├── 1041│ ├── [5]DigitalSignature│ ├── [5]MsiDigitalSignatureEx│ ├─…

定制自己的Windows CE 5.0 ARM中文模拟器(转)

定制自己的Windows CE 5.0 ARM中文模拟器(转)http://showvi.com/Blog/ViewAirticle/59一、生成OS 1. 安装Windows CE 5.0&#xff08;记得CPU类型里把ARMV4I选上&#xff09;装完之后装DeviceEmulatorBSP.msi&#xff0c;这是ARMV4I模拟器的BSP。 我补充个DeviceEmulatorBSP.ms…

Spring Data JPA 从入门到精通~@Version处理乐观锁的问题

Version 处理乐观锁的问题 Version 乐观锁介绍 我们在研究 Auditing 的时候&#xff0c;发现了一个有趣的注解 Version&#xff0c;源码如下&#xff1a; package org.springframework.data.annotation; /*** Demarcates a property to be used as version field to impleme…

人工智能即服务 当人工智能遇到云计算

来源&#xff1a;企业网为了在竞争中保持领先地位&#xff0c;越来越多的企业正在寻求将人工智能技术整合到其应用程序、产品、服务&#xff0c;以及大数据分析方法中。而企业开始使用人工智能技术的最简单和最流行的方法之一是使用基于云计算的人工智能即服务产品。根据调研机…

视频裁剪

用【格式工厂FFSetup190.exe】将视频文件格式专程AVI, 再用视频裁剪工具【SolveigMM AVI Trimmer】裁剪需要的段。 源文件-添加视频文件-填入开始时间和停止时间&#xff08;用三耳确定填写的时间值&#xff09;-按添加按钮-选择目的文件路径及名称-运行。 转载于:https://www.…

三星s9php禁用列表,ADB禁用列表

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼谷歌程序pm uninstall --user 0com.google.android.ext.servicespm uninstall --user 0com.google.android.onetimeinitializerpm uninstall --user 0com.google.android.ext.sharedpm uninstall --user 0com.google.android.confi…