1

Is this possible to do?

I have only found sources where they create multiple repositories and multiple Entity classes to perform this. However, I was not able to find any sources showing that you can have 1 Repository class hit different databases.

Basically, I have a DAO class that has read & write methods. I have a Spring Data repository configured for it, and I am trying to set it up so the Read classes hit the Replica DB whereas the Write classes hit the Main DB.

So far, I have been trying by defining two different SpringDataConfig classes for each DB. Like so:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    basePackages = { "repo" },
    entityManagerFactoryRef = "Write",
    transactionManagerRef = "JpaTxnManager_Write")
public class RepositoryConfigSpringDataDbWrite {
}

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    basePackages = { "repo" },
    entityManagerFactoryRef = "Read",
    transactionManagerRef = "JpaTxnManager_Read")
public class RepositoryConfigSpringDataDbRead {
}

Let's call the SpringDataRepository class as EntityRepo. Now, from the DAO class, I am trying to use the @Transactional annotation to point the specific methods to the specific databases, like so:

@Transactional(transactionManager="JpaTxnManager_Read")
public List<Entity> getAllEntitiesById(String id) { 
    return entityRepo.findById(id);
}

Some other method that would call Write would be:

@Transactional(transactionManager="JpaTxnManager_Write")
public List<Entity> getAllEntitiesById(Entity entity) { 
    return entityRepo.save(entity);
}

Any idea if this is possible?

Don Code
  • 781
  • 3
  • 12
  • 25
  • Logically speaking, base on your configuration, you are trying to instantiate the same repositories twice, and I doubt that is possible. Plus, let's assume that is possible, when you call the "getAllEntitiesById" how is gonna decided on which repository to call ? – Vladucu Voican Jan 06 '20 at 18:57

1 Answers1

3

Instead of trying to use force the one bean to perform two potentially conflicting behaviors, you could create two beans extending the singular Jpa interface with separate packages to perform two behaviors. This ensures that, even if a developer forgot the annotation in future Dao methods, there is an explicit request for either a read-only or write repo in your Dao.

Original JPA repository:

public interface EntityRepository extends CrudRepository<Entity, Long> { }

Reconfigure your database configurations to repo.readonly, and repo.write

In repo.readonly:

public interface EntityReadOnlyRepository extends EntityRepository { }

In a repo.write:

public interface EntityWriteRepository extends EntityRepository { }

You can then autowire both repos with their respective configuration into your service.

@Autowired
EntityReadOnlyRepository entityReadOnlyRepository;

@Autowired
EntityWriteRepository entityWriteRepository;

I assume you have data locks on read-only to prevent write, but you could also do custom Impl behavior to throw exceptions for save calls in your read interface.

Compass
  • 5,867
  • 4
  • 30
  • 42
  • So would the SpringData configurations i provided above still work for this? Or would I have to wire them differently? – Don Code Jan 06 '20 at 19:07
  • @DonCode you would just need to change the base packages from `repo` to `repo.readonly` and `repo.write` to reduce chance of crossing wires. Then, wire the read-only repo to the read-only config, and write to write. Wiring two JPA configs to the same packages as you've currently provided might caused an Unresolved Bean Ref because there's two possible beans for the repos. – Compass Jan 06 '20 at 19:10
  • Are there any sources to wire the Repo class to a specific config? – Don Code Jan 06 '20 at 19:17
  • @DonCode https://www.baeldung.com/spring-data-jpa-multiple-databases should get you on the right track – Compass Jan 06 '20 at 19:34
  • This one is creating different entities...what if I am dealing with the same entity?! My guess is that would work. – Don Code Jan 06 '20 at 20:50
  • It should still work. You would just have two Repos with the same Entity mappings. – Compass Jan 06 '20 at 21:39