基本知识:
- Repository:仅仅只是一个标识,没有任何方法,方便Spring自动扫描识别
- CrudRepository:继承Repository,实现一组CRUD相关方法
- PagingAndStortingRepository:继承CrudRepository,实现一组分页排序相关方法
- JpaRepository:继承PagingAndStortingRepository,QueryByExampleExecutor 实现一组JPA规范方法
下面是一个AppUser 的 Dao接口,除了简单的findBy 接口查询外,还有@Query的查询,查询返回一个自定义的结果Useinfo,UserInfo 从2个表中获取,从AppUser 中获取 phone ,name 等信息,从 HearUrl 表中获取userid 对应的头像地址;
@Repository
public interface AppUserRepository extends JpaRepository<AppUser, Long>{
AppUser findByUserid(String userid);
//根据电话和客户名查询
AppUser findByPhoneAndCustomName(String phone, String customName);
//分页查询
Page<AppUser> findByCustomName(String customName,Pageable pageable);
//查询2个表的指定字段,组成新的对象UserInfo
@Query(value = "select new com.cxx.beans.UserInfo(u.userid, u.phone,u.name, u.address, u.info,head.headUrl) "
+ "from AppUser u, HeadUrl head where u.userid = head.userid and"
+ " u.userid = :userid")
UserInfo findUserInfoByUserid(@Param("userid") String userid);
//查询2个表具有同一个userid 的内容,并组成新的对象
@Query(value = "select new com.cxx.beans.UserInfo(u.userid, u.phone,u.name, u.address, u.info,head.headUrl) "
+ "from AppUser u, HeadUrl head where u.userid = head.userid")
List<UserInfo> findUserInfo();
@Query(value = "select u.userid, u.phone,u.name, u.address, u.info,head.headUrl from AppUser u, HeadUrl head"
+ " where u.userid = head.userid and"
+ " u.userid = :userid",nativeQuery = true)
List<Object[]> findUserInfos2(@Param("userid") String userid);
//删除用户,根据name 和city 删除全部匹配的用户
@Modifying
@Transactional
@Query(value="delete from AppUser where name =?1 and city= ?2")
void deleteUser(String name,String city);
//去重查询,查询city 列表
@Query(value="select distinct city from AppUser")
List<String> getCityList();
}
public class UserInfo implements Serializable{
private String userid;
private String phone;
private String name;
private String address;
private String info;
private String headUrl;
public UserInfo()
{
}
public UserInfo(String userid, String phone, String name, String address, String info, String headUrl) {
super();
this.userid = userid;
this.phone = phone;
this.name = name;
this.address = address;
this.info = info;
this.headUrl = headUrl;
}
...
}
findUserInfo 返回的数据结构
{
"userid": "e4d6f4eef48c4408985b65f6997891bb",
"phone": "13760234541",
"name": "张三",
"address": null,
"info": null,
"headUrl": "http://cbc-huanan-image.oss-cn-shenzhen.aliyuncs.com/15337983334421.png"
}
findUserinfos2 返回的数据结构:
[
[
"e4d6f4eef48c4408985b65f6997891bb",
"13760234541",
"张三",
null,
null,
"http://cbc-huanan-image.oss-cn-shenzhen.aliyuncs.com/15337983334421.png"
],
[ ... ]
]
查询到多个去重后,比如我需要查包含密码信息的房间和包含指纹信息的房间,查找结果再去重,得到所有的房间号
//set去重
Set set = new HashSet();
List<String> listNew=new ArrayList<>();
set.addAll(list1);
set.addAll(list2);
listNew.addAll(set);
更正:
我想从 A表(AppUser)中获取一些字段(name ,等), 再根据B表(HeadUrl)中获取一些字段(headUrl),组成查询结果,上面的这个方法,在有一个表中不存在相应的记录是无法得到想要的结果 @Query(value = "select new com.cxx.beans.UserInfo(u.userid, u.phone,u.name, u.address, u.info,head.headUrl) "
+ "from AppUser u, HeadUrl head where u.userid = head.userid and"
+ " u.userid = :userid")
UserInfo findUserInfoByUserid(@Param("userid") String userid);
正确的SQL 查询语句如下:需要用LeftJoin 方式,这样当HeadUrl 中查询内容为空时也能正确返回。
所以正确的查询方法如下,但这个返回的是Object数组,需要根据这个数组内容,再手动转成我们需要的对象
@Query(select u.userid, u.phone,u.name, u.address, u.info, head.headUrl from AppUser u LEFT JOIN HeadUrl head USING(userid) where u.userid = :userid",nativeQuery =true)
List<Object[]> findFriendsByUserid(@Param("userid")String userid);
复杂的查询方式:
- Criteria API 查询;
- QueryByExampleExecutor 实例查询;
Spring JPA方法名解析步骤
- 在进行方法名解析时会先去掉多余的前缀,比如find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析,并且如果方法最后一个参数时 Sort 或 Pageable 类型,也会提取相关信息
- 比如:findByNameLikeAndAgeGreaterThan
- 剔除findBy
- 判断nameLikeAndAgeGreaterThan(根据POJO规范,首字母变小写)是否为返回对象 User 的一个属性,如果是,则根据该属性进行查询,如果没有该属性,则进行下一步
- 从右往左截取第一个大写字母开头的字符串(此处为Than),然后检查剩下的字符串是否为 User 的一个属性,如果是,则根据该属性进行查询,否则重复第2步,直到找出 name 为 User 的属性
- 从已截取的部分后面开始,重新第 1 步开始(剔除条件语句),循环,直到把方法名处理完毕
- 通过获取的操作、条件和属性、带入参数值,生成查询
关键字 | 例子 | 对应的JPQL语句 |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | 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 ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … 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) |
关联外键查询
- 假设有两张表 address与 user
- address表中有一个 user_id 的外键列对应着 user 表的主键
- 若查询条件为 id 为 1 的 address且同时对应 id 为 2 的用户,如下列 SQL 语句:
SELECT a.* FROM address a JOIN user u ON a.user_id = u.id WHERE a.id = 1 AND u.id = 2
- 则使用 _ 来连接关联实体属性查询,上述 SQL 对应的 JPA 方法名为
Address findTopByIdAndUser_Id(int addressId,int userId);
限制查询结果数量
public interface PersonRepository extends JpaRepository<Person,Longs>{
//获得符合查询条件的前30条数据
List<Person>findTop30ByName(String name);
}
通过@query编写创建查询
- 可以通过@Query(若使用nativesql属性,则使用原生的sql语句)注解来创建查询(参数也可用 ?1 ?2 代替,则不需@Param),如:
@Query("select * from User u where u.name like :first and u.age>:age")
List<User> findByNameLikeAndAgeGreaterThan(@Param("first")String firstName,@Param("age")Integer age);
@Modifying
@Transactional
@Query("update User u set u.name = ?1 where u.id = ?2")
public int increaseSalary(String name, int id);
@Modifying
@Transactional
@Query(value="delete from UserShips where userid =?1 and houseNo= ?2")
void deleteByUseridAndHouseNo(String userid ,String houseNo);
- 更新、删除操作需要加上@Transactional @Modifying