spring配置事务的三种方式:编程式、声明式、注解式
1、配置事务
要实现注解式的事务配置,只需在applicationContext.xml中加入如下代码:
<!-- 配置事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="txManager" />
只需在业务层中添加@Transaction方法即可使用事务
@Transaction
只能用到 public 方法上,对于其他非 public 方法,标记了 @Transaction 也不会报错,但方法没有事务功能<!-- mybatis.spring自动映射,会扫描org.mybatis.spring.sample.mapper下的所有接口,然后创建各自接口的动态代理类 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.mycompany.web.entity.mapping"/> </bean> <!-- 自动扫描,多个包以 逗号分隔,让Bean定义注解工作起来 --> <context:component-scan base-package="com.mycompany.web"/> <aop:aspectj-autoproxy proxy-target-class="true"/>如果此时报错,是因为文件头没有引入xmlns和schema导致的,在文件头引入即可,只需引入需要的
2、单个事务测试场景:
插入一个User对象的集合,如果插入对象的个数小于2,则正常插入;如果试图插入5条数据(对象的个数大于2),则抛出异常(事务必处理必须抛出异常,只有这样,spring才能帮助事务回滚),这样,数据库就会回滚,不插入任何数据。测试结果,如果数据库没插入任何数据,证明事务处理设置成功,否则,失败。测试业务类方法的代码如下:
@Service("userService") public class UserServiceImpl implements IUserService{ @Resource private IUserDao userDaoImpl; @Transactional @Override publicvoid Amethod(List<User> userList){ for(int i=0;i<userList.size();i++){ if(i<<span style="color:#ff0000;background-color: rgb(255, 255, 255);">2</span>){ this.userDaoImpl.insert(userList.get(i)); }else{ thrownew RuntimeException(); } } } }
由于单元测试没有成功,将测试代码放入Controller方法中,走页面跳转:
@RequestMapping("/index") public String getUserById(Model model){ List<User> userList = new ArrayList<User>(); for(int i=0;i<5;i++){ User userTemp = new User(); userTemp.setId(i+2L); userTemp.setAge(i); userTemp.setName("xiaohong" + i); userTemp.setGender("女"); userList.add(userTemp); } userService.insertUser(userList); return "MyJsp"; }运行成功后打开访问页面, 会出现错误,因为方法中抛出了这个异常。实质上是进行了事务管理,数据库没有插入数据,表示事务配置成功;反之,如果方法上去掉 @Transaction ,则前两条数据会插入到数据库中,然后报异常。
参考出处忘记了。
3、多个事务测试场景:
场景一:在2的基础上再加一个实体UserRole,同样的方式测试业务类中加入方法:
@Transactional @Override public void Bmethod(List<UserRole> userRoleList){ <span style="white-space:pre"> </span>for(int i=0;i<userRoleList.size();i++){ <span style="white-space:pre"> </span>if(i<<span style="color:#ff0000;">2</span>){ <span style="white-space:pre"> </span>this.userRoleDaoImpl.insertSelective(userRoleList.get(i)); }else{ <span style="white-space:pre"> </span>throw new RuntimeException(); } } }在Controller类的方法getUserById中加入如下代码:
List<UserRole> userRoleList = new ArrayList<UserRole>(); for(int i=0;i<5;i++){ UserRole userRoleTemp = new UserRole(); userRoleTemp.setRoleId(i+1L); userRoleTemp.setUserId(i+1L); userRoleTemp.setCreateUserId(i+1L); userRoleTemp.setCreateTime(new Date()); userRoleList.add(userRoleTemp); } userRoleService.insertUserRole(userRoleList);运行后,发现两个事务是单独生效并且都生效的
场景二:那么再修改一下,在Amethod中调用Bmethod方法,在controller中调用A方法,问:此时生效的事务是A还是B还是A和B的事务都生效?
结果:
1)当A、B都满足条件时(即条件为插入数据小于2条,而试图插入的数据个数也小于2条),才成功保存数据并且全部数据都成功保存;
2)当A不满足条件或B不满足条件或A和B都不满足条件时,全部回滚,所有数据都保存失败,并抛出异常。