Loading Spring context and its consequences

Let’s say we have an application trying to insert a row on some table. Using Spring JDBC techniques, we must define one Spring XML context file as next.






  




  

  

  

  

  

  


We can define too a class in order to simplify the process of getting transactions and DAOs from Spring Context. Below two alternatives are shown: DBManager class and StaticDBManager class.

DBManager is coded in a dynamic way…

public class DBManager {

  private ClassPathResource resource;
  private XmlBeanFactory xmlFactory;

  public DBManager() {
    resource = new ClassPathResource("/es/foo/db/spring-config.xml", DBManager.class);
        xmlFactory = new XmlBeanFactory(resource);
  }

  public JdbcDaoSupport getDAO(String daoName) {
        DataSource dataSource = (DataSource)xmlFactory.getBean("datasource");
        JdbcDaoSupport dao = (JdbcDaoSupport)xmlFactory.getBean(daoName);
        dao.setDataSource(dataSource);
        return dao;
  }

  public TransactionTemplate getTransactionTemplate() {
    return (TransactionTemplate)xmlFactory.getBean("transactionTemplate");
  }

}

… while StaticDBManager is coded in a static way.

public class StaticDBManager {

  public static JdbcDaoSupport getDAO(String daoName) {
    ClassPathResource resource = new ClassPathResource("/es/foo/db/spring-config.xml", StaticDBManager.class);
    XmlBeanFactory xmlFactory = new XmlBeanFactory(resource);
    DataSource dataSource = (DataSource)xmlFactory.getBean("datasource");
    JdbcDaoSupport dao = (JdbcDaoSupport)xmlFactory.getBean(daoName);
    dao.setDataSource(dataSource);
    return dao;
  }

  public static TransactionTemplate getTransactionTemplate() {
    ClassPathResource resource = new ClassPathResource("/es/foo/db/spring-config.xml", StaticDBManager.class);
    XmlBeanFactory xmlFactory = new XmlBeanFactory(resource);
    return (TransactionTemplate)xmlFactory.getBean("transactionTemplate");
  }

}

Without thinking of it deeply, we can imagine both solutions working in the same way.

public class SpringDBTest {

  class DoWork implements TransactionCallback {

    private DBManager db;

    public DoWork(DBManager db) {
      this.db = db;
    }

    public Object doInTransaction(TransactionStatus ts) {
      SomeDAO someDAO = (SomeDAO) db.getDAO("someDAO");
      someDAO.insert();
      return null;
    }

  }

  public static void main(String... args) throws Exception {

    // Test 1 - Load Spring Context once
    DBManager db = new DBManager();
    TransactionTemplate ttDynamic = db.getTransactionTemplate();
    ttDynamic.execute(new SpringDBTest().new DoWork(db));

    // Test 2 - Load Spring Context statically twice
    TransactionTemplate ttStatic = StaticDBManager.getTransactionTemplate();
    ttStatic.execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus ts) {
        try {
          SomeDAO someDAO = (SomeDAO) StaticDBManager.getDAO("someDAO");
          someDAO.insert();
        } catch (RuntimeException re) {
          ts.setRollbackOnly();
          re.printStackTrace();
        }
        return null;
      }
    });

  }

}

However, running the code, no rollback is performed on Runtime Exception for Test 2.

This behavior is caused by Spring Context load in StaticDBManager class. Doing the initialization so, two different instances of datasource object are generated (one for the transaction and another one for the DAO) due to Spring Injection mechanism. So, in Test 2, transactional context is lost on execution.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s