最近看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層。