I have a service with one method:

```
    @Service
    public class DefaultTestService implements TestService {
        private static final Logger LOGGER = Logger.getLogger(DefaultTestService.class);
        @Autowired
        private TestRepository testRepository;

        @Transactional(readOnly = false, isolation = Isolation.SERIALIZABLE)
        @Override
        public void incrementAndGet(Long testModelId) {
            LOGGER.debug("Transaction is active: " + TransactionSynchronizationManager.isActualTransactionActive());
            final TestModel tm = testRepository.findOne(testModelId);
            if (tm != null) {
                LOGGER.debug("Updated " + testModelId + " from value: " + tm.getValue());
                tm.setValue(tm.getValue() + 1);
                testRepository.save(tm);
            } else {
                LOGGER.debug("Saved with id: " + testModelId);
                final TestModel ntm = new TestModel();
                ntm.setId(testModelId);
                testRepository.save(ntm);
            }
       }
    }

```

And I'm running Gatling with 2 parallel calls config with `testModelId = 1L` argument. 
As a result of these calls I'm getting error:

```
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "test_model_pkey"

```

What I can see from logs is that two calls have entered this method at once and each printed log

```
"Saved with id: 1"
"Saved with id: 1"

```

I assumed that adding transaction annotation on this method would block one of the calls on the line `testRepository.findOne(testModelId)` until other call finishes its execution, but as I can see from logs it's working in a different way.

So my question is how transaction works in this case when concurrent access appears? And how can I handle this case with concurrent access?