简体   繁体   中英

Spring transaction by connecting to multiple databases

I am trying to work on a small program where I can connect to multiple databases using Spring and trying to use Spring transactions by deploying my web-application on weblogic server. The problem is that the transaction management is not working properly. I am trying to insert records in 2 databases, the first one inserts without throwing any exceptions, where as the second insert query is written such that it throws an exception. Ideally in this situation the transaction should rollback but the first transaction is committed without any issues.

Here is my spring-config.xml file

<context:component-scan base-package="com.examples" />

<!-- Database1 -->

<bean id="db1DataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/mydb1" />
    <property name="username" value="root" />
    <property name="password" value="" />
</bean>

<!-- Database2 -->

<bean id="db2DataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/mydb2" />
    <property name="username" value="root" />
    <property name="password" value="" />
</bean>

<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
        value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix">
        <value>/WEB-INF/views/</value>
    </property>
    <property name="suffix" value=".jsp" />
</bean>

This is my controller:

@Controller
public class EmployeeController {

    @Autowired
    private CommonEmployeeService commonService;

    @RequestMapping(value = "/employee", method = GET)
    public String showPersonListForGivenAge(
            @RequestParam(value = "id") int id,
            @RequestParam(value = "name") String name,
            @RequestParam(value = "email") String email,
            Map<String, Object> model) {

        Employee e = new Employee(id,name);
        EmployeeDetails details = new EmployeeDetails(id,email);

        commonService.insert(e, details);

        return "welcome";
    }
}

This is my common service:

@Service
public class CommonEmployeeService {

    @Autowired
    EmployeeDetailsService detailsService;

    @Autowired
    EmployeeService service;


    @Transactional
    public boolean insert(Employee e, EmployeeDetails details) {
        service.insert(e);
        detailsService.insert(details);
        return true;
    }
}

These are my other services:

EmployeeService.java

@Service

public class EmployeeService {

    @Autowired
    EmployeeDao dao;

    //@Transactional(propagation=Propagation.REQUIRED)
    public boolean insert(Employee e) {
        return dao.insert(e);
    }
}

EmployeeDetailsService.java -- The DAO in this service throws NullPointerException

@Service
public class EmployeeDetailsService {

    @Autowired
    EmployeeDetailsDao dao;

    //@Transactional(propagation=Propagation.REQUIRED)
    public boolean insert(EmployeeDetails e) {
        return dao.insert(e);
    }

}

Update: Adding Dao Classes:

EmployeeDao.java:

@Repository
public class EmployeeDao {

    JdbcTemplate template;

    @Resource(name = "db1DataSource")
    public void setDataSource(DataSource dataSource) {
        this.template = new JdbcTemplate(dataSource);
    }

    public boolean insert(Employee e) {
        int cnt = template.update("insert into Employee values(?,?)",
                e.getId(), e.getName());
        if (cnt > 0) {
            return true;
        }
        return false;
    }
}

EmployeeDetailsDao.java

@Repository
public class EmployeeDetailsDao {

    JdbcTemplate template;

    @Resource(name = "db2DataSource")
    public void setDataSource(DataSource dataSource) {
        this.template = new JdbcTemplate(dataSource);
    }

    public boolean insert(EmployeeDetails e) {
        if(e != null){
            throw new NullPointerException();   
        }

        int cnt = template.update("insert into EmployeeDetails values(?,?)",
                e.getId(), e.getEmail());
        if (cnt > 0) {
            return true;
        }
        return false;
    }
}

Try adding below in spring-config.xml :

<context:component-scan base-package=“your.packagename.contatining.EmployeeDetailsDao” />
<mvc:annotation-driven />

and changing @Transactional in your CommonEmployeeService with @Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED) as below

@Service
public class CommonEmployeeService {

    @Autowired
    EmployeeDetailsService detailsService;

    @Autowired
    EmployeeService service;

@Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
    public boolean insert(Employee e, EmployeeDetails details) {
        service.insert(e);
        detailsService.insert(details);
        return true;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM