1

I have configured a Micronaut application with two MySQL databases but it always performs operations with default datasource.

How can I work with multiple databases?

Here is my application.yml configuration:

datasources:
  default:
      url: jdbc:mysql://localhost:3306/micronaut_demo
      username: root
      password: goti@181994
      dialect: MYSQL
  target:
      url: jdbc:mysql://localhost:3306/micronaut_demo_target
      username: root
      password: goti@181994
      dialect: MYSQL
jpa:
  default:
    packages-to-scan:
      - 'com.example'
    properties:
      hibernate:
        hbm2ddl:
          auto: create-drop
        show_sql: true
  target:
    properties:
      hibernate:
        hbm2ddl:
          auto: create-drop
        show_sql: true

And here is my Repository declaration:

@Singleton
@Repository("target")
public class DepartmentRepositoryImpl implements  DepartmentRepository {
    private EntityManager entityManager;

    public DepartmentRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    @ReadOnly
    public Optional<Department> findById(Long id) {
        return Optional.ofNullable(entityManager.find(Department.class, id));
    }

    @Override
    @Transactional
    public Department save(String name) {
        //save logic
    }
}

As you can see, I specified the datasource to use with:

@Repository("target")
tmarwen
  • 15,750
  • 5
  • 43
  • 62
umesh
  • 155
  • 1
  • 9
  • Could you please add the `DepartmentRepository ` declaration? And how are you calling the `DepartmentRepositoryImpl` repository bean? Could you add the caller snippet? – tmarwen Apr 11 '21 at 14:59
  • Thanks for your reply, DepartmentRepository is just interface, with only declared methods. i am calling these methods as normal as we do, by injecting DepartmentRepository. – umesh Apr 12 '21 at 14:56

1 Answers1

0

You can annotate your @Repository beans with @EachBean annotation specifying EntityManager as the dependent type allowing for Microanut to create a bean per each created EntityManager (and each DataSource under the hood):

@EachBean(EntityManager.class)
@Repository
public class DepartmentRepositoryImpl implements  DepartmentRepository {

    private EntityManager entityManager;

    public DepartmentRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    @ReadOnly
    public Optional<Department> findById(Long id) {
        return Optional.ofNullable(entityManager.find(Department.class, id));
    }

    @Override
    @Transactional
    public Department save(String name) {
        //save logic
    }
}

You can then inject a qualified DepartmentRepository based on the needed target DataSource:

@Singleton
public class ServiceImpl implements Service {

    private DepartmentRepository departmentRepository;

    public ServiceImpl(@Named("target") DepartmentRepository departmentRepository) {
        this.departmentRepository = departmentRepository;
    }

    @Override
    public Department save(String name) {
        return this.departmentRepository.save(name);
    }
}

Or dynamically using an injected ApplicationContext:

@Singleton
public class ServiceImpl implements Service {

    private ApplicationContext applicationContext;

    public ServiceImpl(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Department save(String name) {
        return this.save(name, "default");
    }

    public Department save(String name, String targetDataSource) {
        return this.applicationContext.getBean(DepartmentRepository.class, Qualifiers.byName(target)).save(name);
    }
}
tmarwen
  • 15,750
  • 5
  • 43
  • 62