La Carbonell de Plats Bruts La Carbonell de Plats Bruts -4 years ago 120
Java Question

Spring @Transactional read-only

I have a basic SpringBoot app. using Spring Initializer, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file

With this dependency

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>


I've created this service declared as readOnly:

@Service
@Transactional(readOnly = true)
public class TimeLapseService {

@Autowired
TimeLapseRepository timeLapseRepository;

public Set<TimeLapse> findAllByCompanyId(long companyId) {
return timeLapseRepository.findAllByCompanyId(companyId);
}

public Iterable<TimeLapse> findAll (User user) {

if (user.isAdmin()) {
return timeLapseRepository.findAll();
} else {
return timeLapseRepository.findAllByCompanyId(user.getCompany().getId());
}

}

public void createTimeLapse (TimeLapse timeLapse) {
timeLapseRepository.save (timeLapse);
}

}


and

public interface TimeLapseRepository extends CrudRepository<TimeLapse, Long> {
....
}


As far as I know, since the service is declared as readonly, creating a new service shouldn't persist anything to the DB, but it creates a row in the TABLE

timeLapseService.createTimeLapse(timeLapse24h);


JPA properties:

spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
hibernate.dialect=org.hibernate.dialect.H2Dialect

Answer Source

BeanS call a transactional=read-only Bean1, which does a lookup and calls transactional=read-write Bean2 which saves a new object.

> Bean1 starts a read-only tx. 31 09:39:44.199 [pool-1-thread-1] DEBUG
> o.s.orm.jpa.JpaTransactionManager - Creating new transaction with name
> [nz.co.vodafone.wcim.business.Bean1.startSomething]:
> PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''

> 
> Bean 2 pariticipates in it. 31 09:39:44.230 [pool-1-thread-1] DEBUG
> o.s.orm.jpa.JpaTransactionManager - Participating in existing
> transaction
> 

Nothing is committed to the database.

Now change Bean2 @Transactional annotation to add propagation=Propagation.REQUIRES_NEW

> Bean1 starts a read-only tx. 31 09:31:36.418 [pool-1-thread-1] DEBUG
> o.s.orm.jpa.JpaTransactionManager - Creating new transaction with name
> [nz.co.vodafone.wcim.business.Bean1.startSomething]:
> PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
> 
> Bean2 starts a new read-write tx 31 09:31:36.449 [pool-1-thread-1]
> DEBUG o.s.orm.jpa.JpaTransactionManager - Suspending current
> transaction, creating new transaction with name

Unless you make as below it would be persisted

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void createTimeLapse (TimeLapse timeLapse)
   { 
    timeLapseRepository.save (timeLapse); 
   } 
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download