zoukankan      html  css  js  c++  java
  • Spring Data Jpa 学习笔记

    什么的Spring Data JPA

    Spring Data JPA为Java Persistence API(JPA)提供了存储库支持。它简化了需要访问JPA数据源的应用程序的开发。

    maven依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
    

    核心概念

    1、核心接口Repository

    public interface Repository<T, ID>
    

    It takes the domain class to manage as well as the ID type of the domain class as type arguments. This interface acts primarily as a marker interface to capture the types to work with and to help you to discover interfaces that extend this one.

    T : 表实体类型的泛型。
    ID: 表关键字类型,可为组合。
    举例:

    interface UserRepository extends CrudRepository<User, Long>
    

    2、CrudRepository

    public interface CrudRepository<T, ID> extends Repository<T, ID>
    

    提供复杂的CURD功能。 除了已经提供的接口,还可以新增接口,并不用自己实现。 比如countByXXX,deleteByXXX(返回个数),findByXXX,removeByXXX(返回集合),如:

      long deleteByLastname(String lastname);  
      List<User> removeByLastname(String lastname);
    

    3、PagingAndSortingRepository

    public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID>
    

    多提供了2个接口,用于分页和排序访问。

    4、JpaRepository

    public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
    

    从实现上看,是提供了一些批量操作接口,待考证。

    5、@NoRepositoryBean

    中间存储库接口使用注释@NoRepositoryBean。确保将该注释添加到Spring Data不应在运行时创建实例的所有存储库接口。

    就像abstart class一样,注解了@NoRepositoryBean的接口不生成Bean。

    初始化数据库

    就是把存在 json或xml文件中的默认数据给导到数据库中。

    定义库接口

    1、支持可空性判断注解

    @NonNull: Annotation to indicate that a specific parameter, return value, or field cannot be null (not needed on parameter and return value where @NonNullApi and @NonNullFields apply) .   
    @Nullable: Annotation to indicate that a specific parameter, return value, or field can be null.    
    @NonNullApi: Annotation at the package level that declares non-null as the default behavior for parameters and return values.   
    @NonNullFields: Annotation at the package level that declares non-null as the default behavior for fields.
    

    2、支持返回值Optional

    Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress);
    

    定义查询方法

    两种方式 1、通过直接从方法名称派生查询。 2、通过使用手动定义的查询。

    通过@EnableJpaRepositories(queryLookupStrategy = Key.CREATEIFNOT_FOUND)配置,值有如下3个:

        CREATE:根据名称创建。  
        USE_DECLARED_QUERY:尝试查找声明的,找不到抛异常。  
        CREATE_IF_NOT_FOUND(默认):先USE_DECLARED_QUERY,找不到按CREATE。  
    

    名称关键字

    1、find…By,read…By,query…By,count…By,和get…By
    2、And Or 3、Is Equals
    4、Between,LessThan,GreaterThan,After Before 
    5、IgnoreCase、AllIgnoreCase
    6、OrderBy...Asc/Desc
    7、first或top,可接数字
    8、Distinct
    9、StartingWith EndingWith Containing
    10、 Like,NotNull Not
    11、In NotIn True False

    支持分页

    附加排序参数:Sort(不支持函数) JpaSort.unsafe(支持函数) 
    附加分页参数:Pageable
    返回分页结果:Page

    支持流式结果

    @Query("select u from User u")
    Stream<User> findAllByCustomQueryAndStream();
    
    Stream<User> readAllByFirstnameNotNull();
    
    @Query("select u from User u")
    Stream<User> streamAllPaged(Pageable pageable);
    
    try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
      stream.forEach(…);
    }
    

    异步查询结果

    @Async
    Future<User> findByFirstname(String firstname);               
    
    @Async
    CompletableFuture<User> findOneByFirstname(String firstname); 
    
    @Async
    ListenableFuture<User> findOneByLastname(String lastname);    
    

    命名查询 先在Entity中定义NamedQuery注解,再在Repository中添加方法

    @Entity
    @NamedQuery(name = "User.findByEmailAddress",
      query = "select u from User u where u.emailAddress = ?1")
    public class User {
    
    }
    public interface UserRepository extends JpaRepository<User, Long> {
    
      List<User> findByLastname(String lastname);
    
      User findByEmailAddress(String emailAddress);
    }
    

    直接运用@Query

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query("select u from User u where u.emailAddress = ?1")
      User findByEmailAddress(String emailAddress);
    }
    

    使用命名参数可以防止位置出错

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
      User findByLastnameOrFirstname(@Param("lastname") String lastname,
                                     @Param("firstname") String firstname);
    }
    

    使用原生SQL语句查询

    该@Query注释允许通过设定运行的原生查询nativeQuery标志设置为true,如图以下示例:

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
      User findByEmailAddress(String emailAddress);
    }
    

    原生分页查询

    Spring Data JPA目前不支持对本机查询进行动态排序,因为它必须操纵声明的实际查询,而对于本机SQL,它无法可靠地执行。但是,您可以通过自己指定计数查询来使用本机查询进行分页,如以下示例所示:

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
        countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
        nativeQuery = true)
      Page<User> findByLastname(String lastname, Pageable pageable);
    }
    

    使用SpEL表达式

      @Query("select u from #{#entityName} u where u.lastname = ?1")
      List<User> findByLastname(String lastname);
    

    如上,可使用#{#entityName}代替实体名。

    Querydsl 扩展

    Querydsl定义了查询条件,使用如下:

    public interface QuerydslPredicateExecutor<T> { 
          Iterable<T> findAll(Predicate predicate);  
          //....    more functionality omitted.
    }
    
    interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {
    }
    
    Predicate predicate = user.firstname.equalsIgnoreCase("dave")
        .and(user.lastname.startsWithIgnoreCase("mathews"));
    
    userRepository.findAll(predicate);
    

    修改查询

    @Modifying
    @Query("update User u set u.firstname = ?1 where u.lastname = ?2")
    int setFixedFirstnameFor(String firstname, String lastname);
    

    删除

    派生删除查询是执行查询然后调用CrudRepository.delete(Iterable users)结果并保持行为与其他delete(…)方法的实现同步的快捷方式CrudRepository。

    View

    声明一个需要的结果的Interface

    interface NamesOnly {
    
      String getFirstname();
      String getLastname();
    }
    

    定义返回接口的查询方法

    interface PersonRepository extends Repository<Person, UUID> {
    
      Collection<NamesOnly> findByLastname(String lastname);
    }
    

    结果也可以扩展其他表的对应关系

    interface PersonSummary {
    
      String getFirstname();
      String getLastname();
      AddressSummary getAddress();
    
      interface AddressSummary {
        String getCity();
      }
    }
    

    还可以用SpEL表达式做简单的组合,但不建议这么做,下面有更好的方法

    interface NamesOnly {
    
      @Value("#{target.firstname + ' ' + target.lastname}")
      String getFullName();
      …
    }
    

    使用接口的方法获取组合结果

    interface NamesOnly {
    
      String getFirstname();
      String getLastname();
    
      default String getFullName() {
        return getFirstname.concat(" ").concat(getLastname());
      }
    }
    

    使用Bean的方法获取组合结果

    @Component
    class MyBean {
    
      String getFullName(Person person) {
        …
      }
    }
    
    interface NamesOnly {
    
      @Value("#{@myBean.getFullName(target)}")
      String getFullName();
      …
    }
    

    为了方便扩展,可以用泛型在使用时才指定返回View类型

    interface PersonRepository extends Repository<Person, UUID> {
    
      <T> Collection<T> findByLastname(String lastname, Class<T> type);
    }
    

    创建库实例

    通过JavaConfig

    要指定扫描路径:

    @EnableJpaRepositories("com.acme.repositories")
    

    在Spring容器外使用

    RepositoryFactorySupport factory = … // Instantiate factory here
    UserRepository repository = factory.getRepository(UserRepository.class);
    

    自定义查询方法

    class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
    
      public void someCustomMethod(User user) {
        // Your custom implementation
      }
    }
    

    实现本身不依赖于Spring Data,可以是常规的Spring bean。因此,您可以使用标准依赖项注入行为将引用注入其他bean(例如a JdbcTemplate),参与方面等。

    网络支持

    参考文档

    两个特性,没具体看

    EntityManagerFactory
    PlatformTransactionManager

    基于注解的配置

    @Configuration
    @EnableJpaRepositories
    @EnableTransactionManagement
    class ApplicationConfig {
    
      @Bean
      public DataSource dataSource() {
    
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        return builder.setType(EmbeddedDatabaseType.HSQL).build();
      }
    
      @Bean
      public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
    
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.acme.domain");
        factory.setDataSource(dataSource());
        return factory;
      }
    
      @Bean
      public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
      }
    }
    

    上述配置类使用EmbeddedDatabaseBuilderAPI来设置嵌入式HSQL数据库spring-jdbc。然后Spring Data设置EntityManagerFactory并使用Hibernate作为示例持久性提供程序。这里声明的最后一个基础架构组件是JpaTransactionManager。最后,该示例使用@EnableJpaRepositories注释激活Spring Data JPA存储库

    默认情况下,Spring Data JPA存储库是默认的Spring bean。它们是单例范围并且急切地初始化。在启动期间,他们已经与JPA EntityManager进行交互以进行验证和元数据分析。Spring Framework支持EntityManagerFactory在后台线程中初始化JPA ,因为该进程通常占用Spring应用程序中的大量启动时间。为了有效地利用后台初始化,我们需要确保尽可能晚地初始化JPA存储库。

    从Spring Data JPA 2.1开始,您现在可以配置BootstrapMode

    保存实体

    可以使用该CrudRepository.save(…)方法执行保存实体。它通过使用基础JPA持久化或合并给定实体EntityManager。如果实体尚未持久化,则Spring Data JPA会通过调用该entityManager.persist(…)方法来保存实体。否则,它会调用该entityManager.merge(…)方法。

    存储过程

    按示例查询

    它允许动态创建查询,并且不需要您编写包含字段名称的查询。

    简单使用如下: 构造匹配器: 
    1:

    Person person = new Person();                         
    person.setFirstname("Dave");                          
    
    Example<Person> example = Example.of(person);   
    

    2:

    Person person = new Person();                          
    person.setFirstname("Dave");                           
    
    ExampleMatcher matcher = ExampleMatcher.matching()     
      .withIgnorePaths("lastname")                         
      .withIncludeNullValues()                             
      .withStringMatcherEnding();                          
    
    Example<Person> example = Example.of(person, matcher); 
    

    库扩展QueryByExampleExecutor接口:

    public interface QueryByExampleExecutor<T> {
    
      <S extends T> S findOne(Example<S> example);
    
      <S extends T> Iterable<S> findAll(Example<S> example);
    
      // … more functionality omitted.
    }
    

    查询:

    public interface PersonRepository extends JpaRepository<Person, String> { … }
    
    public class PersonService {
    
      @Autowired PersonRepository personRepository;
    
      public List<Person> findPeople(Person probe) {
        return personRepository.findAll(Example.of(probe));
      }
    }
    

    事务性

    public interface UserRepository extends CrudRepository<User, Long> {
    
      @Override
      @Transactional(timeout = 10)
      public List<User> findAll();
    
      // Further query method declarations
    }
    
    @Transactional(readOnly = true)
    public interface UserRepository extends JpaRepository<User, Long> {
    
      List<User> findByLastname(String lastname);
    
      @Modifying
      @Transactional
      @Query("delete from User u where u.active = false")
      void deleteInactiveUsers();
    }
    

    通常,您希望将readOnly标志设置为true,因为大多数查询方法只读取数据。与此相反,deleteInactiveUsers()使用@Modifying注释并覆盖事务配置。因此,该方法在readOnly标志设置为的情况下运行false。

    Lock

    interface UserRepository extends Repository<User, Long> {
    
      // Plain query method
      @Lock(LockModeType.READ)
      List<User> findByLastname(String lastname);
    }
    

    审计

    CDI集成

    在容器外使用,具体略。

    参考

    https://docs.spring.io/spring-data/jpa/docs/2.1.3.RELEASE/reference/html/

    https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#spring-core

  • 相关阅读:
    STM32概述
    对xlslib库与libxls库的简易封装
    Makefile.am编写规则
    linux下使用autoconf制作Makefile
    python 登录三次禁止登录
    Linux -- gpasswd
    Linux -- userdel
    Linux -- groupmod
    Linux -- groupadd
    Linux -- passwd
  • 原文地址:https://www.cnblogs.com/aoyihuashao/p/10193799.html
Copyright © 2011-2022 走看看