title: Spring Boot transaction w/ Sybase & Oracle
body: <p>I'm trying to setup a Spring boot app which feature 2 datasources - one for Sybase and one for oracle. </p>
  
  <p>I set them up like this in Application.class:</p>
  
  <pre><code>@Primary
      @Bean(name="oracleDatasource")
      @ConfigurationProperties(prefix="oracle")
      public DataSource oracleDataSource()  {
          return DataSourceBuilder.create().build();
      }
  
      @Primary
      @Bean(name="oracleJdbcTemplate")
      @Autowired
      JdbcTemplate oracleJdbcTemplate (@Qualifier("oracleDatasource") DataSource dataSource) {
          return new JdbcTemplate(dataSource);
      }
  
      @Bean(name="sybaseDatasource")
      @ConfigurationProperties(prefix="sybase")
      public DataSource sybaseDataSource()  {
          DataSource ds =  DataSourceBuilder.create().build();
  
          try {
              DatabaseMetaData meta = ds.getConnection().getMetaData();
              System.out.println(meta.getDriverName());
          } catch (SQLException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          return ds;
      }
  
      @Bean(name="sybaseJdbcTemplate")
      @Autowired
      JdbcTemplate sybaseJdbcTemplate (@Qualifier("sybaseDatasource") DataSource dataSource) {
          return new JdbcTemplate(dataSource);
      }
  </code></pre>
  
  <p>I added that meta data part in the Sybase one to confirm that when Spring boot launches, it successfully gets a Connection and prints out driver name. Working good so far.</p>
  
  <p>However when I call a method from my controller which features a @Transaction, the Spring transaction interceptor seems to try and create the data source for Sybase over again, and fails with null pointer on the driver name. It doesn't make any sense!</p>
  
  <pre><code>java.lang.NullPointerException: null
      at java.lang.Class.forName0(Native Method)
      at java.lang.Class.forName(Class.java:264)
      at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:657)
      at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:430)
      at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204)
      at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
      at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:439)
      at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
      at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
  ... rest omitted
  </code></pre>
  
  <p>Why would it do that, and how do I fix this?</p>
  
  <p>The basic chain of calls is:</p>
  
  <p>Controller:</p>
  
  <pre><code>@RestController
  public class BlahBlahController {
  
  @Autowired
      private BlahBlahDelegate delegate=null;
  
  @RequestMapping("blah")
      public Object doBlahBlah() {
  
          return delegate.doBlahBlah();
   }
  </code></pre>
  
  <p>Delegate:</p>
  
  <pre><code>@Component
      public class BlahBlahDelegate {
  
      @Autowired
          private BlahBlahDao dao=null;
  
  @Transactional
  public Object doBlahBlah() {
    // does some other stuff
    return dao.doBlahBlah();
  }
  </code></pre>
  
  <p>Dao:</p>
  
  <pre><code>@Repository
  public class BlahBlahDao {
  
  @Autowired
      ApplicationContext context;
  
  private JdbcTemplate getJdbcTemplate(String datasourceName) throws IAPBusinessException {
  
          if (datasourceName.equals("oracle")) {
              return (JdbcTemplate)context.getBean("oracleJdbcTemplate");
          } else if (datasourceName.equals("Sybase")) {
              return (JdbcTemplate)context.getBean("sybaseJdbcTemplate");
          } else 
              throw new IAPBusinessException("No datasource with ID "+datasourceName+" exists");
      }
  
  @Transactional
  public Object doBlahBlah() {
    JdbcTemplate jdbc = getJdbcTemplate("oracle");
    jdbc.update("blah blah");
    return something;
  }
  </code></pre>
  
  <p>So that sums it up. There is no other autowiring or referencing to those datasources or the jdbc templates, so why is the transaction interceptor trying seemingly to instatiate another Sybase BasicDataSource when it was already done during app launch? And why does it do it when the Sybase data source is not even being called upon to actually do anything? </p>