詳解Java的MyBatis框架中的事務(wù)處理
一、MyBatis單獨(dú)使用時(shí),使用SqlSession來(lái)處理事務(wù):
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); // 打開(kāi)會(huì)話,事務(wù)開(kāi)始
try {
IUserMapper mapper = session.getMapper(IUserMapper.class);
User user = new User(9, "Test transaction");
int affectedCount = mapper.updateUser(user); // 因后面的異常而未執(zhí)行commit語(yǔ)句
User user = new User(10, "Test transaction continuously");
int affectedCount2 = mapper.updateUser(user2); // 因后面的異常而未執(zhí)行commit語(yǔ)句
int i = 2 / 0; // 觸發(fā)運(yùn)行時(shí)異常
session.commit(); // 提交會(huì)話,即事務(wù)提交
} finally {
session.close(); // 關(guān)閉會(huì)話,釋放資源
}
}
}
二、和Spring集成后,使用Spring的事務(wù)管理:
一個(gè)使用MyBatis-Spring的主要原因是它允許MyBatis參與到Spring的事務(wù)管理中。而不是給MyBatis創(chuàng)建一個(gè)新的特定的事務(wù)管理器,MyBatis-Spring利用了存在于Spring中的DataSourceTransactionManager。
一旦DataSourceTransactionManager配置好了,你可以在Spring中以你通常的做法來(lái)配置事務(wù)。@Transactional注解和AOP樣式的配置都是支持的。在事務(wù)處理期間,一個(gè)單獨(dú)的SqlSession對(duì)象將會(huì)被創(chuàng)建和使用。當(dāng)事務(wù)完成時(shí),這個(gè)session會(huì)以合適的方式提交或回滾。
一旦事務(wù)創(chuàng)建之后,MyBatis-Spring將會(huì)透明的管理事務(wù)。在你的DAO或Service類中就不需要額外的代碼了。
1.標(biāo)準(zhǔn)配置
要開(kāi)啟Spring的事務(wù)處理,在Spring的XML配置文件中簡(jiǎn)單創(chuàng)建一個(gè)DataSourceTransactionManager對(duì)象:
<bean id="transactionManager" class="org.springframework.jdbc.datasource .DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
指定的DataSource一般可以是你使用Spring的任意JDBC DataSource。這包含了連接池和通過(guò)JNDI查找獲得的DataSource。
要注意,為事務(wù)管理器指定的DataSource必須和用來(lái)創(chuàng)建SqlSessionFactoryBean的是同一個(gè)數(shù)據(jù)源,否則事務(wù)管理器就無(wú)法工作了。
2.容器管理事務(wù)
如果你正使用一個(gè)JEE容器而且想讓Spring參與到容器管理事務(wù)中,那么Spring應(yīng)該使用JtaTransactionManager或它的容器指定的子類來(lái)配置。做這件事情的最方便的方式是用Spring的事務(wù)命名空間:
<tx:jta-transaction-manager/>
在這種配置中,MyBatis將會(huì)和其它由容器管理事務(wù)配置的Spring事務(wù)資源一樣。Spring會(huì)自動(dòng)使用任意存在的容器事務(wù),在上面附加一個(gè)SqlSession。 如果沒(méi)有開(kāi)始事務(wù),或者需要基于事務(wù)配置,Spring會(huì)開(kāi)啟一個(gè)新的容器管理事務(wù)。
注意,如果你想使用容器管理事務(wù),而不想使用Spring的事務(wù)管理,你就必須配置SqlSessionFactoryBean來(lái)使用基本的MyBatis的ManagedTransactionFactory而不是其它任意的Spring事務(wù)管理器:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="transactionFactoryClass">
<value>org.apache.ibatis.transaction.managed.ManagedTransactionFactory"/>
</property>
</bean>
3.編程式事務(wù)管理
MyBatis的SqlSession提供指定的方法來(lái)處理編程式的事務(wù)。但是當(dāng)使用MyBatis-Spring時(shí),bean將會(huì)使用Spring管理的SqlSession或映射器來(lái)注入。那就是說(shuō)Spring通常是處理事務(wù)的。你不能在Spring管理的SqlSession上調(diào)用SqlSession.commit(),SqlSession.rollback()或SqlSession.close()方法。如果這樣做了,就會(huì)拋出UnsupportedOperationException異常。注意在使用注入的映射器時(shí)不能訪問(wèn)那些方法。無(wú)論連接是否設(shè)置為自動(dòng)提交,SqlSession數(shù)據(jù)方法的執(zhí)行或在Spring事務(wù)之外任意調(diào)用映射器方法都將會(huì)自動(dòng)被提交。下面是一個(gè)編程式事務(wù)示例:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try{
userMapper.insertUser(user);
}catch(MyException ex){
throw ex;
}
txManager.commit(status);
4.@Transactional方式:
在類路徑下創(chuàng)建beans-da-tx.xml文件,在beans-da.xml(系列五)的基礎(chǔ)上加入事務(wù)配置:
<!-- 事務(wù)管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 事務(wù)注解驅(qū)動(dòng),標(biāo)注@Transactional的類和方法將具有事務(wù)性 -->
<tx:annotation-driven transaction-manager="txManager" />
<bean id="userService" class="com.john.hbatis.service.UserService" />
服務(wù)類:
@Service("userService")
public class UserService {
@Autowired
IUserMapper mapper;
public int batchUpdateUsersWhenException() { // 非事務(wù)性
User user = new User(9, "Before exception");
int affectedCount = mapper.updateUser(user); // 執(zhí)行成功
User user2 = new User(10, "After exception");
int i = 1 / 0; // 拋出運(yùn)行時(shí)異常
int affectedCount2 = mapper.updateUser(user2); // 未執(zhí)行
if (affectedCount == 1 && affectedCount2 == 1) {
return 1;
}
return 0;
}
@Transactional
public int txUpdateUsersWhenException() { // 事務(wù)性
User user = new User(9, "Before exception");
int affectedCount = mapper.updateUser(user); // 因后面的異常而回滾
User user2 = new User(10, "After exception");
int i = 1 / 0; // 拋出運(yùn)行時(shí)異常,事務(wù)回滾
int affectedCount2 = mapper.updateUser(user2); // 未執(zhí)行
if (affectedCount == 1 && affectedCount2 == 1) {
return 1;
}
return 0;
}
}
在測(cè)試類中加入:
@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();
}
}
5.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) { // 事務(wù)操作
User user = new User(9, "Before exception");
int affectedCount = mapper.updateUser(user); // 因后面的異常而回滾
User user2 = new User(10, "After exception");
int i = 1 / 0; // 拋出運(yùn)行時(shí)異常并回滾
int affectedCount2 = mapper.updateUser(user2); // 未執(zhí)行
if (affectedCount == 1 && affectedCount2 == 1) {
return 1;
}
return 0;
}
});
return retVal;
}
在SpringIntegrateTxTest類中加入:
@Test
public void updateUsersWhenExceptionViaTxTemplateTest() {
userService.txUpdateUsersWhenExceptionViaTxTemplate(); //
}
注:不可catch Exception或RuntimeException而不拋出:
@Transactional
public int txUpdateUsersWhenExceptionAndCatch() { // 事務(wù)性操作,但是外圍框架捕獲不到異常,認(rèn)為執(zhí)行正確而提交。
try {
User user = new User(9, "Before exception");
int affectedCount = mapper.updateUser(user); // 執(zhí)行成功
User user2 = new User(10, "After exception");
int i = 1 / 0; // 拋出運(yùn)行時(shí)異常
int affectedCount2 = mapper.updateUser(user2); // 未執(zhí)行
if (affectedCount == 1 && affectedCount2 == 1) {
return 1;
}
} catch (Exception e) { // 所有異常被捕獲而未拋出
e.printStackTrace();
}
return 0;
}
- 詳解Java的JDBC API中事務(wù)的提交和回滾
- Java 事務(wù)詳解及簡(jiǎn)單應(yīng)用實(shí)例
- Java Spring 事務(wù)回滾詳解
- 在Java的JDBC使用中設(shè)置事務(wù)回滾的保存點(diǎn)的方法
- 深入解析Java中的JDBC事務(wù)
- Java事務(wù)的個(gè)人理解小結(jié)
- Java與Oracle實(shí)現(xiàn)事務(wù)(JDBC事務(wù))實(shí)例詳解
- java事務(wù)回滾失敗問(wèn)題分析
- Java基于JDBC實(shí)現(xiàn)事務(wù),銀行轉(zhuǎn)賬及貨物進(jìn)出庫(kù)功能示例
- Java使用jdbc連接MySQL數(shù)據(jù)庫(kù)實(shí)例分析
- Java實(shí)現(xiàn)的mysql事務(wù)處理操作示例
相關(guān)文章
基于Rest的API解決方案(jersey與swagger集成)
下面小編就為大家?guī)?lái)一篇基于Rest的API解決方案(jersey與swagger集成)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
springboot之security?FilterSecurityInterceptor的使用要點(diǎn)記錄
SpringSecurity默認(rèn)登錄頁(yè)的使用示例教程

