Skip to content

Spring Data Jpa

字数
903 字
阅读
6 分钟

基于 JPA 标准,并提供了一套简洁的 API 和注解,封装 JPA 的复杂性,简化了数据层的开发工作,使开发人员能够更专注于业务逻辑的实现

java
public interface LogRecordRepository extends JpaPlusRepository<LogRecord, Long> {

    // 方式1: 属性名
    List<LogRecord> findByType(String type);

    // 方式2: 属性表达式(如:And、Equals.....)
    List<LogRecord> findByTypeAndIp(String type, String ip);

    // 方式3: 内置注解查询、事务更新
    @Query(value = "select * from xx_log where time >= ?1", nativeQuery = true)
    List<LogRecord> findByTimeout(Long time);

    @Transactional
    @Modifying
    @Query(value = "update xx_log set time=?1 , where id =?2 ", nativeQuery = true)
    int updateTime(Long time, Long id);

    // 方式4: QueryDsl
    Iterable<LogRecord> findAll(Predicate predicate);
}

注解

@EnableJpaPlusRepositories

依赖

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

扩展

JpaPlusRepository 整合了 JpaRepositoryImplementationQuerydslPredicateExecutor 在保留原方法基础上,扩展了对QueryDsl的支持

java
public interface JpaPlusRepository<T, ID> extends JpaRepositoryImplementation<T, ID>, QuerydslPredicateExecutor<T> {

    T findOne(ID id);

    Page<T> findAll(JPAQuery<T> query, Pageable pageable);

    Page<T> findAll(JPAQuery<T> query, Pageable pageable, OrderSpecifier<?>... orders);

    <S extends T> S insertOrUpdate(S entity);

    <S extends T> List<S> insertOrUpdate(S... entities);

    <S extends T> List<S> insertOrUpdate(List<S> entities);

    int insertOrUpdateRow(T entity);

    int insertOrUpdateRow(T... entities);

    int insertOrUpdateRow(List<T> entities);

    int update(T entity, Predicate... predicate);

    int update(Path<T> key, T val, Predicate... predicate);

    <V> int update(Path<V> key, Expression<? extends V> expression, Predicate... predicate);

    int delete(ID... ids);

    int delete(List<ID> ids);

    int delete(Predicate... predicate);
}

使用

java
@Log4j2
@EnableJpaAuditing
@EnableJpaPlusRepositories
@SpringBootApplication
public class FastBootApplication {

    public static void main(String[] args) throws UnsupportedEncodingException {
        SpringApplication app = new SpringApplication(FastBootApplication.class);
        app.setBannerMode(Banner.Mode.CONSOLE);
        app.run(args);
        log.info("Started FastBootApplication Successfully");
    }
}

示例

QLogRecord ql = QLogRecord.logRecord;

java
public class JpaPlusPojo {

    @Data
    @AllArgsConstructor
    public static class LogRecordPojo {

        public Long id;

        public String ip;

        public Long min;

        public Long max;
    }
}

查询

单表

java
Test
@Order(1)
public void select() {
    // 条件
    Predicate predicate = ql.type.likeIgnoreCase("%GET%");
    // 排序
    Sort sort = Sort.by(Direction.ASC, LogRecord.FIELDS.createDate);
    // 分页
    Pageable pageable = PageRequest.of(0, 10, sort);

    // 分页查询
    Expression<LogRecord> exp = ql;
    JPAQuery<LogRecord> jpaQuery = mJpaQuery.select(exp).from(ql).where(predicate);
    Page<LogRecord> data = mLogRecordRepository.findAll(jpaQuery, pageable);
    assertEquals(data.getContent().size(), 6);

    // 分页查询
    Expression<LogRecord> expFields = Projections.fields(LogRecord.class, ql, ql.id, ql.ip);
    jpaQuery.select(expFields);
    data = mLogRecordRepository.findAll(jpaQuery, pageable);
    assertEquals(data.getContent().size(), 6);

    // 投影查询(多表联合查询)
    Expression expTuple =Projections.constructor(LogRecordPojo.class, ql.id, ql.ip, ql.time.min(), ql.time.max());
    List<LogRecordPojo> list = jpaQuery.select(expTuple).from(ql).groupBy(ql.type, ql.createDate).fetch();
    assertTrue(list.size() > 0);
}

多表

java
@RequestMapping(value = "page")
public PaginationResult page(BaseVo base, PaginationVo page) {
    // 对象
    QUser qUser = QUser.user;
    QSRole qRole = QSRole.sRole;
    QUserRole qUserRole = QUserRole.userRole;
    // 条件
    Predicate predicate = qUser.id.isNotNull();
    if (StrUtil.isNotBlank(base.getKeyword())) {
         Predicate p1 = qUser.id.like("%" + base.getKeyword() + "%");
         Predicate p2 = qUser.username.likeIgnoreCase("%" + base.getKeyword() + "%");
         Predicate p3 = qUser.nickname.likeIgnoreCase("%" + base.getKeyword() + "%");
         predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2, p3));
    }
    // 分页
    Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), Sort.by(Direction.DESC, User.FIELDS.createDate));
    // 查询字段
    QBean<User> selectBean = Projections.fields(User.class
                , qUse // 主表字段
                , qRole.id.longValue().as(User.FIELDS.roleId), //联查字段
                , qRole.name.as(User.FIELDS.roleName));
    // 构造查询
    JPAQuery<User> jpaQuery = mJPAQueryFactory.select(selectBean)
                .from(qUser)
                .leftJoin(qUserRole)
                .on(qUser.id.eq(qUserRole.pk.users))
                .leftJoin(qRole)
                .on(qRole.id.eq(qUserRole.pk.roles))
                .where(predicate);
    // 分页查询
    Page<User> data = mUserRepository.findAll(jpaQuery, pageable);
    // 构造
    return PaginationHelper.create(data);
}

新增

java
@Test
@Order(3)
public void insertOrUpdate() {
    // 单个
    LogRecord lr11 = result.get(0);
    lr11.setTime(100L);
    LogRecord lr12 = mLogRecordRepo.insertOrUpdate(lr11);
    assertEquals(lr12.getTime(), 100);
    lr12.setTime(101L);
    int row = mLogRecordRepo.insertOrUpdateRow(lr12);
    assertEquals(row, 1);

    // 多个
    LogRecord lr21 = result.get(0);
    lr21.setTime(102L);
    LogRecord lr22 = result.get(1);
    lr22.setTime(103L);
    List<LogRecord> lrs3 = mLogRecordRepo.insertOrUpdate(lr21, lr22);
    assertEquals(lrs3.get(0).getTime(), 102);
    assertEquals(lrs3.get(1).getTime(), 103);
    lr21.setTime(104L);
    lr22.setTime(104L);
    row = mLogRecordRepo.insertOrUpdateRow(lr21, lr22);
    assertEquals(row, 2);
}

更新

java
@Test
@Order(4)
public void update() {
    LogRecord lr = result.get(0);
    Long id = lr.getId();
    Predicate predicate = ql.id.eq(id);

    lr.setTime(101L);
    int row = mLogRecordRepo.update(lr, predicate);
    assertTrue(row > 0);
    assertEquals(mLogRecordRepo.findOne(id).getTime(), 101);

    lr.setTime(102L);
    row = mLogRecordRepo.update(ql, lr, predicate);
    assertTrue(row > 0);
    assertEquals(mLogRecordRepo.findOne(id).getTime(), 102);

    row = mLogRecordRepo.update(ql.time, Expressions.constant(103L), predicate);
    assertTrue(row > 0);
    assertEquals(mLogRecordRepo.findOne(id).getTime(), 103);
}

删除

java
@Test
@Order(3)
public void delete() {
    // 单个
    mLogRecordRepo.delete(result.get(0).getId(), result.get(1).getId());

    // 多个
    int row = mLogRecordRepo.delete(ql.type.eq("GET"));
    assertTrue(row > 0);
}

其他

属性表达式

关键字示例片段
AndfindByNameAndAgewhere x.name = ?1 and x.age = ?2
OrfindByNameOrAgewhere x.name = ?1 or x.age = ?2
IsfindByNameIswhere x.name = ?1
EqualsfindByNameEqualswhere x.name = ?1
BetweenfindByStartDateBetweenwhere x.startDate between ?1 and ?2
LessThanfindByAgeLessThanwhere x.age < ?1
LessThanEqualfindByAgeLessThanEqualwhere x.age ⇐ ?1
GreaterThanfindByAgeGreaterThanwhere x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqualwhere x.age >= ?1
AfterfindByStartDateAfterwhere x.startDate > ?1
BeforefindByStartDateBeforewhere x.startDate < ?1
IsNullfindByAgeIsNullwhere x.age is null
IsNotNullfindByAgeIsNotNullwhere x.age not null
NotNullfindByAgeNotNullwhere x.age not null
LikefindByNameLikewhere x.name like ?1
NotLikefindByNameNotLikewhere x.name not like ?1
StartingWithfindByNameStartingWithwhere x.name like ?1 (parameter bound with appended %)
EndingWithfindByNameEndingWithwhere x.name like ?1 (parameter bound with prepended %)
ContainingfindByNameContainingwhere x.name like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByNameDescwhere x.age = ?1 order by x.name desc
NotfindByNameNotwhere x.name <> ?1
InfindByAgeIn(Collectionages)where x.age in ?1
NotInfindByAgeNotIn(Collectionage)where x.age not in ?1
TRUEfindByActiveTrue()where x.active = true
FALSEfindByActiveFalse()where x.active = false
IgnoreCasefindByNameIgnoreCasewhere UPPER(x.name) = UPPER(?1)

Released under the MIT License.