myBatis系列之七:事务管理

myBatis系列之一:搭建开发环境

myBatis系列之二:以接口方式交互数据

myBatis系列之三:增删改查

myBatis系列之四:关联数据的查询

myBatis系列之五:与Spring3集成

myBatis系列之六:与SpringMVC集成

1.myBatis单独使用时,使用SqlSession来处理事务:

public class MyBatisTxTest {

	private static SqlSessionFactory sqlSessionFactory;
	private static Reader reader;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		try {
			reader = Resources.getResourceAsReader("Configuration.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
		} finally {
			if (reader != null) {
				reader.close();
			}
		}
	}
	
	@Test
	public void updateUserTxTest() {
		SqlSession session = sqlSessionFactory.openSession(false); // 打开会话,事务开始
		
		try {
			IUserMapper mapper = session.getMapper(IUserMapper.class);
			User user = new User(9, "Test transaction");
			int affectedCount = mapper.updateUser(user); // 因后面的异常而未执行commit语句
			User user = new User(10, "Test transaction continuously");
			int affectedCount2 = mapper.updateUser(user2); // 因后面的异常而未执行commit语句
			int i = 2 / 0; // 触发运行时异常
			session.commit(); // 提交会话,即事务提交
		} finally {
			session.close(); // 关闭会话,释放资源
		}
	}
}

2.和Spring集成后,使用Spring的事务管理:

a.@Transactional方式:

在类路径下创建beans-da-tx.xml文件,在beans-da.xml(系列五)的基础上加入事务配置:

<!-- 事务管理器 -->
  <bean id="txManager"
  	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  		<property name="dataSource" ref="dataSource" />
  </bean>
  
  <!-- 事务注解驱动,标注@Transactional的类和方法将具有事务性 -->
  <tx:annotation-driven transaction-manager="txManager" />

  <bean id="userService" class="com.john.hbatis.service.UserService" />

服务类:

@Service("userService")
public class UserService {

	@Autowired
	IUserMapper mapper;

	public int batchUpdateUsersWhenException() { // 非事务性
		User user = new User(9, "Before exception");
		int affectedCount = mapper.updateUser(user); // 执行成功
		User user2 = new User(10, "After exception");
		int i = 1 / 0; // 抛出运行时异常
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
		return 0;
	}

	@Transactional
	public int txUpdateUsersWhenException() { // 事务性
		User user = new User(9, "Before exception");
		int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
		User user2 = new User(10, "After exception");
		int i = 1 / 0; // 抛出运行时异常,事务回滚
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
		return 0;
	}
}

在测试类中加入:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:beans-da-tx.xml" })
public class SpringIntegrateTxTest {

	@Resource
	UserService userService;

	@Test
	public void updateUsersExceptionTest() {
		userService.batchUpdateUsersWhenException();
	}

	@Test
	public void txUpdateUsersExceptionTest() {
		userService.txUpdateUsersWhenException();
	}
}

b.TransactionTemplate方式

在beans-da-tx.xml中添加:

<bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">
  	<constructor-arg type="org.springframework.transaction.PlatformTransactionManager" ref="transactionManager" />
  </bean>

在UserService类加入:

@Autowired(required = false)
TransactionTemplate txTemplate;

public int txUpdateUsersWhenExceptionViaTxTemplate() {
	int retVal = txTemplate.execute(new TransactionCallback<Integer>() {

		@Override
		public Integer doInTransaction(TransactionStatus status) { // 事务操作
			User user = new User(9, "Before exception");
			int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
			User user2 = new User(10, "After exception");
			int i = 1 / 0; // 抛出运行时异常并回滚
			int affectedCount2 = mapper.updateUser(user2); // 未执行
			if (affectedCount == 1 && affectedCount2 == 1) {
				return 1;
			}
			return 0;
		}
		
	});
	return retVal;
}

在SpringIntegrateTxTest类中加入:

@Test
public void updateUsersWhenExceptionViaTxTemplateTest() {
	userService.txUpdateUsersWhenExceptionViaTxTemplate(); // 
}

注:不可catchException或RuntimeException而不抛出

@Transactional
public int txUpdateUsersWhenExceptionAndCatch() { // 事务性操作,但是外围框架捕获不到异常,认为执行正确而提交。
	try {
		User user = new User(9, "Before exception");
		int affectedCount = mapper.updateUser(user); // 执行成功
		User user2 = new User(10, "After exception");
		int i = 1 / 0; // 抛出运行时异常
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
	} catch (Exception e) { // 所有异常被捕获而未抛出
		e.printStackTrace();
	}
	return 0;
}

相关推荐