【问题标题】:Why Querydsl always requires connection to be transactional?为什么 Querydsl 总是要求连接是事务性的?
【发布时间】:2026-01-04 08:15:02
【问题描述】:

最近我在我的 Spring Boot 应用程序中尝试了一个名为 Querydsl 的数据库访问新工具,这是我在 @Configuration 类中配置上下文的方法:

@Bean
public com.querydsl.sql.Configuration querydslConfiguration() {
    SQLTemplates templates = OracleTemplates.builder().build();
    com.querydsl.sql.Configuration configuration = new com.querydsl.sql.Configuration(templates);
    configuration.setExceptionTranslator(new SpringExceptionTranslator());
    return configuration;
}

@Bean
public SQLQueryFactory queryFactory(DataSource dataSource) {
    Provider<Connection> provider = new SpringConnectionProvider(dataSource);
    return new SQLQueryFactory(querydslConfiguration(), provider);
}

我的查询是一个非常简单的选择:

fun detailedEntityByIds(ids: Set<String>): List<DetailedEntity> {
    val qDetails = QTContainerDetails.tContainerDetails
    return sqlQueryFactory.select(qDetails).from(qDetails)
        .where(qDetails.id.`in`(ids))
        .fetch().map { mapper.qDslEntToModel(it) }
}

然后我遇到的是以下异常:

java.lang.IllegalStateException:连接不是事务性的

我很快找到了这个问题:[QueryDSL/Spring]java.lang.IllegalStateException: Connection is not transactional,并建议使用@Transactional 来解决这个问题。

为什么 Querydsl 要求连接是事务性的?我曾经将@Transactional 放在我真正需要的服务层方法上。现在 Querydsl “强制”我将它放在整个 DAO 类中,因为看起来每个 Querydsl 查询都需要它。

【问题讨论】:

    标签: spring spring-transactions querydsl


    【解决方案1】:

    来自 Javadoc

    /**
     * {@code SpringConnectionProvider} is a Provider implementation which provides a transactionally bound connection
     *
     * <p>Usage example</p>
     * <pre>
     * {@code
     * Provider<Connection> provider = new SpringConnectionProvider(dataSource());
     * SQLQueryFactory queryFactory = SQLQueryFactory(configuration, provider);
     * }
     * </pre>
     */
    

    原因是为了资源管理。您无权访问底层 JDBC 实现。事务将关闭 ResultSets、Statements、Connections 等。如果没有事务,每个连接都会保持打开状态、连接池饱和、数据库资源不足等。

    如果您想管理自己的资源,您可以编写自己的Provider&lt;Connection&gt; 并传入DataSource E.G.

    private static Provider<Connection> getConnection(DataSource dataSource) {
        return () -> org.springframework.jdbc.datasource.DataSourceUtils.getConnection(dataSource);
    }
    

    【讨论】: