Question

I try to write a transaction manager using JDBC in Spring.

my app-servlet.xml

<!-- JDBC Config -->
<bean   id="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" 
        p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.databaseurl}" 
        p:username="${jdbc.username}" 
        p:password="${jdbc.password}" />

<!-- dataSource TransactionManager -->
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="UserDAOImpl" class="com.project.dao.impl.UserDAOImpl">
    <property name="transactionManager" ref="transactionManager"/>
</bean>

my UserDAOImpl.java

public class UserDAOImpl implements UserDAO {

//transaction manager
private DataSourceTransactionManager transactionManager;
private JdbcTemplate jdbcTemplate;

public UserDAOImpl() {
    super();
    DataSource dataSource = transactionManager.getDataSource();
    jdbcTemplate = new JdbcTemplate(dataSource);
}

public void setTransactionManager(DataSourceTransactionManager transactionManager)    {
    this.transactionManager = transactionManager;
}
....
}

Even though I have transactionManager Bean in my app-servlet, UserDAOImpl won't be instatiated because transactionManager is null. Probably I miss some point but couldn't find out what is wrong.

Was it helpful?

Solution

You should use constructor injection for your transaction manager. Spring is going to call the constructor before it can inject the transactionManager property.

 public UserDAOImpl() 
 {
    /* Transaction Manager NOT set yet */
    DataSource dataSource = transactionManager.getDataSource();
 }

Change it to use constructor injection

 public UserDAOImpl(TransactionManager transactionManager) ...

Then configuration

 <bean id="UserDAOImpl" class="com.project.dao.impl.UserDAOImpl">
   <constructor-arg ref="transactionManager"/>
 </bean>

OTHER TIPS

If you are using spring with annotations, this should work

@Repository
public class UserDAOImpl implements UserDAO{

@Autowired
private DataSourceTransactionManager transactionManager;

private JdbcTemplate jdbcTemplate;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

and you can do away with this line in the configuration

<bean id="UserDAOImpl" class="com.project.dao.impl.UserDAOImpl">
<property name="transactionManager" ref="transactionManager"/>
</bean>

instead do a component scan:

<!-- Scans within the base package of the application for @Components to configure as beans -->
<context:component-scan base-package="${your package}" />

You can refer more on this in the documentation. If you aren't using annotations change the release version in the URL of the given link to the one you are using. That has enough enough examples to do the same without annotations.

Do you have a properties file or other ways in which these variables are being initilaized

p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.databaseurl}" 
        p:username="${jdbc.username}" 
        p:password="${jdbc.password}"

These are place-holders and will need values, for example in this link

There is a properties file called jdbc.properties that is defining the data for driver-class name etc.

Here is the sample source code for the example

You could also modify obtaining jdbcTemplate:

public void setTransactionManager(DataSourceTransactionManager transactionManager)    {
  this.transactionManager = transactionManager;
  DataSource dataSource = transactionManager.getDataSource();
  jdbcTemplate = new JdbcTemplate(dataSource);
} 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top