14

問題の解決策を見つけるのに苦労しています。
ログイン時に検証フラグを設定するメソッドを含むサービス クラスがあります。

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

私のリポジトリはSpringData CrudRepositoryで、verifyUserは次のようなものです

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

単体テストでコードを直接呼び出すと、すべて正常に動作します。アプリケーションを介して認証プロバイダーから呼び出すと、次の例外が発生します。

javax.persistence.TransactionRequiredException: 更新/削除クエリの実行

@Autowiredサービス クラスは、アノテーションを使用して、単体テストと認証プロバイダーの両方に挿入されます。テスト自体には興味深いアノテーション自体はなく、認証プロバイダーにもありません。

私はアイデアが足りないので、誰かが手がかりを持っていれば、とても感謝しています.

編集: verifyUser 更新スクリプトを呼び出す代わりに、検証されていないすべてのユーザーを取得し、検証済みフラグを設定して、リポジトリの save() メソッドを使用します。それは機能しますが、非常に醜いので、より良い提案を受け入れます。

EDIT2:

リクエストごとに、ここに構成の永続性部分があります。これが最も関連性が高いと思います。残りは認証のみを扱います。この構成は単体テストと Web アプリの両方で使用されます。唯一の違いは、データソースが単体テスト用の H2 DB と Web アプリ用の mysql が埋め込まれていることです。

<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>

さらに、単体テストではなく、Web アプリのみにある構成があります。

<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>
4

5 に答える 5

9

<tx:annotation-driven/>を含むコンテキストに移動すると<context:annotation-config/>、Springがを取得すると思います@Transactional。は<tx:annotation-driven/>、それが定義されているアプリケーションコンテキストでのみBeanを装飾するポストプロセッサです。詳細については、ここで私の回答を参照してください。

于 2012-09-07T16:25:40.987 に答える
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 プラグインに追加します。実行時ではなく、コンパイル時にアスペクトを組み込みます (mode=proxy)。

        <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>
于 2012-09-08T09:23:09.990 に答える
4

いくつかの問題があり、削除または更新を実行するサービス メソッドに @Transactional アノテーションを追加するだけで解決しました。

于 2017-07-10T19:16:26.883 に答える
3

このように使う

@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);
于 2019-09-11T10:03:28.447 に答える
2

私も同じ問題に直面し、アノテーション@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)を追加することで解決しました

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)
public class UserRolesService{
..........
}
于 2017-08-18T05:40:45.030 に答える