https://blog.csdn.net/linmengmeng_1314/article/details/101599559
需要继承两个接口
public interface UserDao extends JpaRepository, JpaSpecificationExecutor {
}
count:统计 long count = userDao.count();
exists系列方法:数据库中是否存在 boolean b = userDao.existsById(2);
find系列方法:立即加载 Optional
System.out.println(user.get());
getOne:延迟加载,返回的是一个动态代理对象 User user = userDao.getOne(2);
System.out.println(user);
除了调用spring data jpa内置的api,我们也可以在dao接口中定义我们自己的方法,通过@Query声明jpql或sql语句。
public interface UserDao extends JpaRepository
@Query(value = "from User where name = :name and age = :age")
public User findUserByName(@Param("name") String userName,@Param("age") int age);
}
@Query(value = "update User set name = :name where id = :id")
@Modifying
public Integer updateNameById(@Param("id") int id,@Param("name") String userName);
@org.junit.Test
@Transactional(rollbackFor = Exception.class)
//@Rollback(value = false)//如果设置为fasle,即使发生异常也不会回滚
public void testJpql(){
User user = userDao.findUserByName("lili",18);
System.out.println(user);
userDao.updateNameById(user.getId(),"lili_2");
}
public interface UserDao extends JpaRepository
@Query(value = "select * from user where name = :name and age = :age",nativeQuery = true)
public User findUserByName(@Param("name") String userName,@Param("age") int age);
}
spring data jpa制定了一些约定,如果按照这些约定来定义方法名,则会自动解析出sql语句。
findBy + 属性名 + 查询方式 + (And|Or) + 属性名 + 查询方式...
查询方式 | 方法命名 | sql where字句 |
---|---|---|
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Is,Equals | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEquals | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEquals | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like '?%' |
EndingWith | findByNameEndingWith | where name like '%?' |
Containing | findByNameContaining | where name like '%?%' |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection> c) | where id in (?) |
NotIn | findByIdNotIn(Collection> c) | where id not in (?) |
True | findByAaaTue | where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
简单挑几个示例:
public interface UserDao extends JpaRepository, JpaSpecificationExecutor {
public User findByName(String name);
public User findByNameLike(String name);
public User findByNameLikeAndAge(String name, int age);
public List findByIdBetween(int idMin, int idMax);
}
@org.junit.Test
public void testName(){
User user1 = userDao.findByName("tom");
System.out.println(user1);
User user2 = userDao.findByNameLike("t%");
System.out.println(user2);
User user3 = userDao.findByNameLikeAndAge("tom",18);
System.out.println(user3);
List users = userDao.findByIdBetween(1, 3);
users.forEach(new Consumer() {
@Override
public void accept(User user) {
System.out.println(user);
}
});
}
Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.age as age3_0_, user0_.name as name4_0_, user0_.phone as phone5_0_, user0_.sex as sex6_0_ from user user0_ where user0_.name=?
User{id=3, name='tom', age=18, sex=1, address='null', phone='null'}
Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.age as age3_0_, user0_.name as name4_0_, user0_.phone as phone5_0_, user0_.sex as sex6_0_ from user user0_ where user0_.name like ? escape ?
User{id=3, name='tom', age=18, sex=1, address='null', phone='null'}
Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.age as age3_0_, user0_.name as name4_0_, user0_.phone as phone5_0_, user0_.sex as sex6_0_ from user user0_ where (user0_.name like ? escape ?) and user0_.age=?
User{id=3, name='tom', age=18, sex=1, address='null', phone='null'}
Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.age as age3_0_, user0_.name as name4_0_, user0_.phone as phone5_0_, user0_.sex as sex6_0_ from user user0_ where user0_.id between ? and ?
User{id=2, name='lili2', age=18, sex=1, address='null', phone='null'}
User{id=3, name='tom', age=18, sex=1, address='null', phone='null'}
我们上面提到过,springdata jpa的dao层一般继承2个接口JpaRepository和JpaSpecificationExecutor。JpaRepository封装了crud、统计、排序、分页的常见操作,而JpaSpecificationExecutor基于JPA的criteria查询封装了另一种查询方式,我们之前一直在使用JpaRepository中的方法,下面来看下JpaSpecificationExecutor接口,它里面只提供了5个方法:
public interface JpaSpecificationExecutor {
//查询一个
Optional findOne(@Nullable Specification spec);
//查询全部
List findAll(@Nullable Specification spec);
//查询全部 提供分页功能
Page findAll(@Nullable Specification spec, Pageable pageable);
//查询全部,提供排序功能
List findAll(@Nullable Specification spec, Sort sort);
//统计
long count(@Nullable Specification spec);
}
可以看到,这5个方法有个共同点,接收一个Specification参数。
Specification是对JPA规范中Root、CriteriaQuery、CriteriaBuilder的一层封装,用于构建过滤条件。实例化Specification需要实现它的toPerdicate方法:
//参数含义在我的另一文JPA规范中有介绍,简单说来Root用于获得查询属性,CriteriaBuilder用于构建过滤条件,CriteriaQuery用于指定最终查询语句,这里一般不会使用,默认为where语句。
Predicate toPredicate(Root
注意这里创建出来的是where查询语句。
来个简单示例,查询表中年龄大于等于18的所有河南人:
@Test
public void test(){
Specification
@Override
public Predicate toPredicate(Root
//分别构造各个单属性的过滤条件
Predicate namePredicate = criteriaBuilder.like(root.get("address"), "河南%");
Predicate agePredicate = criteriaBuilder.ge(root.get("age"), 18);//大于等于
//组合成最终的过滤条件
Predicate predicate = criteriaBuilder.and(namePredicate, agePredicate);
return predicate;
}
};
//查询
List
users.forEach(new Consumer
@Override
public void accept(User user) {
System.out.println(user);
}
});
}
如果要添加排序和分页,可以使用Sort和Pageable。
Sort sort = new Sort(Sort.Direction.DESC,"id");//排序属性可以设置多个
List
Sort sort = new Sort(Sort.Direction.DESC,"id");
//Pageable pageable = PageRequest.of(0,10);//pageIndex,pageSize
Pageable pageable = PageRequest.of(0,10,sort);
Page
users.forEach(new Consumer
@Override
public void accept(User user) {
System.out.println(user);
}
});
application.yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/study?serverTimezone=GMT
username: root
password: crystal1024
jpa:
show-sql: true
hibernate:
ddl-auto: update
https://github.com/lunxinfeng/jpa/tree/master/springdatajpa