Search code examples
springjpaquerydsl

spring querydsl I don't want start a transaction


Entity:

package com.test.entity

@Entity
@Table(name="TEST_TABLE")
public class TestTable implements HasMapping, PrimaryKey<Long>, Serializable {
public static final String TABLE_NAME = "TEST_TABLE";

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="ID", nullable=false)
    private Long id;

    @Id
    @Column(name="Name", nullable=false)
    private String name;

    @Temporal(value=TemporalType.TIMESTAMP)
    @Column(name="CREATE_TIME", nullable=true)
    @CreatedDate
    private Date createTime;

    @Column(name="CREATE_USER", nullable=true, length=32)
    @CreatedBy
    private String createUser;

    @Temporal(value=TemporalType.TIMESTAMP)
    @Column(name="LST_UPD_TIME", nullable=true)
    @LastModifiedDate
    private Date lstUpdTime;

    @Column(name="LST_UPD_USER", nullable=true, length=32)
    @LastModifiedBy
    private String lstUpdUser;

    @Column(name="JPA_VERSION", nullable=false)
    @Version
    private Integer jpaVersion;
    ......
}

QPath

package com.test.qpath

@Generated("com.mysema.query.codegen.EntitySerializer")
public class QTestTable extends EntityPathBase<TestTable> {

    private static final long serialVersionUID = -1751805455;

    public static final QTestTable testTable = new QTestTable("testTable");

    public final NumberPath<Long> id = createNumber("id", Long.class);

    public final DateTimePath<java.util.Date> createTime = createDateTime("createTime", java.util.Date.class);

    public final StringPath createUser = createString("createUser");

    public final NumberPath<Integer> jpaVersion = createNumber("jpaVersion", Integer.class);

    public final DateTimePath<java.util.Date> lstUpdTime = createDateTime("lstUpdTime", java.util.Date.class);

    public final StringPath lstUpdUser = createString("lstUpdUser");

    public QTestTable(String variable) {
        super(TestTable.class, forVariable(variable));
    }

    @SuppressWarnings("all")
    public QTestTable(Path<? extends TestTable> path) {
        super((Class)path.getType(), path.getMetadata());
    }

    public QTestTable(PathMetadata<?> metadata) {
        super(TestTable.class, metadata);
    }
    ......
}

Repository

package com.test.repos

public interface RTestTable extends JpaRepository<TestTable, Long>, QueryDslPredicateExecutor<TestTable> {
}

Service

package com.test.service

@Service
public class TestServiceR() {
    @Autowired
    private RTestTable rTestTable;
    public void handler() {
        long id = 1;
        TestTable t = rTestTable.findone(id);
    }
}


package com.test.service

@Service
public class TestServiceQuery() {
    @Autowired
    private RTestTable rTestTable;
    @PersistenceContext
    private EntityManager em;
    private QTestTable qTestTable = QTestTable.testTable;
    public void handler() {
        long id = 1;
        JPAQuery query = new JPAQuery(em);
        TestTable t = query.from(qTestTable).where(qTestTable.id.eq(id)).singleResult(qTestTable);
    }
}

spring config

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="#{env.jdbcUrl}" />
    <property name="username" value="#{env.jdbcUsername}" />
    <property name="password" value="#{env.jdbcPassword}" />
    <property name="initialSize" value="1" />
    <property name="minIdle" value="#{env['jdbcMinIdle'] ?: 2 }" />
    <property name="maxActive" value="#{env['jdbcMaxActive'] ?: 20}" />
    <property name="minEvictableIdleTimeMillis" value="#{env['jdbcMinEvictableIdleTimeMillis'] ?: 1800000}" />
    <property name="validationQuery" value="#{env['jdbcTestSql']}" />
    <property name="testWhileIdle" value="#{env['jdbcTestWhileIdle']?: false}" />
    <property name="testOnBorrow" value="#{env['jdbcTestOnBorrow']?: true}" />
    <property name="testOnReturn" value="#{env['jdbcTestOnReturn']?: false}" />
    <property name="poolPreparedStatements" value="false" />
    <property name="maxPoolPreparedStatementPerConnectionSize" value="-1" />
    <property name="filters" value="mergeStat,slf4j" />
    <property name="connectionProperties" value="druid.stat.slowSqlMillis=1500;druid.stat.logSlowSql=true" />
    <property name="timeBetweenLogStatsMillis" value="900000" />
</bean>
<bean id="emf"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceUnitName" value="default" />
    <property name="packagesToScan">
        <list>
            <value>com.sunline.ccs.infrastructure.shared.model</value>
        </list>
    </property>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="#{env['jpaDatabaseType']?:'DEFAULT'}" />
            <property name="showSql" value="#{env['jpaShowSql']?:false}" />
        </bean>
    </property>
</bean>

<bean id="sessionFactory" factory-bean="emf" factory-method="getSessionFactory" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf" />
</bean>

<tx:annotation-driven mode="aspectj"
    transaction-manager="transactionManager" />

<jpa:repositories base-package="com.test.repos" />

I test TestServiceR.handler() and TestServiceQuery.handler(). I think they don't start a transaction. but class TestServiceR are start a transaction. why? how can i set TestServiceR.handler() don't start a transaction.


Solution

  • TestServiceR calls RTestTable.findOne which extends JpaRepository, which is implemented by SimpleJpaRepository, which is annotated with @Transactional(readOnly = true). So, the transaction is started by SimpleJpaRepository.

    Is there a particular reason why you are worried about the transaction, given that it does not affect the application adversely (at least not much)? See the comment history for this Spring Data JPA JIRA issue if you are not convinced.

    If you still want to override the default behaviour, you can initialise JPA repositories as @EnableJpaRepositories(enableDefaultTransactions = false) (Java configuration) or <jpa:repositories enable-default-transactions="false" ... /> (XML configuration) to prevent the default implementation from creating transactions by default. See this Spring Data JPA JIRA issue for more details.