Spring Data JPA基础学习

SpringDataJPA是Spring对JPA的封装,提供统一接口,通过方法名自动生成SQL,简化数据库访问。只需实现JpaRepository和JpaSpecificationExecutor接口,即可进行CRUD操作。配置包括数据库、EntityManagerFactory、事务管理器等。使用@Query和@Modifying注解支持JPQL和原生SQL查询,同时支持方法命名规则查询,实现动态构建查询语句。

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

上次有写到JPA的相关知识,接下来说一下Spring Data JPA

Spring Data JPA 是Spring基于ORM框架、JPA规范封装的一套JPA应用框架,开发者可以使用很简单的代码就进行数据库的访问与操作。

在日常使用中Spring Data JPA 开发让我们解脱了DAO层的操作,基本所有的CRUD都可以进行使用它实现;它的简单方式在于我们在书写代码时候只需要在Dao层实现两个接口就可以了,JPA框架已经给我封装好了方法直接使用。

Spring Data JPA的特点:

  • 提供了统一的接口,我们不会重复的sql
  • 我们可以通过方法名进行自动生成sql语句
  • 通过接口自动注入实现类,实现非常简单
  • 遵循数据库规范同时很灵活的访问数据库

了解了Spring Data JPA 和JPA还有Hibernate但是之间有什么关系:

我们前面说过JPA是一套规范,是由接口和抽象类进行完成的,而Hibernate是一款成熟的ORM框架,而且实现了JPA规范,使用JPA的API进行编程,就是意味着我们站在更改一层进行处理问题,直接通过接口进行处理面向接口编程;而Spring Data JPA 是对JPA进行了更高一步的封装,是在JPA规范下专门对数据持久化的解决方法。

在这里插入图片描述

使用Spring Data JPA就需要搭建它的环境,需要整合Spring和Spring Data JPA,并且还需要实现方式Hibernate的依赖,并且数据库驱动。

环境配置

我们需要配置的东西都有如下

  1. 操作数据库:配置数据库信息是必要的 DataSource
  2. 在JPA时候有操作JPA的EntityManagerFactory,所以需要实体管理工厂对象 EntityManagerFactory
    1. 扫描的包、数据库、JPA的实现方式、JPA实现方式适配器
  3. 事务的配置就是使用JPA的事务管理器 JpaTransactionManager
  4. Spring需要扫描实体对象扫描包 context Component-Scan
  5. Spring的事务:声明式或者编程式 tx
  6. 最后需要将配置的整合进去Spring Data JPA里 jpa:repositories
<!--数据库配置-->
<bean id="ds" class="xxxDataSource">
  <property name="url" value=""></property>
  <property name="Driver" value=""></property>
  <property name="username" value=""></property>
  <property name="password" value=""></property>
</bean>



<!--EntityManagerFactory配置-->
<bean id="MyEntitiManagerFactory" class="xxx.LocalContainerEntityManagerFactoryBean">
 	<!--数据库-->
  <proerty name="dataSource" ref="ds"></proerty>
  
  <!--扫描的包-->
  <proerty name="PageToScan" value="xxx.xxx.model"></proerty>
  
  <!--JPA的实现方式-->
  <proerty name="persistenceProvicer">
  	<bean class="xxx.HibernatePersistenceProvider"></bean>
  </proerty>
  <!--实现方式的适配器-->
  <proerty name="jpaVendorAdapter">
    <bean class="xxx.HibernateJpaVendorAdapter">
      	<!--是否创建表-->
    		<property name="GenerateDdl" value=""></property>
        <!--使用的数据库配置-->
        <property name="database" value=""></property>
        <!--数据库方言-->
        <property name="databasePlatform" value="MySQLDialect"></property>
        <!--是否显示sql语句-->
      	<property name="showSql" value=""></property>
    </bean>
  </proerty>
  
  <!--JPA的高级特性  支持Hibernate的-->
  <property name="jpaDialect">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
  </property>
</bean>


<!--JPa的事务管理器-->
<bean id="JpaTranscationManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="MyEntitiManagerFactory"></property>
</bean>

<!--Spring注解扫描的包-->
<context:component-scan base-package="xxxx"></context:component-scan>

<!--Spring事务-->

<!--整合Spring Data JPa-->
<jpa:repositories base-package="xxx" tansaction-manager-ref="JpaTranscationManager" entity-manager-factory-ref="MyEntitiManagerFactory"></jpa:repositories>

实现方数据库的value 大写

在这里插入图片描述

我觉得其实配置能看懂就行,也没必要全背过,

下面来看看Spring Data JPA是怎么样解脱我们的Dao层的

使用Spring Data JPA 只需要编写符合规范的接口就可以,有两点要求

  1. 创建一个Dao接口,并实现JpaRepository接口和JpaSpecificationExecutor接口
  2. 提供相应的泛型
/**
 * Spring Data JPA 书写Dao层的规范
 *      继承两个接口
 *             JpaRepository:封装了基本的CRUD操作
 *                  实体类
 *                  对应主键的类型
 *             JpaSpecificationExecutor:封装了复杂操作(分页查询等等)
 *                  实体类
 */
public interface StudentDao extends JpaRepository<Student,Long>, JpaSpecificationExecutor<Student>{
  
}

然后直接从容器获取bean对象就可以进行操作

在这里插入图片描述

可以看到我们没有写任何方法,就已经有封装好的基本方法

接下来看一下为什么能够这么方便,其实就是我们实现的两个接口里面的方法,追溯到顶层接口CrudRepository在这里插入图片描述

JpaSpecificationExecutor在这里插入图片描述
已经封装了方法

Spring Data JPA的运行过程剖析
在这里插入图片描述

发现此时注入的bean对象是一个代理对象,本质是通过JDKDynamicAopProxy生成的代理对象

我们进入此对象看看:

在这里插入图片描述

主要是这个invoke方法,当前这个targetSource是一个SimpleJpaRepository对象,

在这里插入图片描述

进入方法实际就是调用em.find方法

在这里插入图片描述

而em就是EntityManager实体管理器

所以我们得到结论Spring Data JPA只是对标准JPA操作进行了进一步封装,简化了Dao层代码的开发

在这里插入图片描述

Spring Data JPA的CRUD基本和JPA的相同

  • save方法是保存或者更新方法,判断依据就是是否存在id
    有id:更新操作,先查询后更新
    没有id:保存操作在这里插入图片描述

  • getOne使用JPA的getReference方法
    findOne使用JAP的findOne方法

  • delete查询到了再进行删除在这里插入图片描述

来看一下Spring Data JPA的JPQL查询语言

搭配使用@Query注解

在这里插入图片描述

  • value就是:JPQL语句

  • nativeQuery:是否使用本地sql查询 默认false 就是使用JPQL; true是使用sql语句查询

举个例子:

//还是使用对象而不是数据库表
@Query(value = "from Student where stutName = ? ")
public Student findByName(String name);
//多占位符设置    ?1代表参数的占位符,其中1对应方法中的参数索引
//   要么就是顺序写,要么就是根据占位符数组匹配
@Query(value="from Student where stuName = ?2 and stuAge = ?1")
public Student findByNameAndAge(Integer age,String name);

如果需要更新操作的话,还得搭配注解@Modifying

@Query(value = "update Student set stuId = ?2 where stuName = ?1")
@Modifying
public void updateById(String name,Long id);

并且在测试类需要添加事务的注解@Transaction和@Rollback(false)

SpringDataJPA 执行jqpl语句执行更新或者删除之后默认事务进行回滚,需要加上@Rollback(value=false)

输入想要使用sql查询,需要@query注解(value=“sql”,nativeQuery=true)

除此之外Spring Data JPA还有一个可以进行自定义查询方式:方法命名规则查询。顾名思义就是根据方法名字进行对应的查询,按照规则进行书写方法名称,就可以执行查询语句。

查询方法以findBy开头涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。

例如:

public Student findByStuName(String stuName);//根据stuName进行查询
public Student findByStuNameLike(String stuName);//模糊查询
public Student findByStuNameLikeAndStuClassAndStuAge(String stuName,String stuClass,String stuAge);//多条件查询

具体的关键字,使用方法和生产成SQL如下表所示

*Keyword**Sample**JPQL*
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection age)… where x.age not in ?1
TRUEfindByActiveTrue()… where x.active = true
FALSEfindByActiveFalse()… where x.active = false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值