详解Java的MyBatis框架中的事务处理

网友投稿 336 2023-07-15


详解Java的MyBatis框架中的事务处理

一、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 affectedCounhttp://t2 = mapper.updateUser(user2); // 因后面的异常而未执行commit语句

int i = 2 / 0; // 触发运行时异常

session.commit(); // 提交会话,即事务提交

} finally {

session.close(); // 关闭会话,释放资源

}

}

}

二、和Spring集成后,使用Spring的事务管理:

一个使用MyBatis-Spring的主要原因是它允许MyBatis参与到Spring的事务管理中。而不是给MyBatis创建一个新的特定的事务管理器,MyBatis-Spring利用了存在于Spring中http://的DataSourceTransactionManager。

一旦DataSourceTransactionManager配置好了,你可以在Spring中以你通常的做法来配置事务。@Transactional注解和AOP样式的配置都是支持的。在事务处理期间,一个单独的SqlSession对象将会被创建和使用。当事务完成时,这个session会以合适的方式提交或回滚。

一旦事务创建之后,MyBatis-Spring将会透明的管理事务。在你的DAO或Service类中就不需要额外的代码了。

1.标准配置

要开启Spring的事务处理,在Spring的XML配置文件中简单创建一个DataSourceTransactionManager对象:

指定的DataSource一般可以是你使用Spring的任意JDBC DataSource。这包含了连接池和通过JNDI查找获得的DataSource。

要注意,为事务管理器指定的DataSource必须和用来创建SqlSessionFactoryBean的是同一个数据源,否则事务管理器就无法工作了。

 

2.容器管理事务

如果你正使用一个JEE容器而且想让Spring参与到容器管理事务中,那么Spring应该使用JtaTransactionManager或它的容器指定的子类来配置。做这件事情的最方便的方式是用Spring的事务命名空间:

在这种配置中,MyBatis将会和其它由容器管理事务配置的Spring事务资源一样。Spring会自动使用任意存在的容器事务,在上面附加一个SqlSession。 如果没有开始事务,或者需要基于事务配置,Spring会开启一个新的容器管理事务。

注意,如果你想使用容器管理事务,而不想使用Spring的事务管理,你就必须配置SqlSessionFactoryBean来使用基本的MyBatis的ManagedTransactionFactory而不是其它任意的Spring事务管理器:

org.apache.ibatis.transaction.managed.ManagedTransactionFactory"/>

3.编程式事务管理

MyBatis的SqlSession提供指定的方法来处理编程式的事务。但是当使用MyBatis-Spring时,bean将会使用Spring管理的SqlSession或映射器来注入。那就是说Spring通常是处理事务的。你不能在Spring管理的SqlSession上调用SqlSession.commit(),SqlSession.rollback()或SqlSession.close()方法。如果这样做了,就会抛出UnsupportedOperationException异常。注意在使用注入的映射器时不能访问那些方法。无论连接是否设置为自动提交,SqlSession数据方法的执行或在Spring事务之外任意调用映射器方法都将会自动被提交。下面是一个编程式事务示例:

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方式:

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

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

服务类:

@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(locatiohttp://ns = { "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中添加:

&leMeZKt;/bean>

在UserService类加入:

@Autowired(required = false)

TransactionTemplate txTemplate;

public int txUpdateUsersWhenExceptionViaTxTemplate() {

int retVal = txTemplate.execute(new TransactionCallback() {

@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(); //

}

注:不可catch Exception或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;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Bootstrap开发实战之响应式轮播图
下一篇:Java访问Hadoop分布式文件系统HDFS的配置说明
相关文章

 发表评论

暂时没有评论,来抢沙发吧~