最近看mybatis的時候做了一個練習,但是進行事務處理的時候出了問題,如下
package com.henu.lz.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.henu.lz.dao.PersonMapper;
import com.henu.lz.model.Person;
@Controller
public class SupplierController {
@Autowired
PersonMapper personMapper;
@Transactional
@RequestMapping("/add")
public String addPerson(
@RequestParam("name1") String name1,
@RequestParam("age1") int age1,
@RequestParam("name2") String name2,
@RequestParam("age2") int age2,
Model model) {
Person person1 = new Person();
Person person2 = new Person();
person1.setName(name1);
person1.setAge(age1);
person2.setName(name2);
person2.setAge(age2);
personMapper.save(person1);
personMapper.save(person2);
model.addAttribute("message", "添加成功!");
return "success";
}
}
spring容器和springmvc的配置都沒有問題,dao層就是mybatis比較與眾不同的的寫有sql的xml以及接口。在從前台傳值的時候person1正常傳,person2傳能拋SQLException的值,按理說事務應該回滾的,數據庫中不會有person1,但是查看數據庫卻有person1。用的mysql,引擎設置為innodb后還是這樣,換了oracle之后依然如此。這兩次save不在一個事務。
網上看了下別人的經歷,有的是try…catch之后自行處理沒有throw,有的是說設置rollbackFor……有一個比較接近
http://www.iteye.com/topic/714686
用的是 hibernate 3.2,在配置dao和controller的時候都用了注解方式自動掃描
<context:component-scan base-package="com..." />
這樣說是導致dao中事務無效,我試過這樣配置,服務啟動直接就出錯了,很顯然沖突,而且用context:include-filter和context:exclude-filter來屏蔽掉controller層的解決辦法也有點沒必要,分別掃描dao層和controller層不就行了,我是這樣配置的。
查看mybatis官網上的project,是比我多了一層service層,然后在service中用的@transactional,我加了一層
package com.henu.lz.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.henu.lz.dao.PersonMapper;
import com.henu.lz.model.Person;
@Service(value="personService")
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonMapper personMapper;
@Transactional
public void save(Person p1, Person p2) {
personMapper.save(p1);
personMapper.save(p2);
}
}
相應的,controller也修改為
package com.henu.lz.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.henu.lz.model.Person;
import com.henu.lz.service.PersonService;
@Controller
public class SupplierController {
@Resource
private PersonService personService;
@RequestMapping("/add")
public String addPerson(
@RequestParam("name1") String name1,
@RequestParam("age1") int age1,
@RequestParam("name2") String name2,
@RequestParam("age2") int age2,
Model model) {
Person person1 = new Person();
Person person2 = new Person();
person1.setName(name1);
person1.setAge(age1);
person2.setName(name2);
person2.setAge(age2);
personService.save(person1, person2);
model.addAttribute("message", "添加成功!");
return "success";
}
}
這時再按開始那樣傳值能得到預期結果了。
一開始也注意到少了一層service,但是覺得在controller中做同樣的事情也可以的,所以就杯具了。
因為spring的context和mvc是分開的,貌似controller不能被注冊到spring的context中,於是不能被transactionManager攔截,那么controller中那個@transactional就不起作用了。看了聲明式事務的五種配置,都是對注冊到context中的bean起作用的,不論是攔截器方式還是aop:config方式。
事務注解方式不能應用於接口,我的mapper用的又是xml方式的,所以只能加一層service,然后controller中的交易就放在service層。

