0

I have a springboot application, with its own datasource (let's call DB1) set on properties working fine.

But this application needs do configure a new datasource (DB2), using some parameters the user have informed before and stored in DB1.

My idea is to create a named bean, so a specific part of my application can use to access DB2 tables. I think it is possible to do that by restarting the application, but I would like to avoid it though.

Besides, I need that some part of my code use the new datasource (spring data jpa, mappings, and so on). I don't know if this matter, but it is a web application, so I cannot create the datasource only for the request thread.

Can you help me?

Thanks in advance.

1
  • I found a solution injecting the first EntityManager to get the connection parameters and using a @PostConstruct annotation to create the second datasource. The only problem with this approach is that I need to restart the application if the parameters are not correct. Commented Nov 29, 2016 at 12:26

1 Answer 1

1

Spring has dynamic datasource routing if that's where you are headed. In my case it is the same schema (WR/RO)

public class RoutingDataSource extends AbstractRoutingDataSource {

  @Autowired
  private DataSourceConfig dataSourceConfig;

  @Override
  protected Object determineCurrentLookupKey() {
    return DbContextHolder.getDbType();
  }

  public enum DbType {
    MASTER, WRITE, READONLY,  
  }

Then you need a custom annotation and an aspect

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyConnection {
}

@Aspect 
@Component
@Order(1)
public class ReadOnlyConnectionInterceptor {

  Pointcut(value = "execution(public * *(..))")
  public void anyPublicMethod() {}

  @Around("@annotation(readOnlyConnection)")
  public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable           {
    Object result = null;
    try {
      DbContextHolder.setDbType(DbType.READONLY);
      result = proceedingJoinPoint.proceed();
      DbContextHolder.clearDbType();
      return result;
    } finally {
      DbContextHolder.clearDbType();
    }
  }
}

And then you can act on you DB with the tag @ReadOnlyConnection

@Override
@Transactional(readOnly = true)
@ReadOnlyConnection
public UnitDTO getUnitById(Long id) {
  return unitRepository.findOne(id);
}

An example can be found here: https://github.com/afedulov/routing-data-source.

I used that as a basis for my work although it is still in progress because I still need to resolve runtime dependencies ( i.e. hibernate sharding ).

Sign up to request clarification or add additional context in comments.

2 Comments

Please don't provide link-only answers, links may get broken and the answer becomes irrelevant. Put most important bits to your post directly.
Agreed. Added example behavior with full source link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.