spring Data jpa坑爹Bug

一 起源

由於新公司項目是使用 spring data jpa ,因此就使用一下這個jpa. 在測試寫原生SQL,啓動項目(springboot項目),報了一個錯了,下面張貼報錯內容

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException: Cannot use native queries with dynamic sorting and/or pagination in method public abstract org.springframework.data.domain.Page cn.magicwindow.demo.dao.UserRepository.findByAppName(java.lang.String,org.springframework.data.domain.Pageable)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:592) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1219) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1131) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:589) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
	... 19 common frames omitted

一看這個就知道jpa 這個方法寫的有問題。下面粘貼UserRepository方法代碼:

@Query(value="SELECT * FROM USER u LEFT JOIN app a ON u.app_id = a.id WHERE a.`name` = ?1 "
           ,countQuery="SELECT count(*) FROM USER u LEFT JOIN app a ON u.app_id = a.id WHERE a.`name` = ?1", nativeQuery = true)
    Page<User>  findByAppName(String appName , Pageable pageable);

調用UserRepository方法的代碼:

public Page<User> findByCondition(){

        Pageable pageable = new PageRequest(1,10);
        Page<User>  user =  userRepository.findByAppName("ELEX_APP",pageable);

        return user;
    }

二 解決方法

這個代碼我也沒有發現什麼錯誤啊。然後通過各種查詢找到了答案 需要sql加上

ORDER BY ?#{#pageable}

正確的代碼

@Query(value="SELECT * FROM USER u LEFT JOIN app a ON u.app_id = a.id WHERE a.`name` = ?1 ORDER BY ?#{#pageable}"
           ,countQuery="SELECT count(*) FROM USER u LEFT JOIN app a ON u.app_id = a.id WHERE a.`name` = ?1", nativeQuery = true)
    Page<User>  findByAppName(String appName , Pageable pageable);

三 源代碼解釋

對於這個問題很無奈 所以找源碼

public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
   super(method, em, queryString, evaluationContextProvider, parser);
   JpaParameters parameters = method.getParameters();
   boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter();
   boolean containsPageableOrSortInQueryExpression = queryString.contains("#pageable") || queryString.contains("#sort");
   if(hasPagingOrSortingParameter && !containsPageableOrSortInQueryExpression) {
       throw new InvalidJpaQueryMethodException("Cannot use native queries with dynamic sorting and/or pagination in method " + method);
   }
}
從源碼上一目瞭然 如果SQL中沒有 #pageable 而 參數中有 Pageable就會報錯。

是不是很坑爹 畢竟jpa案例就沒有啊。https://docs.spring.io/spring-data/jpa/docs/1.10.2.RELEASE/reference/html/

案例截圖:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章