Spring 分離をテストするための非常に単純な例を作成しています。私は2つの非常によく似たScheduleクラスを持っています:
@Service("manager1")
public class Manager1 {
private Service1 service1;
@Scheduled(fixedDelay = 15000)
public void sendScheduledCampaigns() {
service1.changeCredits();
}
...
@Service("manager2")
public class Manager2 {
private Service2 service2;
@Scheduled(fixedDelay = 15000)
public void sendScheduledCampaigns() {
service2.changeCredits();
}
...
また、非常によく似たサービス クラスが 2 つあります。
@Service("service1")
@Transactional
public class Service1 {
private UserService userService;
private static Logger log = Logger.getLogger(Service1.class);
public void changeCredits() {
User user = userService.getUserById(1);
log.info("Service1 previous credits: " + user.getCredits());
int newCredit = user.getCredits() + 5;
user.setCredits(newCredit);
log.info("Service1 new credits: " + user.getCredits());
}
...
@Service("service2")
@Transactional
public class Service2 {
private UserService userService;
private static Logger log = Logger.getLogger(Service2.class);
public void changeCredits() {
User user = userService.getUserById(1);
log.info("Service2 previous credits: " + user.getCredits());
int newCredit = user.getCredits() + 5;
user.setCredits(newCredit);
log.info("Service2 new credits: " + user.getCredits());
}
このコードを実行すると、両方のトランザクションが同時に実行されると、両方のトランザクションがデータベースから同じ値を取得していることがわかります。したがって、彼らは他のものの変更を無視しています。これはトランザクション分離のエラーだと思います:
INFO 27 Feb 2014 14:14:22 - Service1 previous credits: 0
INFO 27 Feb 2014 14:14:22 - Service2 previous credits: 0
INFO 27 Feb 2014 14:14:22 - Service1 new credits: 5
INFO 27 Feb 2014 14:14:22 - Service2 new credits: 5
ここで、クレジット値は 10 にする必要があります。
この後、両方のプロセスが同時に実行されていないため、計算は正常に開始されます。
Feb 27, 2014 2:14:23 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Feb 27, 2014 2:14:23 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Feb 27, 2014 2:14:23 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 10698 ms
INFO 27 Feb 2014 14:14:37 - Service2 previous credits: 5
INFO 27 Feb 2014 14:14:37 - Service2 new credits: 10
INFO 27 Feb 2014 14:14:38 - Service1 previous credits: 10
INFO 27 Feb 2014 14:14:38 - Service1 new credits: 15
私は MYSQL を使用しています。これらは私のタスクとトランザクションの構成です。
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="100"/>
<task:scheduler id="myScheduler" pool-size="100"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
<property name="packagesToScan" value="test.domain" />
</bean>
何らかの理由で、私のデフォルトの分離レベルはnullです。私はこれからそれを得ました:
log.info("isolation: " +TransactionSynchronizationManager.getCurrentTransactionIsolationLevel());
そこで、両方のサービスの分離レベルを変更しようとしました:
@Service("service1")
@Transactional(isolation=Isolation.REPEATABLE_READ)
public class Service1 {
@Service("service2")
@Transactional(isolation=Isolation.REPEATABLE_READ)
public class Service2 {
結果はまだ間違っています。
なぜこれが起こっているのかについて何か考えがありますか?
前もって感謝します。