【问题标题】:[QueryDSL/Spring]java.lang.IllegalStateException: Connection is not transactional[QueryDSL/Spring]java.lang.IllegalStateException:连接不是事务性的
【发布时间】:2015-12-10 10:06:23
【问题描述】:

我正在编写 Spring+Vaadin 应用程序。我想添加 QueryDSL 来访问数据库(Oracle)。我查看了文档 (http://docs.spring.io/spring-data/jdbc/docs/current/reference/html/core.querydsl.html) 并读到 Spring 建议使用标准 QueryDSL api。我将以下依赖项添加到我的项目中:

<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-sql-spring</artifactId>
    <version>${querydsl.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-sql</artifactId>
    <version>${querydsl.version}</version>
</dependency>

我的beans.xml如下:

<bean id="dataSourceOracle" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db.oracle.driverClassName}" />
    <property name="url" value="${db.oracle.url}"/>
    <property name="username" value="${db.oracle.username}" />
    <property name="password" value="${db.oracle.password}" />
    <property name="defaultAutoCommit" value="false" />
</bean>

在我的DatabaseFacade 实现中,我做了以下配置:

private SQLQueryFactory query;

@Autowired
@Qualifier("DataSource")
public void setDataSource(DataSource dataSource) {
    Provider<Connection> provider = new SpringConnectionProvider(dataSource);
    Configuration configuration = new Configuration(new OracleTemplates());
    configuration.setExceptionTranslator(new SpringExceptionTranslator());
    query = new SQLQueryFactory(configuration, provider);
}

不幸的是,每次我启动应用程序时都会收到:

10:29:54.490 [main] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
10:29:56.231 [main] ERROR c.r.i.k.b.impl.DatabaseFacadeImpl - Error happend in com.roche.icc.kps.backend.impl.DatabaseFacadeImpl.getEditableKPSStores
10:29:56.234 [main] ERROR c.r.i.k.b.impl.DatabaseFacadeImpl - Connection is not transactional
java.lang.IllegalStateException: Connection is not transactional
    at com.mysema.query.sql.spring.SpringConnectionProvider.get(SpringConnectionProvider.java:45) ~[querydsl-sql-spring-3.7.0.jar:na]
    at com.mysema.query.sql.spring.SpringConnectionProvider.get(SpringConnectionProvider.java:33) ~[querydsl-sql-spring-3.7.0.jar:na]
    at com.mysema.query.sql.SQLQueryFactory.query(SQLQueryFactory.java:63) ~[querydsl-sql-3.7.0.jar:na]
    at com.mysema.query.sql.SQLQueryFactory.query(SQLQueryFactory.java:28) ~[querydsl-sql-3.7.0.jar:na]
    at com.mysema.query.sql.AbstractSQLQueryFactory.from(AbstractSQLQueryFactory.java:54) ~[querydsl-sql-3.7.0.jar:na]

有人遇到过这个问题吗?我应该使用不同的DataSource(Atomikos 吗?)?

感谢您的帮助!

卡米尔

【问题讨论】:

    标签: java spring querydsl transactional


    【解决方案1】:

    我遇到了同样的问题。

    问题在于 QueryDSL 期望数据源连接处于事务中。所以要么你必须明确地开始事务并处理它,要么 IOC 容器应该为你做这件事。

    在这种情况下,您很可能在任何应该启动事务的应用程序层(服务/存储库)中都没有 @Transactional 注释。

    向您的 dao 或服务层添加 @Transactional 注释以解决问题。

    帮助我的链接是 https://groups.google.com/forum/#!topic/querydsl/_PqMek79TZE

    一个示例项目。 https://github.com/querydsl/querydsl/tree/master/querydsl-examples/querydsl-example-sql-spring

    更新

    这就是示例项目中的 DaoImpl 的方式。
    注意类级别的@Transactional 注解。

    @Transactional
    public class CustomerDaoImpl implements CustomerDao {
    
    @Inject
    SQLQueryFactory queryFactory;
    
    final QBean<CustomerAddress> customerAddressBean = bean(CustomerAddress.class,
            customerAddress.addressTypeCode, customerAddress.fromDate, customerAddress.toDate,
            bean(Address.class, address.all()).as("address"));
    
    final QBean<Customer> customerBean = bean(Customer.class,
            customer.id, customer.name,
            bean(Person.class, person.all()).as("contactPerson"),
            GroupBy.set(customerAddressBean).as("addresses"));
    
    @Override
    public Customer findById(long id) {
        List<Customer> customers = findAll(customer.id.eq(id));
        return customers.isEmpty() ? null : customers.get(0);
    }
    
    @Override
    public List<Customer> findAll(Predicate... where) {
        return queryFactory.from(customer)
            .leftJoin(customer.contactPersonFk, person)
            .leftJoin(customer._customer3Fk, customerAddress)
            .leftJoin(customerAddress.addressFk, address)
            .where(where)
            .transform(GroupBy.groupBy(customer.id).list(customerBean));
    }
    
    @Override
    public Customer save(Customer c) {
        Long id = c.getId();
    
        if (id == null) {
            id = queryFactory.insert(customer)
                    .set(customer.name, c.getName())
                    .set(customer.contactPersonId, c.getContactPerson().getId())
                    .executeWithKey(customer.id);
            c.setId(id);
        } else {
            queryFactory.update(customer)
                .set(customer.name, c.getName())
                .set(customer.contactPersonId, c.getContactPerson().getId())
                .where(customer.id.eq(c.getId()))
                .execute();
    
            // delete address rows
            queryFactory.delete(customerAddress)
                .where(customerAddress.customerId.eq(id))
                .execute();
        }
    
        SQLInsertClause insert = queryFactory.insert(customerAddress);
        for (CustomerAddress ca : c.getAddresses()) {
            if (ca.getAddress().getId() == null) {
                ca.getAddress().setId(queryFactory.insert(address)
                    .populate(ca.getAddress())
                    .executeWithKey(address.id));
            }
            insert.set(customerAddress.customerId, id)
                .set(customerAddress.addressId, ca.getAddress().getId())
                .set(customerAddress.addressTypeCode, ca.getAddressTypeCode())
                .set(customerAddress.fromDate, ca.getFromDate())
                .set(customerAddress.toDate, ca.getToDate())
                .addBatch();
        }
        insert.execute();
    
        c.setId(id);
        return c;
    }
    
    @Override
    public long count() {
        return queryFactory.from(customer).fetchCount();
    }
    
    @Override
    public void delete(Customer c) {
        // TODO use combined delete clause
        queryFactory.delete(customerAddress)
            .where(customerAddress.customerId.eq(c.getId()))
            .execute();
    
        queryFactory.delete(customer)
            .where(customer.id.eq(c.getId()))
            .execute();
    }
    
    }
    

    在您的情况下,注释应放置在您的 DatabaseFacade 实现中。我假设您的 Spring 应用程序也配置了事务管理器。

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    • 更新了答案以包含链接中的基本部分。
    【解决方案2】:

    我遇到了这个问题,可以像下面这样解决这个问题:

    除了你应该为你的 dao/Repository 类标记@Transactional 注解之外,你还必须为你的 spring java config 类标记@EnableTransactionManagement,就像下面一样

    @Configuration
    @EnableTransactionManagement
    public class QuerydslConfiguration {
        @Bean
        public DataSource dataSource() {
            // implement your datasource
        }
    
        @Bean
        @Qualifier("transactionManager")
        public PlatformTransactionManager transactionManager() {
            return new DataSourceTransactionManager(dataSource());
        }
    
        @Bean
        public com.querydsl.sql.Configuration initConfiguration() {
            // check the spring integration section
        }
    
        @Bean
        public SQLQueryFactory queryFactory() {
            // check the spring integration section
        }
    }
    
    @Repository
    @Transactional
    public class PaymentDAO {
    }
    

    spring integration section

    您也可以在 spring 上下文 xml 中声明EnableTransactionManagement
    &lt;tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-24
      • 2013-01-09
      • 2023-04-05
      • 2018-11-05
      • 2020-09-06
      • 1970-01-01
      • 2018-01-31
      相关资源
      最近更新 更多