经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
Spring-Data-Jpa使用总结
来源:cnblogs  作者:逸竹小站  时间:2019/10/17 10:38:34  对本文有异议

参考资源列表

  1. 官方文档:https://docs.spring.io/spring-data/jpa/docs/2.1.5.RELEASE/reference/html/
  2. 《Spring Data JPA入门到精通》

前言

JPAJava Persistence API的简称,是SpringHibernate的基础上进行的二次封装框架,为了更好更方便的融入Spring大家庭,同时也提供了一些Hibernate没有的特性,与其他ORM框架一起构成SpringData,统一封装了ORM层,使开发人员使用起来更加方便快捷。

备注:本文所有代码都是基于SpringBoot 2.1.5版本

JPA的使用

基本单表操作的使用

对于操作单表来说,jpa提供了非常方便使用的封装,我们只需要按规范编写Repository接口同时继承JpaRepository就可以享用jpa基本功能了。代码如下:

User实体:

  1. package com.yizhu.entity;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. import lombok.ToString;
  5. import javax.persistence.*;
  6. import java.io.Serializable;
  7. import java.util.List;
  8. import java.util.Set;
  9. @Entity
  10. @Table(name = "t_user")
  11. @Data
  12. @Builder
  13. public class User implements Serializable {
  14. private static final long serialVersionUID = 1L;
  15. @Id
  16. @GeneratedValue(strategy = GenerationType.IDENTITY)
  17. private Long id;
  18. private String name;
  19. private String password;
  20. private Integer age;
  21. private Integer sex;
  22. }

repository接口:

  1. package com.yizhu.repository;
  2. import com.yizhu.entity.User;
  3. public interface UserRepository extends JpaRepository<User, Long>{
  4. }

下面看看jpa为我们提供了哪些默认操作单表数据的方法

  1. package org.springframework.data.jpa.repository;
  2. @NoRepositoryBean
  3. public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
  4. List<T> findAll(); // 查询全表数据
  5. List<T> findAll(Sort var1); // 查询全表数据,支持排序
  6. List<T> findAllById(Iterable<ID> var1); // 根据id字段查询所有匹配数据
  7. <S extends T> List<S> saveAll(Iterable<S> var1); // 批量保存或更新数据
  8. void flush(); // 刷新本地缓存到数据库
  9. <S extends T> S saveAndFlush(S var1); // 保存或更新单挑数据及刷新本地缓存到数据库
  10. void deleteInBatch(Iterable<T> var1); // 批量删除数据
  11. void deleteAllInBatch(); // 批量删除全表数据
  12. T getOne(ID var1); // 根据id查询一条匹配数据
  13. <S extends T> List<S> findAll(Example<S> ar1); // Example方式的查询指定实体
  14. <S extends T> List<S> findAll(Example<S> var1, Sort var2); // Example方式的查询指定实体并排序
  15. }
  1. package org.springframework.data.repository;
  2. @NoRepositoryBean
  3. public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
  4. Iterable<T> findAll(Sort var1); // 根据排序查询全表,返回类型是任意集合
  5. Page<T> findAll(Pageable var1); // 根据分页参数分页查询
  6. }
  1. package org.springframework.data.repository;
  2. @NoRepositoryBean
  3. public interface CrudRepository<T, ID> extends Repository<T, ID> {
  4. <S extends T> S save(S var1); // 保存或更新单条数据
  5. <S extends T> Iterable<S> saveAll(Iterable<S> var1); // 批量保存或更新
  6. Optional<T> findById(ID var1); // 根据id查询数据,返回类型是Optional
  7. boolean existsById(ID var1); // 根据id判断数据是否存在
  8. Iterable<T> findAll(); // 查询全表数据,返回类型为集合
  9. Iterable<T> findAllById(Iterable<ID> var1); // 根据id集合查询数据
  10. long count(); // 统计全表数据量
  11. void deleteById(ID var1); // 根据id删除数据
  12. void delete(T var1); // 删除单条数据
  13. void deleteAll(Iterable<? extends T> var1); // 删除指定集合数据
  14. void deleteAll(); // 删除全表数据
  15. }
  1. package org.springframework.data.repository.query;
  2. public interface QueryByExampleExecutor<T> {
  3. <S extends T> Optional<S> findOne(Example<S> var1); // 根据Example查询一条
  4. <S extends T> Iterable<S> findAll(Example<S> var1); // 根据Example查询所有数据
  5. <S extends T> Iterable<S> findAll(Example<S> var1, Sort var2); // 根据Example查询所有数据,并排序
  6. <S extends T> Page<S> findAll(Example<S> var1, Pageable var2); // 根据Example分页查询
  7. <S extends T> long count(Example<S> var1); // 根据Example统计
  8. <S extends T> boolean exists(Example<S> var1); // 根据Example判断数据是否存在
  9. }

除此之外,jpa提供了一套新的生成sql的机制,非常方便好用,jpa根据Repository接口的方法中的关键字、实体字段及出入参,自动生成sql,这种方式启动容器的时候就可以检查语法是否正确,简单使用例子如下:

  1. package com.yizhu.repository;
  2. import com.yizhu .entity.User;
  3. import org.springframework.data.jpa.repository.EntityGraph;
  4. import org.springframework.data.jpa.repository.JpaRepository;
  5. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  6. import org.springframework.data.jpa.repository.Query;
  7. import org.springframework.data.repository.query.Param;
  8. import java.util.List;
  9. public interface UserRepository extends JpaRepository<User, Long>{
  10. /**
  11. * 根据年龄查询用户信息
  12. * @param age
  13. * @return
  14. */
  15. List<User> findAllByAge(Integer age);
  16. /**
  17. * 根据用户性别和所属组织名称查询用户信息
  18. * @param userSex
  19. * @param orgName
  20. * @return
  21. */
  22. List<User> findBySexAndOrg(@Param("sex") Integer sex, @Param("name") String name);
  23. /**
  24. * 根据用户名模糊查询
  25. * @return
  26. */
  27. List<User> findAllByNameLike(@Param("name") String name);
  28. }

除了findByAnd之外,还有一些关键词,全部定义在PartTreePart类,组装起来可以生成各种各样的sql,下面截取部分代码,感兴趣的同学可以打开源码去阅读

  1. package org.springframework.data.repository.query.parser;
  2. public class PartTree implements Streamable<PartTree.OrPart> {
  3. private static final String KEYWORD_TEMPLATE = "(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))";
  4. private static final String QUERY_PATTERN = "find|read|get|query|stream";
  5. private static final String COUNT_PATTERN = "count";
  6. private static final String EXISTS_PATTERN = "exists";
  7. private static final String DELETE_PATTERN = "delete|remove";
  8. private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get|query|stream|count|exists|delete|remove)((\\p{Lu}.*?))??By");
  9. private final PartTree.Subject subject;
  10. private final PartTree.Predicate predicate;
  11. ...
  12. private static String[] split(String text, String keyword) {
  13. Pattern pattern = Pattern.compile(String.format("(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))", keyword));
  14. return pattern.split(text);
  15. }
  16. private static class Predicate implements Streamable<PartTree.OrPart> {
  17. private static final Pattern ALL_IGNORE_CASE = Pattern.compile("AllIgnor(ing|e)Case");
  18. private static final String ORDER_BY = "OrderBy";
  19. private final List<PartTree.OrPart> nodes;
  20. private final OrderBySource orderBySource;
  21. private boolean alwaysIgnoreCase;
  22. public Predicate(String predicate, Class<?> domainClass) {
  23. String[] parts = PartTree.split(this.detectAndSetAllIgnoreCase(predicate), "OrderBy");
  24. if (parts.length > 2) {
  25. throw new IllegalArgumentException("OrderBy must not be used more than once in a method name!");
  26. } else {
  27. this.nodes = (List)Arrays.stream(PartTree.split(parts[0], "Or")).filter(StringUtils::hasText).map((part) -> {
  28. return new PartTree.OrPart(part, domainClass, this.alwaysIgnoreCase);
  29. }).collect(Collectors.toList());
  30. this.orderBySource = parts.length == 2 ? new OrderBySource(parts[1], Optional.of(domainClass)) : OrderBySource.EMPTY;
  31. }
  32. }
  33. ...
  34. }
  35. private static class Subject {
  36. private static final String DISTINCT = "Distinct";
  37. private static final Pattern COUNT_BY_TEMPLATE = Pattern.compile("^count(\\p{Lu}.*?)??By");
  38. private static final Pattern EXISTS_BY_TEMPLATE = Pattern.compile("^(exists)(\\p{Lu}.*?)??By");
  39. private static final Pattern DELETE_BY_TEMPLATE = Pattern.compile("^(delete|remove)(\\p{Lu}.*?)??By");
  40. private static final String LIMITING_QUERY_PATTERN = "(First|Top)(\\d*)?";
  41. private static final Pattern LIMITED_QUERY_TEMPLATE = Pattern.compile("^(find|read|get|query|stream)(Distinct)?(First|Top)(\\d*)?(\\p{Lu}.*?)??By");
  42. private final boolean distinct;
  43. private final boolean count;
  44. private final boolean exists;
  45. private final boolean delete;
  46. private final Optional<Integer> maxResults;
  47. public Subject(Optional<String> subject) {
  48. this.distinct = (Boolean)subject.map((it) -> {
  49. return it.contains("Distinct");
  50. }).orElse(false);
  51. this.count = this.matches(subject, COUNT_BY_TEMPLATE);
  52. this.exists = this.matches(subject, EXISTS_BY_TEMPLATE);
  53. this.delete = this.matches(subject, DELETE_BY_TEMPLATE);
  54. this.maxResults = this.returnMaxResultsIfFirstKSubjectOrNull(subject);
  55. }
  56. private Optional<Integer> returnMaxResultsIfFirstKSubjectOrNull(Optional<String> subject) {
  57. return subject.map((it) -> {
  58. Matcher grp = LIMITED_QUERY_TEMPLATE.matcher(it);
  59. return !grp.find() ? null : StringUtils.hasText(grp.group(4)) ? Integer.valueOf(grp.group(4)) : 1;
  60. });
  61. }
  62. ...
  63. private boolean matches(Optional<String> subject, Pattern pattern) {
  64. return (Boolean)subject.map((it) -> {
  65. return pattern.matcher(it).find();
  66. }).orElse(false);
  67. }
  68. }
  69. }
  1. package org.springframework.data.repository.query.parser;
  2. public class Part {
  3. private static final Pattern IGNORE_CASE = Pattern.compile("Ignor(ing|e)Case");
  4. private final PropertyPath propertyPath;
  5. private final Part.Type type;
  6. private Part.IgnoreCaseType ignoreCase;
  7. ...
  8. public static enum Type {
  9. BETWEEN(2, new String[]{"IsBetween", "Between"}),
  10. IS_NOT_NULL(0, new String[]{"IsNotNull", "NotNull"}),
  11. IS_NULL(0, new String[]{"IsNull", "Null"}),
  12. LESS_THAN(new String[]{"IsLessThan", "LessThan"}),
  13. LESS_THAN_EQUAL(new String[]{"IsLessThanEqual", "LessThanEqual"}),
  14. GREATER_THAN(new String[]{"IsGreaterThan", "GreaterThan"}),
  15. GREATER_THAN_EQUAL(new String[]{"IsGreaterThanEqual", "GreaterThanEqual"}),
  16. BEFORE(new String[]{"IsBefore", "Before"}),
  17. AFTER(new String[]{"IsAfter", "After"}),
  18. NOT_LIKE(new String[]{"IsNotLike", "NotLike"}),
  19. LIKE(new String[]{"IsLike", "Like"}),
  20. STARTING_WITH(new String[]{"IsStartingWith", "StartingWith", "StartsWith"}),
  21. ENDING_WITH(new String[]{"IsEndingWith", "EndingWith", "EndsWith"}),
  22. IS_NOT_EMPTY(0, new String[]{"IsNotEmpty", "NotEmpty"}),
  23. IS_EMPTY(0, new String[]{"IsEmpty", "Empty"}),
  24. NOT_CONTAINING(new String[]{"IsNotContaining", "NotContaining", "NotContains"}),
  25. CONTAINING(new String[]{"IsContaining", "Containing", "Contains"}),
  26. NOT_IN(new String[]{"IsNotIn", "NotIn"}),
  27. IN(new String[]{"IsIn", "In"}),
  28. NEAR(new String[]{"IsNear", "Near"}),
  29. WITHIN(new String[]{"IsWithin", "Within"}),
  30. REGEX(new String[]{"MatchesRegex", "Matches", "Regex"}),
  31. EXISTS(0, new String[]{"Exists"}),
  32. TRUE(0, new String[]{"IsTrue", "True"}),
  33. FALSE(0, new String[]{"IsFalse", "False"}),
  34. NEGATING_SIMPLE_PROPERTY(new String[]{"IsNot", "Not"}),
  35. SIMPLE_PROPERTY(new String[]{"Is", "Equals"});
  36. private static final List<Part.Type> ALL = Arrays.asList(IS_NOT_NULL, IS_NULL, BETWEEN, LESS_THAN, LESS_THAN_EQUAL, GREATER_THAN, GREATER_THAN_EQUAL, BEFORE, AFTER, NOT_LIKE, LIKE, STARTING_WITH, ENDING_WITH, IS_NOT_EMPTY, IS_EMPTY, NOT_CONTAINING, CONTAINING, NOT_IN, IN, NEAR, WITHIN, REGEX, EXISTS, TRUE, FALSE, NEGATING_SIMPLE_PROPERTY, SIMPLE_PROPERTY);
  37. public static final Collection<String> ALL_KEYWORDS;
  38. private final List<String> keywords;
  39. private final int numberOfArguments;
  40. ...
  41. static {
  42. List<String> allKeywords = new ArrayList();
  43. Iterator var1 = ALL.iterator();
  44. while(var1.hasNext()) {
  45. Part.Type type = (Part.Type)var1.next();
  46. allKeywords.addAll(type.keywords);
  47. }
  48. ALL_KEYWORDS = Collections.unmodifiableList(allKeywords);
  49. }
  50. }
  51. }

可以看到单表操作的大部分需求jpa都为我们提供了现成的实现,但也支持我们使用@Query注解自定义查询sql,方便有sql基础的同学使用,sql可控性强。

  1. package com.yizhu.repository;
  2. import com.yizhu .entity.User;
  3. import org.springframework.data.jpa.repository.EntityGraph;
  4. import org.springframework.data.jpa.repository.JpaRepository;
  5. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  6. import org.springframework.data.jpa.repository.Query;
  7. import org.springframework.data.repository.query.Param;
  8. import java.util.List;
  9. public interface UserRepository extends JpaRepository<User, Long>{
  10. /**
  11. * 查询所有用户信息
  12. * @return
  13. */
  14. @Query(value = "from User u")
  15. List<User> findAll();
  16. /**
  17. * 根据年龄查询用户信息
  18. * @param age
  19. * @return
  20. */
  21. @Query(value = "select * from t_user u where u.user_age = ?1", nativeQuery = true)
  22. List<User> findAllByAge(Integer age);
  23. /**
  24. * 根据用户性别和所属组织名称查询用户信息
  25. * @param userSex
  26. * @param orgName
  27. * @return
  28. */
  29. @Query(value = "select u from User u left join u.org o where u.userSex = :userSex and o.orgName = :orgName")
  30. List<User> findUsersBySexAndOrg(@Param("userSex") Integer userSex, @Param("orgName") String orgName);
  31. }

多表关联

@OneToOne@OneToMany@ManyToOne@ManyToMany

  1. @Entity
  2. @Table(name = "t_user")
  3. @NamedEntityGraph(name = "User.findUsers", attributeNodes = {@NamedAttributeNode("jobs"), @NamedAttributeNode("roles")})
  4. @Data
  5. @Builder
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class User implements Serializable {
  9. private static final long serialVersionUID = 1L;
  10. @ApiModelProperty(hidden = true)
  11. @Id
  12. @GeneratedValue(strategy = GenerationType.IDENTITY)
  13. private Long id;
  14. @ApiModelProperty(value = "用户名")
  15. @Column(name = "user_name")
  16. private String name;
  17. @ApiModelProperty(value = "用户密码")
  18. @Column(name = "user_password")
  19. private String password;
  20. @ApiModelProperty(value = "用户年龄")
  21. @Column(name = "user_age")
  22. private Integer age;
  23. @ApiModelProperty(value = "用户性别")
  24. @Column(name = "user_sex")
  25. private Integer sex;
  26. @ApiModelProperty(value = "所属组织id")
  27. @Column(name = "org_id")
  28. private Long orgId;
  29. @ApiModelProperty(value = "用户信息")
  30. @OneToOne
  31. @JoinColumn(name = "id", updatable = false, insertable = false)
  32. private UserInfo userInfo;
  33. @ApiModelProperty(value = "用户所属组织")
  34. @ManyToOne
  35. @JoinColumn(name = "org_id", updatable = false, insertable = false)
  36. private Organization org;
  37. @ApiModelProperty(value = "用户角色")
  38. @OneToMany
  39. @JoinColumn(name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
  40. @NotFound(action = NotFoundAction.IGNORE)
  41. private Set<Role> roles;
  42. @ApiModelProperty(value = "用户工作")
  43. @ManyToMany
  44. @JoinTable(
  45. name = "t_user_job",
  46. joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
  47. inverseJoinColumns = @JoinColumn(name = "job_id", referencedColumnName = "id")
  48. )
  49. @NotFound(action = NotFoundAction.IGNORE)
  50. private Set<Job> jobs;

private Set<Role> roles;private Set<Job> jobs;不能用同时使用List集合代替,会报错org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.yizhu.entity.User.jobs, com.yizhu.entity.User.roles]

动态查询

  1. package com.yizhu.repository;
  2. import com.yizhu.dto.UserQueryDto;
  3. import com.yizhu.entity.Organization;
  4. import com.yizhu.entity.User;
  5. import org.springframework.data.jpa.domain.Specification;
  6. import javax.persistence.criteria.Join;
  7. import javax.persistence.criteria.JoinType;
  8. import javax.persistence.criteria.Predicate;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.Optional;
  12. public class UserSpecs {
  13. public static Specification<User> listQuerySpec(UserQueryDto userQueryDto){
  14. return (root, query, builder) -> {
  15. List<Predicate> predicates = new ArrayList<>();
  16. Optional.ofNullable(userQueryDto.getId()).ifPresent(i -> predicates.add(builder.equal(root.get("id"), i)));
  17. Optional.ofNullable(userQueryDto.getName()).ifPresent(n -> predicates.add(builder.equal(root.get("name"), n)));
  18. Optional.ofNullable(userQueryDto.getAge()).ifPresent(a -> predicates.add(builder.equal(root.get("age"), a)));
  19. Optional.ofNullable(userQueryDto.getOrgId()).ifPresent(oi -> predicates.add(builder.equal(root.get("orgId"), oi)));
  20. Optional.ofNullable(userQueryDto.getOrgName()).ifPresent(on -> {
  21. Join<User, Organization> userJoin = root.join(root.getModel().getSingularAttribute("org", Organization.class), JoinType.LEFT);
  22. predicates.add(builder.equal(userJoin.get("orgName"), on));
  23. });
  24. return builder.and(predicates.toArray(new Predicate[predicates.size()]));
  25. };
  26. }
  27. }
  1. package com.yizhu.service;
  2. import com.yizhu.dto.UserQueryDto;
  3. import com.yizhu.entity.User;
  4. import com.yizhu.repository.UserRepository;
  5. import com.yizhu.repository.UserSpecs;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Service;
  8. import java.util.List;
  9. @Service
  10. public class UserService {
  11. @Autowired
  12. private UserRepository userRepository;
  13. public List<User> findUsersDynamic(UserQueryDto userQueryDto){
  14. return userRepository.findAll(UserSpecs.listQuerySpec(userQueryDto));
  15. }
  16. }

审计功能使用

在启动类添加@EnableJpaAuditing注解表示开启jpa审计功能

  1. package com.yizhu;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
  5. @EnableJpaAuditing
  6. @SpringBootApplication
  7. public class DemoApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(DemoApplication.class, args);
  10. }
  11. }

在需要使用审计功能的实体类添加@EntityListeners(AuditingEntityListener.class)注解

  1. package com.yizhu.entity;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. import org.springframework.data.jpa.domain.support.AuditingEntityListener;
  5. import javax.persistence.*;
  6. import java.io.Serializable;
  7. import java.util.Date;
  8. @Entity
  9. @Table(name = "t_role")
  10. @Data
  11. @Builder
  12. @EntityListeners(AuditingEntityListener.class)
  13. public class Role implements Serializable {
  14. private static final long serialVersionUID=1L;
  15. @ApiModelProperty(hidden = true)
  16. @Id
  17. @GeneratedValue(strategy = GenerationType.AUTO)
  18. private Long id;
  19. private String roleName;
  20. @CreatedDate
  21. private Date createTime;
  22. @CreatedBy
  23. private Long createId;
  24. @LastModifiedDate
  25. private Date updateTime;
  26. @LastModifiedBy
  27. private Long updateId;
  28. }

实现AuditorAware接口,告诉容器当前登录人id

  1. package com.yizhu.configuration;
  2. import org.springframework.data.domain.AuditorAware;
  3. import org.springframework.web.context.request.RequestContextHolder;
  4. import org.springframework.web.context.request.ServletRequestAttributes;
  5. import java.util.Optional;
  6. public class UserAuditorAwareImpl implements AuditorAware<Long> {
  7. @Override
  8. public Optional<Long> getCurrentAuditor() {
  9. // 从session中获取登录人id
  10. ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  11. Long userId = (Long)servletRequestAttributes.getRequest().getSession().getAttribute("userId");
  12. return Optional.of(userId);
  13. }
  14. }

ok,然后jpa就会根据IDVersion判断当前操作是更新还是新增数据,新增时会注入当前登录人id到标有@CreateBy注解的字段上,当前时间注入到标有@CreateTime注解字段上;更新时则注入到@LastModifiedBy@LastModifiedDate对应的字段上。想详细了解的可查看org.springframework.data.jpa.domain.support.AuditingEntityListener源码。

常见的坑

  • N+1问题,当使用@ManyToMany@ManyToOne@OneToMany@OneToOne关联
    关系的时候,FetchType怎么配置LAZY或者EAGER。SQL真正执行的时
    候是由一条主表查询和N条子表查询组成的。这种查询效率一般比较
    低下,比如子对象有N个就会执行N+1条SQL。使用JPA 2.1推出来的@EntityGraph、@NamedEntityGraph可以解决该问题。如下。
  1. @ApiModel
  2. @Entity
  3. @Table(name = "t_user")
  4. @NamedEntityGraph(name = "User.findUsers", attributeNodes = {@NamedAttributeNode("jobs"), @NamedAttributeNode("roles")})
  5. @Data
  6. @Builder
  7. @NoArgsConstructor
  8. @AllArgsConstructor
  9. public class User implements Serializable {
  10. private static final long serialVersionUID = 1L;
  11. @ApiModelProperty(hidden = true)
  12. @Id
  13. @GeneratedValue(strategy = GenerationType.IDENTITY)
  14. private Long id;
  15. // 省略其他属性
  16. }
  1. package com.yizhu.repository;
  2. import com.yizhu.entity.User;
  3. import org.springframework.data.jpa.repository.EntityGraph;
  4. import org.springframework.data.jpa.repository.JpaRepository;
  5. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  6. import org.springframework.data.jpa.repository.Query;
  7. import org.springframework.data.repository.query.Param;
  8. import java.util.List;
  9. public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
  10. /**
  11. * 根据id查询用户信息
  12. * @param id
  13. * @return
  14. */
  15. @EntityGraph(value = "User.findUsers", type = EntityGraph.EntityGraphType.FETCH)
  16. User findAllById(Long id);
  17. /**
  18. * 根据name查询用户信息
  19. * @param name
  20. * @return
  21. */
  22. @EntityGraph(value = "User.findUsers", type = EntityGraph.EntityGraphType.FETCH)
  23. @Query(value = "select * from t_user where user_name = :name", nativeQuery = true)
  24. List<User> findAllByUserName(@Param("name") String name);
  25. }
  • 所有的注解要么全配置在字段上,要么全配置在get方法上,不能混用,混用就会启动不起来,但是语法配置没有问题。
  • 所有的关联都是支持单向关联和双向关联的,视具体业务场景而定。JSON序列化的时候使用双向注解会产生死循环,需要人为手动转化一次,或者使用@JsonIgnore。
  • 在所有的关联查询中,表一般是不需要建立外键索引的。@mappedBy的使用需要注意。
  • 级联删除比较危险,建议考虑清楚,或者完全掌握。
  • 不同的关联关系的配置,@JoinClumn里面的name、referencedColumnName代表的意思是不一样的,很容易弄混,可以根据打印出来的SQL做调整。
  • 当配置这些关联关系的时候建议大家直接在表上面,把外键建好,然后通过后面我们介绍的开发工具直接生成,这样可以减少自己调试的时间。

JPA常用注解

摘自《Spring Data JPA从入门到精通》

1554619508054

1554619555135

1554619583326

1554619600777

1554619615592

1554619631450

1554620031094

1554620213902

1554620262086

原文链接:http://www.cnblogs.com/coder2017/p/11690051.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号