Spring+Mybatis 手动控制事务

Spring+Mybatis 手动控制事务

背景&问题

在【财务资金指标录入】项目中,由于对数据库的“修改”操作较为复杂,一条sql语句无法完成整个操作,所以需要在ServiceImpl中人为控制事务的提交和回滚,以保证数据库数据的准确性和一次数据库写操作的原子性。

解决方案

在ServiceImpl中注入Spring框架提供的 DataSourceTransactionManager 对象,使用该对象,并配合try…catch…代码块完成手动事务控制。

代码

ServiceImpl:

package com.sfpay.console.service.impl;

......
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
......

/**
 * 类说明:<br>
 * 财务资金指标录入模块Service层实现类
 * @author 80003614 
 * CreateDate: 2019-2-11
 */
@Service("finFundIdxService")
public class FinFundIdxServiceImpl implements FinFundIdxService {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	// 1.获取事务控制管理器
	@Autowired
	private DataSourceTransactionManager transactionManager;

	@Autowired
	private FinFundIdxMapper finFundIdxMapper;

	......
	
	// 修改
	@Override
	public void updateFinFundIdx(FinanceFundIndex finFundIdx) {
		// 2.获取事务定义
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		// 3.设置事务隔离级别,开启新事务
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
		// 4.获得事务状态
		TransactionStatus status = transactionManager.getTransaction(def);
		try {
			// 5.具体的数据库操作(多个)
			logger.debug("update到数据库前的JavaBean预览:" + finFundIdx.toString());
			// "修改"操作需要与数据库进行3次交互,这3次写操作必须放在一个事务中控制!!!
			finFundIdxMapper.updateFinFundIdx(finFundIdx);
			// int a = 1 / 0;
			finFundIdxMapper.updateFinFundIdx2(finFundIdx);
			finFundIdxMapper.updateFinFundIdx3(finFundIdx);
			transactionManager.commit(status);
		} catch (Exception e) {
			transactionManager.rollback(status);
			throw new RuntimeException(e.getMessage());
		}
	}
}

Mapper.xml:

/**
 * 配置说明:<br>
 * 财务资金指标录入模块Mapper.xml
 * @author 80003614 
 * CreateDate: 2019-2-11
 */

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sfpay.console.dao.FinFundIdxMapper">
	<resultMap id="BaseResultType" type="com.sfpay.console.domain.FinanceFundIndex">
		<id column="IDX_ID" property="idxId" jdbcType="DECIMAL" />
		<result column="IDX_NAME" property="idxName" jdbcType="VARCHAR" />
		<result column="IDX_VAL" property="idxVal" jdbcType="DECIMAL" />
		<result column="BEGIN_DATE" property="beginDate" jdbcType="DATE" />
		<result column="END_DATE" property="endDate" jdbcType="DATE" />
		<result column="CREATE_TIME" property="createTime" jdbcType="DATE" />
		<result column="UPDATE_TIME" property="updateTime" jdbcType="DATE" />	
	</resultMap>

	......

	<!-- 更新 -->
	<!--"财务资金指标"的修改操作需要完成3个步骤,并用同一个事务控制 -->
	<!-- 第一步:针对要修改的那条记录作update或insert操作 -->
	<update id="updateFinFundIdx" parameterType="com.sfpay.console.domain.FinanceFundIndex" >
		merge into EDWSDATA.IMP_FIN_IDX idi
		using (
		select distinct IDX_ID, IDX_NAME, #{idxVal,jdbcType=DECIMAL} IDX_VAL, 
		#{beginDate,jdbcType=DATE} BEGIN_DATE from EDWSDATA.IMP_FIN_IDX
		where IDX_ID = #{idxId,jdbcType=DECIMAL}
		) t
		on (t.IDX_ID = idi.IDX_ID and t.BEGIN_DATE = idi.BEGIN_DATE)
		when matched then update
  		set idi.IDX_VAL = t.IDX_VAL, idi.END_DATE = to_date('2099-12-31','yyyy-mm-dd'), idi.UPDATE_TIME = sysdate
		when not matched then insert(IDX_ID, IDX_NAME, IDX_VAL, BEGIN_DATE, END_DATE, UPDATE_TIME)
  		values(t.IDX_ID, t.IDX_NAME, t.IDX_VAL, t.BEGIN_DATE, to_date('2099-12-31','yyyy-mm-dd'), sysdate)
	</update>
	
	<!-- 第二步:删除这条记录后面的所有记录(以begin_date为基准) -->
	<delete id="updateFinFundIdx2" parameterType="com.sfpay.console.domain.FinanceFundIndex" >
		delete from EDWSDATA.IMP_FIN_IDX t
		where t.IDX_ID = #{idxId,jdbcType=DECIMAL}
		and t.BEGIN_DATE &gt; #{beginDate,jdbcType=DATE}
	</delete>
	
	<!-- 第三步:修改被修改记录的前一条记录的end_date值 -->
	<update id="updateFinFundIdx3" parameterType="com.sfpay.console.domain.FinanceFundIndex" >
		update EDWSDATA.IMP_FIN_IDX t
		set t.END_DATE = #{beginDate,jdbcType=DATE}
		where t.IDX_ID = #{idxId,jdbcType=DECIMAL} 
		and t.BEGIN_DATE = 
		(select BEGIN_DATE from 
		(select BEGIN_DATE, ROW_NUMBER() OVER (PARTITION BY IDX_ID ORDER BY BEGIN_DATE DESC) as rank 
		from EDWSDATA.IMP_FIN_IDX where IDX_ID = #{idxId,jdbcType=DECIMAL}) t1 where t1.rank = 2)
	</update>
</mapper>	

参考文章

链接: Spring+Mybatis 手动控制事务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值