首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【玩转腾讯云】一次jpa自定义查询方法的使用尝试过程

【玩转腾讯云】一次jpa自定义查询方法的使用尝试过程

原创
作者头像
Ezio4396
修改于 2021-04-08 09:10:11
修改于 2021-04-08 09:10:11
2K1
举报

一次jpa自定义查询方法的使用尝试过程

项目测试环境

腾讯云服务器(装好mysql后,连接外网地址做为测试环境)

项目需求

目前客户有一个需求:每一个用户想要看到的帖子顺序都不一样,用户可以按照自己的喜好排列帖子顺序,并且可以手动把某个帖子置顶显示。

现在项目数据交互使用的框架是spring-boot-starter-data-jpa。之前因为项目的工期很赶,所写的代码为直接使用jpa的findAll方法即可满足查询。现在查询条件的变化后,我想要在原本的基础上改动的内容越小越好。

<!--more-->

尝试过程

第一次尝试

我尝试使用下面的命名方式去直接自定义查询方法,来根据userId属性查询所关联的权重表,再根据权重表来查询到帖子表进行排序。

然而这种方法只能查询到这个用户已经排序过的帖子,并不可以看得到没有和该用户关联的帖子。放弃

自定义方法名

jpa框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。

在创建查询时,我们通过在方法名中使用属性名称来表达,比如 findByUserAddressZip ()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,详细规则如下(此处假设该方法针对的域对象为 AccountInfo 类型):

  • 先判断 userAddressZip (根据 POJO 规范,首字母变为小写,下同)是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第二步;
  • 从右往左截取第一个大写字母开头的字符串(此处为 Zip),然后检查剩下的字符串是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user 为 AccountInfo 的一个属性;
  • 接着处理剩下部分( AddressZip ),先判断 user 所对应的类型是否有 addressZip 属性,如果有,则表示该方法最终是根据 "AccountInfo.user.addressZip" 的取值进行查询;否则继续按照步骤 2 的规则从右往左截取,最终表示根据 "AccountInfo.user.address.zip" 的值进行查询。

可能会存在一种特殊情况,比如 AccountInfo 包含一个 user 的属性,也有一个 userAddress 属性,此时会存在混淆。读者可以明确在属性之间加上下划线以显式表达意图,比如 "findByUser_AddressZip()" 或者 "findByUserAddress_Zip()"。

在查询时,通常需要同时根据多个属性进行查询,且查询的条件也格式各样(大于某个值、在某个范围等等),Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下:

  • And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);
  • Or --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);
  • Between --- 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);
  • LessThan --- 等价于 SQL 中的 "<",比如 findBySalaryLessThan(int max);
  • GreaterThan --- 等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min);
  • IsNull --- 等价于 SQL 中的 "is null",比如 findByUsernameIsNull();
  • IsNotNull --- 等价于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();
  • NotNull --- 与 IsNotNull 等价;
  • Like --- 等价于 SQL 中的 "like",比如 findByUsernameLike(String user);
  • NotLike --- 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);
  • OrderBy --- 等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);
  • Not --- 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user);
  • In --- 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
  • NotIn --- 等价于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;

第二次尝试

在网上搜索相关文章时突然发现了这个Api查询条件的限制类,仔细查找研究了一下。发现还是没有找到可以解决这个的方案。

Example matchers

首先,仓库接口需要继承QueryByExampleExecutor接口(继承这个 JpaSpecificationExecutor 也行),这样会引入一组以Example作参数的方法。然后创建一个ExampleMatcher对象,最后再用Example的of方法构造相应的Example对象并传递给相关查询方法。

Example不仅仅局限于默认的设置。你可以给strings定义自己的默认值然后去匹配。使用ExampleMatcher绑定null和特定属性的设置。

代码语言:txt
AI代码解释
复制
Person person = new Person();                          
person.setFirstname("Dave");                           

ExampleMatcher matcher = ExampleMatcher.matching()    
  .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.startsWith())  //模糊查询匹配开头,即{username}%
  .withMatcher("address" ,ExampleMatcher.GenericPropertyMatchers.contains())  //全部模糊查询,即%{address}%
  .withIgnorePaths("lastname")  //忽略字段,即不管lastname是什么值都不加入查询条件                 
  .withIncludeNullValues()       
  .withStringMatcherEnding();                          

Example<Person> example = Example.of(person, matcher); 

其中:

  • Person person = new Person(); 创建一个domain对象实例。
  • 设置属性值去查询。
  • ExampleMatcher matcher = ExampleMatcher.matching() 创建一个 ExampleMatcher 让其可以使用,但没有多余的配置项。
  • .withIgnorePaths("lastname") Construct a new ExampleMatcher to ignore the property path lastname。用来排除某个属性的查询。
  • .withIncludeNullValues() Construct a new ExampleMatcher to ignore the property path lastname and to include null values。让空值也参与查询。
  • .withStringMatcherEnding(); Construct a new ExampleMatcher to ignore the property path lastname, to include null values, and use perform suffix string matching。匹配后缀字符串
  • Example<Person> example = Example.of(person, matcher); 根据domain对象和配置的ExampleMatcher对象来创建一个Example

还可以给个别的属性指定行为.(比如.firstnamelastname以及domain对象的嵌套属性address.city)

  • .ignoreCase() 可以调整他让他匹配大小写敏感的选项。
  • endsWithfirstname 结束的前模糊查询。
  • startWithlastname开始的后模糊查询。
代码语言:txt
AI代码解释
复制
ExampleMatcher matcher = ExampleMatcher.matching()
  .withMatcher("firstname", endsWith())
  .withMatcher("lastname", startsWith().ignoreCase());
}

第四次尝试

没办法,要改动的步骤越来越大。以上的方法都不行的前提下,我只好试了试 Specification 作为 findAll 的参数这种方法。可是虽然用起来要改动的代码很少,但是还是不能查询到我想要的查询结果。查询条件只能加在where上面,而我想要的是用户排过序的加入条件查询,没有排过序的也要排列在后面。

JpaSpecificationExecutor

首先,仓库接口要继承 JpaSpecificationExecutor<T> 这个类,之后就可以使用 findAll(Specification<T> spec)等方法了。

代码语言:txt
AI代码解释
复制
Specification specification = new Specification() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery query,
        CriteriaBuilder cb) {
        List<Predicate> list = new ArrayList<>();
        if (Objects.nonNull("1")) {
            Join<WeightSort, ProjectInfo> join = root.join("weightSort", JoinType.LEFT);
            list.add(cb.equal(join.get("user").get("username"), "zs"));
        }

        if (Objects.nonNull(param.getYear())) {
            list.add(cb.equal(root.get("year"), param.getYear()));
        }
        if (Objects.nonNull(param.getTag())) {
            list.add(cb.like(root.get("tag"), param.getTag() + "%"));
        }

        return query.where(list.toArray(new Predicate[0])).getRestriction();
    }
};
Page<ProjectInfo> projectInfoPageTest = projectInfoRepository.findAll(specification, page);
projectInfoPageTest.stream().forEach(projectInfo -> {
    System.out.println(projectInfo.getId());
});

其中:

  • join 为外键关联查询,通过 project 类中的 WeightSort weightSort;中的 User user 中的 String username属性来作为条件查询。该条件加在where后面。
  • cb.equal 为匹配查询,相当于where后面的=号属性查询。
  • cb.like 为模糊匹配查询,相当于where后面的like属性查询。

上面的代码产生的sql语句为:

代码语言:txt
AI代码解释
复制
SELECT
	p.* 
FROM
	bs_project_info p
	LEFT JOIN bs_project_info_weight_sorts pw ON p.id = pw.project_info_id
	LEFT JOIN bs_weight_sort w ON w.id = pw.weight_sorts_id
	LEFT JOIN system_user u ON u.id = w.user_id
	WHERE
	 u.username = 'zs'
	 and p.year = 2019
	 and p.tag like 'sql%'

但是这种方法还是要写很多行代码,不如把之前的原本的 findAll(Example example) 利用起来。

代码如下:

代码语言:txt
AI代码解释
复制
Example example = Example.of(ProjectInfo.builder().weightSort(null).build());
Page<ProjectInfo> pages = projectInfoRepository.findAll((root, query, cb) -> {
   List<Predicate> predicates = new ArrayList<>();
    predicates.add(QueryByExamplePredicateBuilder.getPredicate(root, cb, example));

    Join<WeightSort, ProjectInfo> join = root.join("weightSort", JoinType.LEFT);
    predicates.add(cb.equal(join.get("user").get("username"), "zs"));

    return query.where(predicates.toArray(new Predicate[0])).getRestriction();
}, page);
pages.stream().forEach(projectInfo -> {
    System.out.println(projectInfo.getId());
});

这样就可以把一些属性相等的条件放进 Example 类里,而且该类本就支持不加入null的条件查询。不用再去判断传入参数为null时不做条件查询。利用上jpa的动态条件查询,节省了很多行代码。

最终的结局

没办法,实在是没有找到可以解决这个问题的方法。只好直接使用原生sql语句来满足需求。

原生sql,Query注释

@Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL 查询语句即可,如下所示:

使用 @Query 提供自定义查询语句示例:

代码语言:txt
AI代码解释
复制
@Query(value = "SELECT "
        + "p.* "
        + " FROM "
        + " bs_project_info p "
        + " LEFT JOIN ( bs_project_info_weight_sorts pw JOIN bs_weight_sort w ON w.id = pw.weight_sorts_id AND w.user_id = :#{#param.userId} )
        +  ON pw.project_info_id = p.id "
        + "where  "
        + " IF( :#{#param.name} IS NOT null, p.name= :#{#param.name},  1=1) and "
        + " IF( :#{#param.year} IS NOT null, p.year = :#{#param.year},  1=1) and "
        + " IF( :#{#param.review} IS NOT null, p.review = :#{#param.review},  1=1) "
        + "ORDER BY "
        + "w.weight desc, p.create_time desc limit :#{#param.pageStart}, :#{#param.sizeStart}", nativeQuery=true)
    List<ProjectInfo> findAllPageProjectByParam(@Param("param") FindProjectParam param);

输入参数 FindProjectParam 类:

代码语言:txt
AI代码解释
复制
@ApiModel
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class FindProjectParam {

    @ApiModelProperty(value ="名称(不填为全部)", example = Mock.SPECIALNAMEID)
    Long name;
    
    @ApiModelProperty(value ="年度(不填为全部)", example = "2019")
    Integer year;
    
    @ApiModelProperty(value ="项目状态(3-待提交,1-已提交)(不填为全部)", example = Mock.REVIEW)
    Integer review;
    
    @ApiModelProperty(value ="用户id", example = Mock.USERNAME)
    Long userId;
    
    @ApiModelProperty(value ="页数")
    Integer pageStart;
    
    @ApiModelProperty(value ="条数")
    Integer sizeStart;
}

查询 ProjectInfo 类(数据库表名为:bs_project_info):

代码语言:txt
AI代码解释
复制
package com.yiring.finance.domain.projectinfo;

import com.yiring.finance.domain.constructioncontent.ConstructionContent;
import com.yiring.finance.domain.dictionary.DictionaryType;
import com.yiring.finance.domain.guide.Guide;
import com.yiring.finance.domain.uploadfile.FileOperation;
import com.yiring.finance.domain.weightsort.WeightSort;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.hibernate.annotaions.Comment;

/**
 * 项目
 *
 * @author zs
 * @date 2021/3/3 17:31
 */

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Comment("项目")
@Table(name = "bs_project_info")
public class ProjectInfo implements Serializable {

    private static final long serialVersionUID = -2079824786038520972L;

    @Comment("主键")
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Comment("项目名称")
    @ApiModelProperty(value ="区域项目名称", example = "2", required = true)
    String projectName;

    @Comment("申报年份")
    @ApiModelProperty(value ="申报年份", example = "2", required = true)
    Integer year;

    @Comment("创建时间")
    @ApiModelProperty(value ="创建时间", example = "2", required = true)
    LocalDateTime createTime;

    

    @Builder.Default
    @Comment("权重")
    @ApiModelProperty(value ="权重", required = true)
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    Set<WeightSort> weightSorts = new HashSet<>();
}

关联权重WeightSort类(数据库名:bs_weight_sort):

代码语言:txt
AI代码解释
复制
package com.yiring.finance.domain.weightsort;

import com.yiring.finance.domain.user.User;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.hibernate.annotaions.Comment;

/**
 * 用户关联项目权重表
 *
 * @author zs
 * @date 2021/3/3 11:09
 */

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Comment("权重表")
@Table(name = "bs_weight_sort")
public class WeightSort implements Serializable {

    private static final long serialVersionUID = 1009267440536346667L;

    @Comment("主键")
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @ApiModelProperty(value ="主键", example = "2")
    Long id;

    @Comment("绑定用户")
    @ApiModelProperty(value ="绑定用户")
    @ManyToOne
    User user;

    @Comment("权重")
    @ApiModelProperty(value ="权重", example = "2")
    Long weight;
}

关联用户User表(数据库表名:SYSTEM_USER):

代码语言:txt
AI代码解释
复制
package com.yiring.finance.domain.user;

import com.yiring.finance.domain.dictionary.DictionaryType;
import com.yiring.finance.domain.permission.Permission;
import com.yiring.finance.domain.role.Role;
import com.yiring.finance.secruity.JwtUser;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.hibernate.annotaions.Comment;

/**
 * 用户
 *
 * @author zs
 * @date 2021/3/3 15:27
 */

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Comment("用户")
@Table(name = "SYSTEM_USER", indexes = {
        @Index(name = "IDX_USERNAME", columnList = "username", unique = true),
        @Index(name = "IDX_MOBILE", columnList = "mobile", unique = true),
        @Index(name = "IDX_EMAIL", columnList = "email", unique = true)
})
public class User implements Serializable {

    private static final long serialVersionUID = -5787847701210907511L;

    @Comment("主键")
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Comment("真实姓名")
    String realName;

    @Comment("用户名")
    @Column(unique = true)
    String username;

    @Comment("密码")
    String password;

    @Comment("手机号")
    @Column(unique = true)
    String mobile;

    @Comment("最后登录IP地址")
    String lastLoginIp;

    @Comment("激活时间")
    LocalDateTime activationTime;

    @Comment("权限更新时间")
    LocalDateTime authorityUpdateTime;

    @Comment("最后重置密码时间")
    LocalDateTime lastPasswordResetTime;

    @Comment("最后登录时间")
    LocalDateTime lastLoginTime;

    @Comment("最后更新信息时间")
    LocalDateTime lastUpdateTime;

    @Comment("创建时间")
    LocalDateTime createTime;

    /**
     * 验证码(非持久化)
     */
    @Transient
    String code;

    /**
     * token(非持久化)
     */
    @Transient
    String token;

}

后记:

主要还是卡在了不能创建临时表之后查询。大佬自己查询操作了一下构建CriteriaQuery这个类。但是还是不能解决这个问题。只能先记录一下,等待以后的解决。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
其中一些方法的理解应用可能比较浅显,希望大家不吝赐教,多多评论
其中一些方法的理解应用可能比较浅显,希望大家不吝赐教,多多评论
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
[Spring Boot] Spring Boot 多数据源动态切换[自定义注解&AOP]
[Spring Boot] Spring Boot 多数据源动态切换[自定义注解&AOP] @TOC 手机用户请横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。 平台 地址 CSDN https://blog.csdn.net/sinat_28690417 简书 https://www.jianshu.com/u/3032cc862300 个人博客 http://xiazhaoyang.tech/ 开发环境描述 ----------------
架构探险之道
2019/07/25
2.8K0
聊一聊 Spring Data JPA 中的那些日常实践
一直以来,团队在使用 ORM 框架上都是比较随意的,一开始是鼓励大家使用 mybatis,主要是期望团队同学可以自己写写 SQL,不至于写 SQL 手生;但是从实际工作中来看,我们并不会涉及到很多非常复杂的 SQL 语句,这就导致了大家会消耗相当部分的精力在写一些重复性并且没有什么技术难度的 SQL,对于基于数据库驱动的业务来说,当业务涉及到的表结构越多时,这种问题就越突出。于是我在项目的脚手架中就提供了 mybatis 和 jpa 两种访问数据库的方式,但是在随后的一段时间中发现,团队在使用 jpa 来操作数据库上的代码提交几乎为 0,而有相当部分的同学则是引入了 mybatis-plus。
磊叔的技术博客
2025/06/09
1450
聊一聊 Spring Data JPA 中的那些日常实践
Spring Data Jpa初体验(内含demo)
我一直在使用Mybatis作为持久化框架,并且觉得Mybatis十分的不错,足够灵活,虽说需要自己手写sql,但是这也是我觉得的一个优点,直观并且优化方便.
呼延十
2019/07/01
1K0
Spring Data Jpa初体验(内含demo)
SaaS-用户管理
用户其实就是saas企业访问的员工,对企业员工完成基本的CRUD操作 表结构如下:
cwl_java
2020/01/02
1K0
Spring学习笔记(三十一)——SpringBoot JPA优雅高效的工具:QueryHelp
有下面的一个问题: 如果需要一个接口,可以根据传进来的不确定的多个参数动态的,条件的查询数据,这个需要怎么处理呢? 其实这个问题在之前的做项目中也有遇到过,处理方法是使用MyBatis的配置语句动态进行拼接,有一种if-else的感觉,当时做这个需求还是挺麻烦的。
不愿意做鱼的小鲸鱼
2022/09/26
1.5K0
Spring学习笔记(三十一)——SpringBoot JPA优雅高效的工具:QueryHelp
带你搭一个SpringBoot+SpringData JPA的Demo
不知道大家对SpringBoot和Spring Data JPA了解多少,如果你已经学过Spring和Hibernate的话,那么SpringBoot和SpringData JPA可以分分钟上手的。SpringBoot和SpringData JPA的好处我就不说了,当时我学习的时候也粗略做过笔记,有兴趣的同学可以去看看
Java3y
2019/08/27
1.6K0
带你搭一个SpringBoot+SpringData JPA的Demo
Spring Data JPA 介绍和使用
Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便。但是Spring Data JPA框架功能更进一步,为我们做了 一个数据持久层框架几乎能做的任何事情。下面来逐步介绍它的强大功能。
乐百川
2022/05/05
3.9K0
Spring Data JPA 实现多表关联查询[通俗易懂]
多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询后的结果,这里介绍第二种方式。
全栈程序员站长
2022/06/29
5.9K0
自定义工作流设计
工作偶尔会遇到需要审批相关的系统,对于流程步骤相对固定的,一般会采取某些第三方的工作流来做对应的系统。目前唯一用过的就是activiti工作流。对它进行了简单的研究学习。参考以前入门的文章,发现它大概会生成二十多表,但是很多表基本没有使用。由于对于其源码没有进入深层次的研究,所以一旦遇到流程错乱就容易找不到问题。基于此,尝试写一个简单的关于自定义流程的设计,多一个备选方案。
用户5166330
2020/07/06
1.1K0
Spring Boot第八章-Spring Data JPA(续)
上一个博客介绍了Spring Data JPA,但是总感觉不够,因而加了此篇博客作为续,以后关于JPA的东西都写在这篇文章里,毕竟在实际运用中会遇到很多需要注意的地方。
全栈程序员站长
2021/05/19
1.6K0
Spring Boot 正确中使用JPA实战
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
后端码匠
2019/10/24
1.6K0
第1章 SAAS-HRM系统概述与搭建环境
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
用户1212940
2019/11/15
2.5K0
第1章 SAAS-HRM系统概述与搭建环境
Spring-Data-Jpa基础用法
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,其中就包括了Spring与EJB3.0的开发团队
leobhao
2022/06/28
8750
Spring-Data-Jpa基础用法
JPA/Hibernate问题汇总
报错很明显,是由于hibernate的懒加载引起的。项目使用的是SpringBoot框架,JPA默认使用的是hibernate的实现,而hibernate的懒加载机制其实就是延迟加载对象,如果没有在session关闭前使用到对象里除id以外的属性时,就只会返回一个没有初始化过的包含了id的代理类。很多时候,这个代理类会引发上述的异常。
雨临Lewis
2022/01/12
2.9K0
Spring JPA 自定义删改
​ 之前介绍的方法,基本都是只读方法,查询创建没有对数据库中存储的实体进行任何修改,但是对于更新和删除来说,如果继续保持只读属性,那么改删功能是难以完成的。通过使用@modify注释查询方法,您可以修改只需要参数绑定的查询,如下面的示例所示:
Kindear
2020/09/14
1.6K0
第十五节:SpringBoot使用JPA访问数据库
第十四节:SpringBoot使用JdbcTemplate访问操作数据库基本用法
入门笔记
2022/06/02
8750
第十五节:SpringBoot使用JPA访问数据库
[Spring Boot] spring-boot-starter-data-jpa
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,其中就包括了Spring与EJB3.0的开发团队。
架构探险之道
2019/07/25
1.3K0
Spring Boot 之 Spring Data JPA 二 ( Query By Example)1 新建Spring Boot工程2 新建实体3 新建Repository4 新建一Service
今天继续学习JPA,但是IDE工具变为了IntelliJ IDEA,其实多数我还是更喜欢Eclipse系列,但是Android Studio什么的,多Get一个技能也不是坏事。 1 新建Spring
孙亖
2018/06/07
1.3K0
第五章:使用QueryDSL与SpringDataJPA实现查询返回自定义对象
在我们实际项目开发中,往往会遇到一种多表关联查询并且仅需要返回多表内的几个字段最后组合成一个集合或者实体。这种情况在传统的查询中我们无法控制查询的字段,只能全部查询出后再做出分离,这种也是我们最不愿意看到的处理方式,这种方式会产生繁琐、复杂、效率低、代码阅读性差等等问题。QueryDSL为我们提供了一个返回自定义对象的工具类型,而Java8新特性Collection中stream方法也能够完成返回自定义对象的逻辑,下面我们就来看下这两种方式如何编写? 本章目标 基于SpringBoot平台完成SpringD
恒宇少年
2018/06/27
4.9K0
java进阶|JPA系列教程(一)单表操作
四,项目的处理器controller,主要用户接收前端传入的参数,这里基于postman测试工具进行测试。
码农王同学
2020/06/17
9400
相关推荐
[Spring Boot] Spring Boot 多数据源动态切换[自定义注解&AOP]
更多 >
交个朋友
加入HAI高性能应用服务器交流群
探索HAI应用新境界 共享实践心得
加入[游戏服务器] 腾讯云官方交流站
游戏服运维小技巧 常见问题齐排查
加入[数据] 腾讯云技术交流站
获取数据实战干货 共享技术经验心得
换一批
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档