什么的 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, 可接数字
- ,Distinct
- ,StartingWith EndingWith Containing
- , Like,NotNull Not
- ,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(Iterableusers) 结果并保持行为与其他 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/
来源: http://www.bubuko.com/infodetail-2901080.html