Spring Data Jpa 的简单查询多表查询HQL,SQL查询总结

基本知识:

  • 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

猜你喜欢

转载自blog.csdn.net/xqt8888/article/details/81607387