学习笔记_Jpa

摘要:
SpringDataJpa原始链接JPA是Java持久化API的缩写,中文称为Java持久化层API。它是一个JDK5.0注释或XML描述对象关系表映射关系,它将在运行时将实体对象持久化到数据库。Sun引入新的JPAORM规范有两个原因:第一,简化现有的JavaEE和JavaSE应用程序开发;第二,Sun希望整合ORM技术,实现世界的统一。1.Jpa查询1.1,JpaRepository配置文件
SpringDataJpa

原文链接

JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

1、Jpa查询

1.1、 JpaRepository简单查询

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

预先生成方法

spring data jpa 默认预先生成了一些基本的CURD的方法,例如:增、删、改等等继承JpaRepository

public interface UserRepository extends JpaRepository<User, Integer>{}

使用默认方法

@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,readXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称:
  • 具体的关键字,使用方法和生产成SQL如下表所示

image-20210329103039223

image-20210329103112864

按照Spring Data的规范,查询方法以find|read|get 开头,涉及查询条件时,条件的属性用条件关键字连接
要注意的是:条件属性以首字母大写

示例:

例如:定义一个Entity实体类:

class People{
       private String firstName;
       private String lastName;
}

以上使用and条件查询时,应这样写:

findByLastNameAndFirstName(String lastName, String firstName);

注意:条件的属性名称与个数要与参数的位置与个数一一对应

1.2、JpaRepository查询方法解析流程

1.2.1、JPA方法名解析流程

Spring Data JPA框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。

假如创建如下的查询:findByUserDepUuid(),框架在解析该方法时,首先剔除findBy,然后对剩下的属性进行解析,假设查询实体为Doc:

  1. 先判断userDepUuid (根据POJO(Plain Ordinary Java Object :简单java对象,实际就是普通java bean)规范,首字母变为小写。)是否是查询实体的一个属性,如果是则根据该属性进行查询;如果没有该属性,继续第二步。
  2. 从右往左截取第一个大写字母开头的字符串(此处为Uuid),然后检查剩下的字符串是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user为查询实体的一个属性。
  3. 接着处理剩下部分(DepUuid),先判断 user 所对应的类型是否有depUuid属性,如果有,则表示该方法最终是根据 “ Doc.user.depUuid” 的取值进行查询;否则继续按照步骤 2 的规则从右往左截取,最终表示根据 “Doc.user.dep.uuid” 的值进行查询。
  4. 可能会存在一种特殊情况,比如 Doc包含一个 user 的属性,也有一个 userDep 属性,此时会存在混淆。可以明确在属性之间加上 "_" 以显式表达意图,比如 "findByUser_DepUuid()" 或者 "findByUserDep_uuid()"。

1.2.2、特殊的参数(分页或排序):

还可以直接在方法的参数上加入分页或排序的参数,比如(注意Spring Boot2.x.x后Pageable和Sort均为私有属性,不支持实例化):

Page<UserModel> findByName(String name, Pageable.of(...));
List<UserModel> findByName(String name, Sort.by(...));

Pageable 是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则

@Test
public void testPageQuery() throws Exception {
    int page=1,size=10;
   
    // 根据给定的页码和页面大小,按照主键降序的规则查询结果
    userRepository.findALL(
        PageRequest.of(start, size, 
                       Sort.by(Direction.DESC, "id")));
    userRepository.findByUserName("testName",  PageRequest.of(start, size, 
                       Sort.by(Direction.DESC, "id")));
}

1.2.3、使用JPA的NamedQueries

方法如下:

  1. 在实体类上使用@NamedQuery,示例如下:

    @NamedQuery(name = "UserModel.findByAge", query = "select o from UserModel o where o.age >= ?1")
    
  2. 在自己实现的DAO的Repository接口里面定义一个同名的方法,示例如下:

    public List<UserModel> findByAge(int age);
    
  3. 然后就可以使用了,Spring会先找是否有同名的NamedQuery,如果有,那么就不会按照接口定义的方法来解析。

1.2.4、使用@Query来指定本地查询

只要设置nativeQuery为true

比如:

@Query(value="select * from tbl_user where name like %?1", nativeQuery=true)
public List<UserModel> findByUuidOrAge(String name);

注意:当前版本的本地查询不支持翻页和动态的排序

1.2.5、使用命名化参数

使用@Param即可

比如:

@Query(value="select o from UserModel o where o.name like %:nn")
public List<UserModel> findByUuidOrAge(@Param("nn") String name);

1.2.6、创建查询的顺序

Spring Data JPA 在为接口创建代理对象时,如果发现同时存在多种上述情况可用,它该优先采用哪种策略呢?

jpa:repositories 提供了query-lookup-strategy 属性,用以指定查找的顺序。它有如下三个取值:

  1. create-if-not-found:

    如果方法通过@Query指定了查询语句,则使用该语句实现查询;

    如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;

    如果两者都没有找到,则通过解析方法名字来创建查询。

    这是querylookup-strategy 属性的默认值

  2. create:通过解析方法名字来创建查询。即使有符合的命名查询,或者方法通过@Query指定的查询语句,都将会被忽略

  3. use-declared-query:

    如果方法通过@Query指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则抛出异常

1.3、JpaRepository限制查询

有时候我们只需要查询前N个元素,或者只取前一个实体。

User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);

1.4、JpaRepository多表查询

多表查询在spring data jpa中有两种实现方式:

  1. 第一种是利用hibernate的级联查询来实现;
  2. 第二种是创建一个结果集的接口来接收连表查询后的结果,

这里主要第二种方式。

  • 首先需要定义一个结果集的接口类。
public interface HotelSummary {
    ...
    City getCity();
    String getName();
    Double getAverageRating();
    default Integer getAverageRatingRounded() {
        return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
    }
}
  • 查询的方法返回类型设置为新创建的接口
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
        + "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
 
@Query("select h.name as name, avg(r.rating) as averageRating "
        + "from Hotel h left outer join h.reviews r  group by h")
Page<HotelSummary> findByCity(Pageable pageable);
  • 使用
Page<HotelSummary> hotels = this.hotelRepository.findByCity(PageRequest.of(0, 10,
                                                                        Sort.by(Direction.ASC, "name")));
for(HotelSummary summay:hotels){
        System.out.println("Name" +summay.getName());
    }

在运行中Spring会给接口(HotelSummary)自动生产一个代理类来接收返回的结果,代码汇总使用getXX的形式来获取

2、JPA更新

2.1、支持更新类的Query语句

添加@Modifying即可

比如:

@Modifying
@Query(value="update UserModel o set o.name=:newName where o.name like %:nn")
public int findByUuidOrAge(@Param("nn") String name, @Param("newName") String newName);

注意:

  1. 方法的返回值应该是int,表示更新语句所影响的行数
  2. 在调用的地方必须加事务,没有事务不能正常执行

3、JPA删除

3.1、SQL方式-删除

@Modifying
@Query(value = "delete from r_upa where user_id= ?1 and point_indecs_id in (?2)", nativeQuery = true)
void deleteByUserAndPointIndecs(Long uid, List<Long> hids);

注意:

执行delete和update语句一样,需要添加@Modifying注解,使用时在Repository或者更上层需要@Transactional注解。

3.2、函数(delete)方式-删除

  • 直接可以使用delete(id),依据id来删除一条数据
  • 也可以使用deleteByName(String name),在使用该方法时,需要添加@Transactional注解,才能使用
  • Spring Data JPA的deleteByXXXX,是先select,在整个Transaction完了之后才执行delete

img

JpaRepository

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    
    /**
	 * Deletes the given entities in a batch which means it will create a single {@link Query}. Assume that we will clear
	 * the {@link javax.persistence.EntityManager} after the call.
	 *
	 * @param entities
     * 批量解绑多个,优势:只会形成一个SQL语句
	 */
	void deleteInBatch(Iterable<T> entities);
 
	/**
	 * Deletes all entities in a batch call.
	 */
	void deleteAllInBatch();
 
   
}

CrudRepository

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
   
    /**
	 * Deletes the entity with the given id.
	 *
	 * @param id must not be {@literal null}.
	 * @throws IllegalArgumentException in case the given {@code id} is {@literal null}
	 */
	void deleteById(ID id);
 
	/**
	 * Deletes a given entity.
	 *
	 * @param entity
	 * @throws IllegalArgumentException in case the given entity is {@literal null}.
	 */
	void delete(T entity);
 
	/**
	 * Deletes the given entities.
	 *
	 * @param entities
	 * @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
	 */
	void deleteAll(Iterable<? extends T> entities);
 
	/**
	 * Deletes all entities managed by the repository.
	 */
	void deleteAll();
}

4、JPA添加

利用JpaRepository和CrudRepository中的 save操作

JpaRepository

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {	
	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
	 */
	<S extends T> List<S> saveAll(Iterable<S> entities);
 
	/**
	 * Flushes all pending changes to the database.
	 */
	void flush();
 
	/**
	 * Saves an entity and flushes changes instantly.
	 *
	 * @param entity
	 * @return the saved entity
	 */
	<S extends T> S saveAndFlush(S entity);
 
	
}

CrudRepository

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
 
	/**
	 * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
	 * entity instance completely.
	 *
	 * @param entity must not be {@literal null}.
	 * @return the saved entity will never be {@literal null}.
	 */
	<S extends T> S save(S entity);
 
	/**
	 * Saves all given entities.
	 *
	 * @param entities must not be {@literal null}.
	 * @return the saved entities will never be {@literal null}.
	 * @throws IllegalArgumentException in case the given entity is {@literal null}.
	 */
	<S extends T> Iterable<S> saveAll(Iterable<S> entities);
}

JpaRepository和CrudRepository 的区别

  • JpaRepository 中的save方法实现源码:
 	@Transactional
    public <S extends T> List<S> save(Iterable<S> entities) {
        List<S> result = new ArrayList<S>();
        if (entities == null) {
            return result;
        }
        for (S entity : entities) {
            result.add(save(entity));
        }
        return result;
    }
  • CrudRepository 中的save方法源代码
	@Transactional
    public <S extends T> S save(S entity) {
        if (entityInformation.isNew(entity)) {
            em.persist(entity);//是新的就插入
            return entity;
        } else {
            return em.merge(entity); //不是新的merge
        }
    }

免责声明:文章转载自《学习笔记_Jpa》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Django日志记录配置代码pytorch中torch.cat(),torch.chunk(),torch.split()函数的使用方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

图表行为用于触发能够改变图表显示的相关动态功能,event事件用于接收action触发的行为,所以action行为要配合event事件一块学习

//触发图表行为(更改变图表显示的相关动态),例如图例开关legendToggleSelect, 数据区域缩放dataZoom,显示提示框showTip等等 //通过不同的type触发不同的行为 myChart.dispatchAction({ type: 'highlight', //高亮指定的数据图形。通过seriesNam...

C# 反射(Reflection)

反射(Reflection)可以在运行时获 得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。 反射用到的命名空间:    System.Reflection    System.Type    System.Reflection.Assembly using System; using System...

实践Kong for Kubernetes(K8S),kong最新2.1版本和kong-ingress-controller:0.9.1版本

先决条件 Kubernetes集群:您可以使用Minikube或GKE集群。Kong与Kubernetes的所有发行版兼容。 kubectl访问权限:您应该已经kubectl安装并配置为与Kubernetes集群通信。 为Kubernetes安装Kong 使用以下安装方法之一安装Kong for Kubernetes: YAML清单 helm K...

(转载)DevExpress ASPxGridView 使用文档四:数据源

转载请注明出处:http://surfsky.cnblogs.com/ ----------------------------------------------------------- DataSource 支持的数据源--     DataTable--     IList--     BindingList--     XXXDataSource...

SpringBoot JPA

-------------------- 剩下的时间不多了,全力做一些自己喜欢的东西 SpringBoot JPA : 默认使用的orm 框架是 hirbernate, 所以具备一些常见的hibernate 的功能, 不用手写数据库中的表,简单的crud 也不需要自己去写,只需继承一个接口就可以了。 @Entity @Table(name = "AUTH_...

MUD教程--巫师入门教程3

1. 指令格式为:edit <档名>,只加文件名,默认为当前目录,加here,表示编辑你当前所处的房间, 回车后即进入线上编辑系统。2. 如果这是一个已经有的档案,你可以使用 z 或 Z 来看档案。z表示一次显示20行,Z表示一次显示40行。为了编辑方便,最好在开始时用 n 表示每一行在开头处显示它的行数,再用一次 n 取消行数显示;3. 还有...