Spring Data JPA 自定义Repository接口与子接口

上篇文章介绍了 Repository接口的使用(Spring Data JPA介绍与Spring的整合),接下来重点掌握 Repository的CrudRepository子接口下的子接口。

在dao层的接口中定义方法,查询的方法:find或get或read开头,遵守一些规定:

KeywordSampleJPQL snippet

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

IsEquals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNullNull

findByAge(Is)Null

… where x.age is null

IsNotNullNotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

 

Repository的子接口的使用时只需要 dao层继承该接口即可。

一、CrudRepository接口

CrudRepository接口还有一个PagingAndSortingRepository子接口:

CrudRepository 主要提供CRUD功能。

PagingAndSortingRepository 提供进行分页和排序记录的方法。

1、CrudRepository 主要提供CRUD功能。

    CrudRepository接口的方法:很好理解就不解释了,下面使用几个即可快速掌握。

    

public interface UserDao extends CrudRepository<User, Long> {

}

测试:

    @Test
    public void test() {
        User user = new User();
        user.setUsername("赵云");
        user.setPassword("123456");
        user.setAge(18);
        user.setCreatetime(LocalDateTime.now());
        User save = userDao.save(user);
        System.out.println(save.getId()); // 4
    }

    @Test
    public void testList() {
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            User user = new User();
            user.setUsername("赵云" + i);
            user.setPassword("123456");
            user.setAge(18 + i);
            user.setCreatetime(LocalDateTime.now());
            list.add(user);
        }

        List<User> saveAll = (List<User>) userDao.saveAll(list);

        // id 不存在,会报错:org.springframework.dao.EmptyResultDataAccessException: 
        // No class cn.jq.springdatajpademo.model.User entity with id 2 exists!
        userDao.deleteById(2L);
    }

2、PagingAndSortingRepository 提供进行分页和排序记录的方法。

        

   Pageable是一个接口,这里使用 PageRequest类

        

测试:

    @Test
    public void test() {
        Sort.Order order1 = new Sort.Order(Sort.Direction.ASC, "age");
        Sort.Order order2 = new Sort.Order(Sort.Direction.DESC, "id");
        Sort sort = Sort.by(order1, order2);
        // 查询第3页
        Pageable pageRequest = PageRequest.of(2, 10, sort);
        Page<User> page = userDao.findAll(pageRequest);

        List<User> userList = page.getContent(); // 数据
        int number = page.getNumber(); // 当前页码,注意默认从0开始
        int totalPages = page.getTotalPages(); // 总页码数
        int numberOfElements = page.getNumberOfElements(); // 当前页码记录数
        long totalElements = page.getTotalElements(); // 总的数量
        int size = page.getSize(); // 每页的记录数

        System.out.println("userList = " + userList);
        System.out.println("number = " + number + 1);
        System.out.println("totalPages = " + totalPages);
        System.out.println("numberOfElements = " + numberOfElements);
        System.out.println("totalElements = " + totalElements);
        System.out.println("size = " + size);
    }

3、JpaRepository接口是项目开发时使用最多的接口。

JpaRepository继承自PagingAndSortingRepository接口,JpaRepository基于JPA的Repository接口,极大减少了JPA作为数据访问的代码,JpaRepository是实现Spring Data JPA技术访问数据库的关键接口。

public interface UserDao extends JpaRepository<User, Long> {

}

   

测试:

    @Test
    public void test() {
        User user = new User();
        user.setUsername("赵云胜多负少");
        user.setPassword("123456");
        user.setAge(18);
        user.setCreatetime(LocalDateTime.now());
//        主键存在update,不存在就insert操作
//        user.setId(4L);
        User saveAndFlush = userDao.saveAndFlush(user);
        System.out.println(saveAndFlush.getId());
    }

二、JpaSpecificationExecutor接口

JpaSpecificationExecutor 是 JPA 2.0 提供的 Criteria API 的使用封装,可以用于动态生成 Query 来满足我们业务中的各种复杂场景。

Spring Data JPA 为我们提供了 JpaSpecificationExecutor 接口。该接口通过Specification来定义查询条件,使用Specification的要点就是CriteriaBuilder,通过这个对象来创建条件,之后返回一个Predicate对象。这个对象中就有了相应的查询需求,我们同样可以定义多个Specification,之后通过Specifications对象将其连接起来。

       

通过源码看出:SimpleJpaRepository类是JpaSpecificationExecutor接口的默认实现。

    

 

测试:

public interface UserDao extends JpaRepository<User, Long>, JpaSpecificationExecutor {

}
    @Test
    public void test() {

        Specification<User> s1 = new Specification<User>() {
            /**
             * @param *root: 代表查询的实体类.
             * @param criteriaQuery: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
             * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象.使用不多
             * @param *criteriaBuilder: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
             * @return: *Predicate 类型, 代表一个查询条件.
             */
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Integer> age = root.get("age");
                Predicate p1 = criteriaBuilder.greaterThan(age, 18);
                Path username = root.get("username");
                Predicate p2 = criteriaBuilder.like(username, "%李四%");
                // where user0_.age>18 and ( user0_.username like ? )
                return criteriaBuilder.and(p1, p2);
            }
        };
       
        List list1 = userDao.findAll(s1);
        System.out.println(list1);


    }

三、自定义Repository接口

如果SpringData提供的JPA接口没有我们需要的查询方式,也是可以自定义Repository接口的。

spring data除了已经给我们提供了大量的 Repository接口,它支持我们自己定义Repository接口来扩展功能,实现一些个性化的需求。

1、自定义Repository接口的具体步骤:

1)新建一个自定义接口

// 自定义 Repository接口
public interface MyUserRepository {

    List<User> findByAge(Integer age);
}

2)新建该自定义接口的实现类,并对方法进行实现,需要注入 EntityManager对象完成对数据库的操作

public class MyUserRepositoryImpl implements MyUserRepository {

    // 这里使用JPA技术实现
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<User> findByAge(Integer age) {
        String jpql = "select u from User u where u.age <= ?1";
        Query query = entityManager.createQuery(jpql, User.class);
        query.setParameter(1, age);
        List<User> resultList = query.getResultList();
        return resultList;
    }
}

注意:实现类的名称必须是该自定义接口的名称+Impl,名称会由SpringData解析。

        EntityManager是JPA中用于增删改查的接口,它的作用相当于一座桥梁,连接内存中的 Java对象和数据库的数据存储。也可以根据它进行sql的原生查找。

3)在目标接口(dao层接口)中继承该自定义接口。

public interface UserDao extends JpaRepository<User, Long>, MyUserRepository {

    // spring data jpa 方法
    List<User> findUsersByUsernameLikeAndAgeLessThanEqual(String username, Integer age);
}

4)测试类,目标接口(dao层接口)就可以使用自定义接口方法

    @Test
    public void testList() {
        List<User> userList = userDao.findByAge(18);
        System.out.println(userList);

        List<User> userList2 = userDao.findUsersByUsernameLikeAndAgeLessThanEqual("%赵云%", 18);
        System.out.println(userList2);
    }

   

 

 

参考文章:

Spring Data JPA之JpaSpecificationExecutor复杂动态查询实例

 

—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值