简体   繁体   中英

Spring boot, jms listener and database transaction

I have 2 records in database because locally created and saved entity wasn't found in a different thread.

My configuration is like this:

@Configuration
@EnableJms
@EnableJpaRepositories
public class MyConfiguration {

@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory(ConnectionFactory connectionFactory,
                                                                  DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    factory.setRecoveryInterval(5000);
    factory.setSessionTransacted(true);
    return factory;
}

}

and this, application.properties:

java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
spring.jms.jndi-name=jms/MyCF
spring.jms.listener.concurrency=5
spring.jms.listener.acknowledge-mode=auto
spring.jms.template.receive-timeout=5000

spring.datasource.jndi-name=jdbc/MyDataSource

spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.generate-ddl=false

And I have MyEntity entity with sequence generator

@Getter
@Setter
@Entity
@Table(name = "MY_ENTITY")
public class MyEntity {
@Id
@Column(name = "ID", nullable = false, precision = 0)
@SequenceGenerator(name="SqName", sequenceName="SQ_ID", allocationSize = 1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SqName")
private long id;
@Basic
@Column(name = "NAME", nullable = true, length = 4000)
private String name;

Then I have my JMS listener:

@JmsListener(destination="jms/MyQueue")
public void onMessage(Message message) throws Exception {
    myService.save(myRepository.findOneByName("name1"));
}

Then I have a MyService class:

@Service
MyServiceImpl implements MyService {
    save(MyEntity myEntity) {
        if(myEntity == null) myEntity = new MyEntity();
        myEntity.setName("name1");
        // do something
        myRepository.save(myEntity);
    }
}

What happened that in one line and one thread newly created entity was saved in myRepository (locally, not yet in DB) and in the next line in a different thread when it called again save method, it didn't find an entity with name "name1" so at the end I had 2 records in the database with "name1".

myRepository.findOneByName("name1") = null;

So, should I add @Transactional annotation to save method in MyServicImpl class or to JmsListener?

I mean, I had @Transactional in save method in MyServiceImpl class and it never happened but maybe it was just by coincidence.

Also, should I add JtaTransactionManager in configuration?

this is concurrent change of the same name of the entitiy,consider the optimistic locking

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM