【问题标题】:Querydsl fetchCount() & fetch() NullPointerException, Connection is closedQuerydsl fetchCount() & fetch() NullPointerException, Connection is closed
【发布时间】:2021-07-23 04:54:18
【问题描述】:

我的目标是在分页、排序和过滤中实现 dao 方法。对于分页,我需要先计数,然后设置偏移量和限制并获取结果(所以从数据库中只获取一个“页面”):

@Slf4j
@Repository
public class UserJdbcRepository {

    private final SQLQueryFactory queryFactory;

    @Autowired
    public UserJdbcRepository(DataSource dataSource) {
        Configuration configuration = new Configuration(new OracleTemplates());
        configuration.setExceptionTranslator(new SpringExceptionTranslator());
        this.queryFactory = new SQLQueryFactory(configuration, dataSource);
    }

    public Page<User> findAll(BooleanExpression predicate, Pageable pageable) {
        QUser u = new QUser("u");

        SQLQuery<Tuple> sql = queryFactory
                .select(u.userId, // omitted)
                .from(u)
                .where(predicate);

        long count = sql.fetchCount();
        List<Tuple> results = sql.fetch();
        // Conversion List<Tuple> to List<User> omitted
        return new PageImpl<>(users, pageable, count);
    }
}

fetchCount() 执行正确,但是 fetch() 抛出 NullPointerException:

java.lang.NullPointerException: null
at com.querydsl.sql.AbstractSQLQuery.fetch(AbstractSQLQuery.java:502) ~[querydsl-sql-4.4.0.jar:na]

从调试中我发现根本原因在 com.querydsl.sql.AbstractSQLQuery:

java.sql.SQLException: Connection is closed

如果我创建第二个(与第一个相同)查询 sql2,那么它正在工作(当然):

SQLQuery<Tuple> sql2 = queryFactory
            .select(... // same as first one)


long count = sql.fetchCount();
List<Tuple> results = sql2.fetch();

我的问题是在调用 fetchCount() 之后连接是否应该真正关闭?还是我配置错误?

我有 SpringBoot 2.4.5;弹簧数据公共 2.5.0; Oracle驱动ojdbc8 21.1.0.0;查询DSL 4.4.0

    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-sql</artifactId>
        <version>${querydsl.version}</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-sql-spring</artifactId>
        <version>${querydsl.version}</version>
        <scope>compile</scope>
    </dependency>

    <plugin>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-maven-plugin</artifactId>
            <version>${querydsl.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>export</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <jdbcDriver>oracle.jdbc.OracleDriver</jdbcDriver>
                <jdbcUrl>jdbc:oracle:thin:@//localhost:1521/XE</jdbcUrl>
                <jdbcUser>user</jdbcUser>
                <jdbcPassword>password</jdbcPassword>
                <sourceFolder>${project.basedir}/src/main/java</sourceFolder>
                <targetFolder>${project.basedir}/src/main/java</targetFolder>
                <packageName>org.project.backend.repository.querydsl</packageName>
                <schemaToPackage>true</schemaToPackage>
                <schemaPattern>project</schemaPattern>
                <tableNamePattern>
                    // omitted
                </tableNamePattern>
            </configuration>    
    <plugin>

【问题讨论】:

    标签: spring-boot jdbc querydsl


    【解决方案1】:

    问题是由配置错误引起的。 QueryDSL doc 包含 Spring 集成部分,其中提到必须使用 SpringConnectionProvider。所以我改变了我的构造函数,它现在按预期工作:

    @Autowired
    public UserJdbcRepository(DataSource dataSource) {
        Configuration configuration = new Configuration(new OracleTemplates());
        configuration.setExceptionTranslator(new SpringExceptionTranslator());
    
        // wrong: this.queryFactory = new SQLQueryFactory(configuration, dataSource);
    
        Provider<Connection> provider = new SpringConnectionProvider(dataSource);
        this.queryFactory = new SQLQueryFactory(configuration, provider);
    }
    

    我还发现有一个有用的方法 fetchResults() 包含用于分页目的的计数(因此不需要显式调用 fetchCount()):

        public Page<User> findAll(BooleanExpression predicate, Pageable pageable) {
        QUser u = new QUser("u");
    
        SQLQuery<Tuple> sql = queryFactory
                .select(u.userId, // omitted)
                .from(u)
                .where(predicate);
    
        sql.offset(pageable.getOffset());
        sql.limit(pageable.getPageSize());
    
        QueryResults<Tuple> queryResults = sql.fetchResults();
        long count = queryResults.getTotal();
        List<Tuple> results = queryResults.getResults();
        // Conversion List<Tuple> to List<User> omitted
        return new PageImpl<>(users, pageable, count);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-05-04
      • 1970-01-01
      • 1970-01-01
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-08
      相关资源
      最近更新 更多