Spring JPA知识点整理
Spring JPA介绍官网:
https://docs.spring.io/spring-data/jpa/docs/2.4.3/reference/html/#repositories.core-concepts
The following table describes the keywords supported for JPA and what a method containing that keyword translates to:
Keyword | Sample | JPQL snippet |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
也支持xml定义:
<named-query name="User.findByLastname"> <query>select u from User u where u.lastname = ?1</query> </named-query>
通过自定义Query:
public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.emailAddress = ?1") User findByEmailAddress(String emailAddress); }
Like:
public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.firstname like %?1") List<User> findByFirstnameEndsWith(String firstname); }
使用Native SQL 也就是原生的SQL语句查询:
public interface UserRepository extends JpaRepository<User, Long> { @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true) User findByEmailAddress(String emailAddress); }
一次性带分页统计(一般不需要,直接用默认带分页的查询方法就可以):
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); }
排序:
public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.lastname like ?1%") List<User> findByAndSort(String lastname, Sort sort); @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%") List<Object[]> findByAsArrayAndSort(String lastname, Sort sort); } repo.findByAndSort("lannister", Sort.by("firstname")); repo.findByAndSort("stark", Sort.by("LENGTH(firstname)")); repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); repo.findByAsArrayAndSort("bolton", Sort.by("fn_len"));
绑定参数名形式:
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); }
使用SpEL 表达式,可以使用动态表名,实际上是通过Domain对象对应的Entity指定表名或对象名所决定的,如果做分表应当是有用,比如同样的表结构,按年分表的查询
具体见:https://docs.spring.io/spring-data/jpa/docs/2.4.3/reference/html/#jpa.query.spel-expressions
@Entity public class User { @Id @GeneratedValue Long id; String lastname; } public interface UserRepository extends JpaRepository<User,Long> { @Query("select u from #{#entityName} u where u.lastname = ?1") List<User> findByLastname(String lastname); }
更新指定字段,仅更新一个表的个别字段时可以使用:
@Modifying @Query("update User u set u.firstname = ?1 where u.lastname = ?2") int setFixedFirstnameFor(String firstname, String lastname);
删除语句,按某些特殊字段删除时使用:
interface UserRepository extends Repository<User, Long> { void deleteByRoleId(long roleId); @Modifying @Query("delete from User u where u.role.id = ?1") void deleteInBulkByRoleId(long roleId); }
自定义BaseRepository的方法:
(1) 自定义基础类,需要有构造函数:
class MyRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID> { private final EntityManager entityManager; MyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); // Keep the EntityManager around to used from the newly introduced methods. this.entityManager = entityManager; } @Transactional public <S extends T> S save(S entity) { // implementation goes here } }
(2) 在SpringBoot的配置类或启动程序中增加声明
@Configuration @EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class) class ApplicationConfiguration { … }
或者用xml形式:
<repositories base-package="com.acme.repository" base-class="….MyRepositoryImpl" />
事件的监控,可以对增删改事件进行监控和后序处理,应该可以用来做内容保存后的创建索引等逻辑:
class AnAggregateRoot { @DomainEvents Collection<Object> domainEvents() { // … return events you want to get published here } @AfterDomainEventPublication void callbackMethod() { // … potentially clean up domain events list } }
The methods are called every time one of a Spring Data repository’s save(…)
, saveAll(…)
, delete(…)
or deleteAll(…)
methods are called.
用法参考:https://blog.csdn.net/f4761/article/details/84622317
给实体对象加上@DynamicUpdate,提高更新效率,也就是指更改变化的字段,能够提高一些效率
Spring JPA动态表:
import org.hibernate.EmptyInterceptor; public class JPAInterceptor extends EmptyInterceptor{ @Override public String onPrepareStatement(String sql) { System.out.println(sql); return super.onPrepareStatement(sql); } }
实现该接口,配置:
spring.jpa.properties.hibernate.ejb.interceptor=xxxx.JPAInterceptor
这样就能拦截jpa执行sql,然后对其中表名进行替换了,可在Onxxx方法利用ThreadLocal设定Entity标记判断是否对sql进行处理,或者获取Entity中的属性取值然后按该取值进行分表。
参考:https://my.oschina.net/u/1053238/blog/1611773