【问题标题】:TransactionRequiredException: Executing an update/delete queryTransactionRequiredException:执行更新/删除查询
【发布时间】:2012-09-01 07:48:38
【问题描述】:

我很难找到解决问题的方法。
我有一个服务类,其中包含一个在登录时设置验证标志的方法。

@Service("userRolesService")
@Repository
@Transactional
public class UserRolesService {
   public void verify() {
       repository.verifyUser();
   }
}

My Repository 是 SpringData CrudRepository,verifyUser 类似于

 @Modifying
 @Query("UPDATE user SET (verified = 1 WHERE verified=0)")
 public void verifyUser();

在单元测试中直接调用代码时,一切正常。通过应用程序从我的身份验证提供程序调用它时,出现以下异常:

javax.persistence.TransactionRequiredException: 执行更新/删除查询

Service 类使用@Autowired 注解注入到我的单元测试和身份验证提供程序中。测试本身没有任何有趣的注解,身份验证提供程序也没有。

我的想法很新鲜,所以如果有人有线索,我将非常感谢。

编辑: 我现在不再调用 verifyUser 更新脚本,而是检索所有未验证的用户,设置已验证标志并使用存储库的 save() 方法。这行得通,但很丑陋,所以我愿意接受更好的建议。

EDIT2:

这里的每个请求是配置的持久性部分,我想这是最相关的,其余的只处理身份验证。此配置用于单元测试和 web 应用程序,唯一的区别是数据源是嵌入式 H2 DB 用于单元测试和 mysql 用于 web 应用程序。

<beans [..]>

    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          depends-on="persistenceInitializer">
        <property name="dataSource" ref="dataSource"/>
        <property name="persistenceUnitName" value="jpa"/>
        <property name="packagesToScan">
            <list>
                <value>com.example.model</value>
            </list>
        </property>
        <property name="jpaVendorAdapter">
            <bean class="com.example.persistence.adapter.ConfigurationRetainingHibernateJpaVendorAdapter">
                <property name="database" value="${spring.hibernate.database}"/>
                <property name="generateDdl" value="${spring.hibernate.generateDdl}"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.DefaultComponentSafeNamingStrategy
                </prop>
            </props>
        </property>
    </bean>

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

    <jpa:repositories base-package="com.example.persistence.repository"/>

    <tx:annotation-driven/>

    <bean id="persistenceInitializer" class="com.example.persistence.init.NoOpInitializer"/>

</beans>

此外,我有一个仅在网络应用程序中的配置,而不是单元测试:

<beans [..]>

    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:application.properties</value>
            </list>
        </property>
    </bean>

    <mvc:annotation-driven/>

    <mvc:default-servlet-handler/>

    <context:annotation-config/>

</beans>

【问题讨论】:

  • 你会发布你的 Spring 配置吗?您的事务后处理器似乎没有找到 bean?
  • 当然,添加了两个配置部分。 Config 被拆分成几个文件,不过大部分应该与这个问题无关。

标签: hibernate jpa spring-mvc


【解决方案1】:

这样使用

@Modifying
    @Transactional 
    @Query(value ="delete from admindata where user_name = :userName AND group_name = :groupName",nativeQuery = true)
    public void deleteadminUser(@Param("userName") String userName,@Param("groupName") String groupName);

【讨论】:

    【解决方案2】:

    我也遇到了同样的问题并通过添加注释解决了@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)
    public class UserRolesService{
    ..........
    }
    

    【讨论】:

    • 您是否设法通过No existing transaction found for transaction marked with propagation 'mandatory'进行宣传
    【解决方案3】:

    我遇到了一些问题,我通过在执行删除或更新的服务方法上添加 @Transactional 注释来解决它。

    【讨论】:

      【解决方案4】:

      - 您的服务类也不应该是存储库

      - 这是您的 applicationContext.xml 的外观:

      <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
          <property name="entityManagerFactory" ref="entityManagerFactory"/>
      </bean>
      <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
      <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
          <property name="persistenceUnitName" value="persistenceUnit"/>
          <property name="dataSource" ref="dataSource"/>
      </bean>
      
      <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
          <property name="driverClassName" value="${database.driverClassName}"/>
          <property name="url" value="${database.url}"/>
          <property name="username" value="${database.username}"/>
          <property name="password" value="${database.password}"/>
          <property name="testOnBorrow" value="true"/>
          <property name="testOnReturn" value="true"/>
          <property name="testWhileIdle" value="true"/>
          <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
          <property name="numTestsPerEvictionRun" value="3"/>
          <property name="minEvictableIdleTimeMillis" value="1800000"/>
          <property name="validationQuery" value="SELECT 1"/>
          <property name="initialSize" value="1"/>
          <property name="minIdle" value="1"/>
          <property name="maxActive" value="10"/>
          <property name="poolPreparedStatements" value="true"/>
          <property name="maxOpenPreparedStatements" value="20"/>
      </bean>
      

      - 下面是单元测试类的定义方式

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(loader=WebContextLoader.class, locations = {"classpath:/META-INF/spring/applicationContext.xml", "classpath:/META-INF/spring/applicationContext-test-override.xml"})
      public class MyTest {
      

      - 注意 applicationContext-test-override.xml 的使用 这用于覆盖上下文中的任何设置以进行测试。这样做意味着您正在测试真实的应用程序上下文,因此如果您在那里犯了错误,它会出现在您的测试中。它应该位于 src/test/resources 中。希望这就是您所需要的:

      <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
          <property name="url" value="${database-test.url}"/>
      </bean>
      

      -(可选)使用 mode=aspectj

      将以下内容添加到 maven 插件中。它在编译时合并方面,而不是运行时(模式=代理)。

              <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>aspectj-maven-plugin</artifactId>
                  <version>1.4</version>
                  <dependencies>
                      <dependency>
                          <groupId>org.aspectj</groupId>
                          <artifactId>aspectjrt</artifactId>
                          <version>${aspectj.version}</version>
                      </dependency>
                      <dependency>
                          <groupId>org.aspectj</groupId>
                          <artifactId>aspectjtools</artifactId>
                          <version>${aspectj.version}</version>
                      </dependency>
                  </dependencies>
                  <executions>
                      <execution>
                          <goals>
                              <goal>compile</goal>
                              <goal>test-compile</goal>
                          </goals>
                          <!-- NB: force aspect compile before normal compile, required for 1.3+ 
                              see: MASPECTJ-13, MASPECTJ-92 -->
                          <phase>process-sources</phase>
                      </execution>
                  </executions>
                  <configuration>
                      <outxml>true</outxml>
                      <aspectLibraries>
                          <aspectLibrary>
                              <groupId>org.springframework</groupId>
                              <artifactId>spring-aspects</artifactId>
                          </aspectLibrary>
                      </aspectLibraries>
                      <source>${java.version}</source>
                      <target>${java.version}</target>
                  </configuration>
              </plugin>
      

      【讨论】:

      • 我将 mode="aspectj" transaction-manager="transactionManager" 添加到我的 tx:annotation-driven 标记后,我的单元测试中也会出现错误。除了对 applcationContext.xml 的更改很有意义之外,我还介绍了这些。尽管如此,异常还是不断出现。
      • 现在可以使用了,非常感谢。史蒂夫的回答被证明是解决方案,但是重新修改我的配置文件是值得的,所以感谢您的输入。没有让 aspectj 注释模式工作,但它在代理模式下工作得很好。
      【解决方案5】:

      我认为如果您将&lt;tx:annotation-driven/&gt; 移动到包含&lt;context:annotation-config/&gt; 的上下文中,那么Spring 会选择您的@Transactional&lt;tx:annotation-driven/&gt; 是一个后处理器,仅在定义它的应用程序上下文中装饰 bean。有关详细说明,请参阅我的回答 here

      【讨论】:

      • 它有效,好像那是我的错误。最后我使用了两个答案,但这似乎是让代码工作的细节,非常感谢:-)
      猜你喜欢
      • 2014-11-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2013-04-18
      • 1970-01-01
      • 2014-09-23
      • 2019-07-16
      • 1970-01-01
      相关资源
      最近更新 更多