spring-data-jpa的使用方式

本文介绍了Java Persistence API (JPA)及其在Spring Data JPA中的应用,包括基本查询、分页查询、自定义SQL查询等高级功能。同时探讨了实体关系映射、懒加载与急加载策略及主键生成机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

 JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。


Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。

实现接口直接操作实现对数据的访问和操作:

 

JpaRepository->PagingAndSortingRepository->CrudRepository->Repository

Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法 
与继承 Repository 等价的一种方式:@RepositoryDefinition 注解,并为其指定 domainClass 和 idClass 属性。 
public interface Repository< T, ID extends Serializable> { } 仅仅是一个标识,表明任何继承它的均为仓库接口类 
CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法 
PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法 
JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法 

基本查询

基本查询也分为两种,一种是spring data默认已经实现,一种是根据查询的方法来自动解析成SQL。

-预先生成方法

spring data jpa 默认预先生成了一些基本的CURD的方法,例如:增、删、改等等
1 继承JpaRepository
public interface UserRepository extends JpaRepository<User, Long> {
}
2 使用默认方法
@Test
public void testBaseQuery() throws Exception {
User user=new User();
userRepository.findAll();
userRepository.findOne(1l);
userRepository.save(user);
userRepository.delete(user);
userRepository.count();
userRepository.exists(1l);
// ...
}
就不解释了根据方法名就看出意思来

-自定义简单查询

自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是 findXXBy , readAXXBy , queryXXBy , countXXBy ,   getXXBy 后面跟属性名称:
User findByUserName(String userName);
也使用一些加一些关键字 And   Or
User findByUserNameOrEmail(String username, String email);
修改、删除、统计也是类似语法
Long deleteById(Long id);
Long countByUserName(String userName)
基本上SQL体系中的关键词都可以使用,例如: LIKE   IgnoreCase   OrderBy
List<User> findByEmailLike(String email);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);
具体的关键字,使用方法和生产成SQL如下表所示

 

Keyword
Sample
JPQL snippet
And
findByLastnameAndFirstname
… where x.lastname = ?1 and x.firstname = ?2
Or
findByLastnameOrFirstname
… where x.lastname = ?1 or x.firstname = ?2
Is,Equals
findByFirstnameIs,findByFirstnameEquals
… where x.firstname = ?1
Between
findByStartDateBetween
… where x.startDate between ?1 and ?2
LessThan
findByAgeLessThan
… where x.age < ?1
LessThanEqual
findByAgeLessThanEqual
… where x.age ⇐ ?1
GreaterThan
findByAgeGreaterThan
… where x.age > ?1
GreaterThanEqual
findByAgeGreaterThanEqual
… where x.age >= ?1
After
findByStartDateAfter
… where x.startDate > ?1
Before
findByStartDateBefore
… where x.startDate < ?1
IsNull
findByAgeIsNull
… where x.age is null
IsNotNull,NotNull
findByAge(Is)NotNull
… where x.age not null
Like
findByFirstnameLike
… where x.firstname like ?1
NotLike
findByFirstnameNotLike
… where x.firstname not like ?1
StartingWith
findByFirstnameStartingWith
… where x.firstname like ?1 (parameter bound with appended %)
EndingWith
findByFirstnameEndingWith
… where x.firstname like ?1 (parameter bound with prepended %)
Containing
findByFirstnameContaining
… where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy
findByAgeOrderByLastnameDesc
… where x.age = ?1 order by x.lastname desc
Not
findByLastnameNot
… where x.lastname <> ?1
In
findByAgeIn(Collection ages)
… where x.age in ?1
NotIn
findByAgeNotIn(Collection age)
… where x.age not in ?1
TRUE
findByActiveTrue()
… where x.active = true
FALSE
findByActiveFalse()
… where x.active = false
IgnoreCase
findByFirstnameIgnoreCase
… where UPPER(x.firstame) = UPPER(?1)

 

复杂查询

在实际的开发中我们需要用到分页、删选、连表等查询的时候就需要特殊的方法或者自定义SQL

-分页查询

分页查询在实际使用中非常普遍了,spring data jpa已经帮我们实现了分页的功能,在查询的方法中,需要传入参数 Pageable   ,当查询中有多个参数的时候 Pageable 建议做为最后一个参数传入
Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);
Pageable   是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则
public  Page<Course> findAllPageAndSort(){
//排序规则 升序or降序 按哪些字段排序
Sort sort= new  Sort(Sort.Direction. DESC , "id" );
//分页规则 第几页 每页数据多少条 怎样排序
Pageable pageable= new  PageRequest( 0 , 3 ,sort);
return  courseRepository .findAll(pageable);
}

-限制查询

有时候我们只需要查询前N个元素,或者支取前一个实体。
List<Course> findFirst3ByTeacherId(Integer teacherId,Sort sort);

-自定义SQL查询

其实Spring data 觉大部分的SQL都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的SQL来查询,spring data也是完美支持的;在SQL的查询方法上面使用 @Query 注解,如涉及到删除和修改在需要加上 @Modifying .也可以根据需要添加   @Transactional   对事物的支持,查询超时的设置等
@Modifying
@Query( "update User u set u.userName = ?1 where u. id  = ?2")
int modifyByIdAndUserId(String userName, Long id);
@Transactional
@Modifying
@Query( "delete from User where  id  = ?1")
void deleteByUserId(Long id);
@Transactional(timeout =  10)
@Query( "select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
@Query( "select u from User u where u.firstname like %?1" )
List<User> findByFirstnameEndsWith(String firstname);

-多表查询

多表查询在spring data jpa中两种实现方式
  • 利用hibernate的级联查询来实现(注解@OneToOne @OneToMany @ManyToOne @ManyToMany )
  • 自定义一个类来接收连表查询后的结果
-实体类Course
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType. IDENTITY)
private Integer  id;
private String  name;
private Integer  teacherId;
//...getter setter
}
-实体类Teacher
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType. IDENTITY)
private Integer  id;
private String  name;
//...getter  setter
}
-查询Course详细信息包括老师姓名 定义结果类
public class CourseDetailDTO  implements Serializable{
private static final Long  serialVersionUID= 1L;
private Integer  courseId;
private String  courseName;
private Integer  teacherId;
private String  teacherName;
public CourseDetailDTO(Integer courseId, String courseName, Integer teacherId, String teacherName) {
this. courseId = courseId;
this. courseName = courseName;
this. teacherId = teacherId;
this. teacherName = teacherName;
}
public CourseDetailDTO() {}
//...getter setter 
}
-查询的方法返回类型设置为自定义结果类
@Query(value =  "select new com.example.jpatest2.dto.CourseDetailDTO(c. id ,c. name ,t.id,t.name) from Course c,Teacher t where c. teacherId =t.id")
List<CourseDetailDTO> findAllInDetail()

注意:@Query(“HQL语句 ”)   @Query(“SQL语句”,nativeQuery=true)

           异常: 结果集没有序列化且忘记写getter/setter方法

"Could not write JSON: No serializer found for class com.example.jpatest2.dto.CourseDetailDTO and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.example.jpatest2.dto.CourseDetailDTO and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])"


补充

-spring.jpa.properties.hibernate.ddl-auto几种配置

  • create:每次加载Hibernate时都会删除上一次生成的表,然后重新生成新表,即使两次没有任何修改也会这样执行,这就导致每次启动都是一个新的数据库,也是导致数据丢失的重要原因。

  • create-drop:每次加载Hibernate时都会生成表,但当SessionFactory关闭时,所生成的表将自动删除。

  • update:最常用的属性值,第一次加载Hibernate时创建数据表(前提是需要先有数据库),以后加载HIbernate时只会根据model更新,即使model已经删除了某些属性,数据表也不会随之删除字段。

  • validate:每次加载Hibernate时都会验证数据表结构,只会和已经存在的数据表进行比较,根据model修改表结构,但不会创建新表。

-JPA通用策略生成器

通过annotation来映射hibernate实体的,基于annotation的hibernate主键标识为@Id, 其生成规则由@GeneratedValue设定的.
JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO.
  • TABLE:使用一个特定的数据库表格来保存主键。
  • SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
  • IDENTITY:主键由数据库自动生成(主要是自动增长型)
  • AUTO:主键由程序控制。 

-Lazy Loading

Advantages:
  • Initial load time much smaller than in the other approach
  • Less memory consumption than in the other approach
Disadvantages:
  • Delayed initialization might impact performance during unwanted moments
  • In some cases you need to handle lazily-initialized objects with a special care or you might end up with an exception

-Eager Loading:

Advantages:
  • No delayed initialization related performance impacts
Disadvantages:
  • Long initial loading time
  • Loading too much unnecessary data might impact performance
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值