目录
1 @Transactional事务注解如何生效
普通的代码 我们会再A 方法中 开启线程,再线程中执行B方法,此时再A方法上使用。
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)注解开启事务,发现A方法中发生异常会执行回滚操作,但是如果B方法中发生异常则不会执行回滚操作。
伪代码如下:
package com.mti.scheduled;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author hf
* @version 1.0
* @description: TODO
* @date 2020/12/10 15:16
*/
public class Test {
private static ExecutorService pool = Executors.newFixedThreadPool(5);
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void A()
{
pool.execute(()->{
B();
});
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
private void B() {
}
}
2产生原因及解决方法:
原因1:@Transactional只能控制单线程事务,所以子线程中的方法B不受A方法上的事务控制
原因2:@Transactional只能在public声明的方法上生效(那么把上边例子中的private改成public就可以了吗?并不能,因为原因3)
原因3:@Transactional是通过proxy实现的,所以B方法要放在新的类中,不能放在A方法所在的类中
3 A方法的工作类
package com.mti.scheduled;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mti.dao.model.LfZtryyjEntity;
import com.mti.service.ILfZtryyjsjService;
import com.mti.threadhandle.AlarmDataDelAndBackupHandle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Author hf
* @Title:
* @Description: TODO (预警数据删除和备份定时任务)
* @Param
* @return
* @Date 2020/11/25 14:26
*/
@Component
@EnableScheduling
@EnableAsync
@Slf4j
public class AlarmDataDelAndBackupScheduled {
@Autowired
private ILfZtryyjsjService iLfZtryyjsjService;
@Autowired
private AlarmDataDelAndBackupHandle alarmDataDelAndBackupHandle;
/**
* 每次查询5W条数据
*/
private static final String size = "50000";
private static ExecutorService pool = Executors.newFixedThreadPool(5);
/**
* @return void
* @Author hf
* @Title: sighOfAlarmData
* @Param []
* @Date 2020/12/9 18:05
* @Desc 定时任务每晚两点开始执行
*/
@Async
@Scheduled(cron = "*/30 * * * * ? ")
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void sighOfAlarmData() throws Exception {
log.info("AlarmDataDelAndBackupScheduled task start");
try {
//三个月前的当前时间
DateTime dateForThreeMonthAgo = DateUtil.offset(DateUtil.date(), DateField.MONTH, -3);
// 从数据库中查询出的对象集合
List<LfZtryyjEntity> list = iLfZtryyjsjService.list(new QueryWrapper<LfZtryyjEntity>().ge("yjsj", dateForThreeMonthAgo).last("LIMIT " + size));
List<List<LfZtryyjEntity>> subListData = ListUtil.split(list, 50);
CountDownLatch downLatch = new CountDownLatch(subListData.size());
for (int i = 0; i < subListData.size(); i++) {
int finalI = i;
pool.execute(() -> {
try {
alarmDataDelAndBackupHandle.delAndInsertData(subListData.get(finalI), downLatch);
} catch (Exception e) {
log.error("备份过程出错", e);
}
});
}
downLatch.await();
log.info("AlarmDataDelAndBackupScheduled task end");
} catch (Exception e) {
log.error("AlarmDataDelAndBackupScheduled task error======》{}", e);
} finally {
pool.shutdown();
}
}
}
4 B方法的工作类:
package com.mti.threadhandle;
import com.mti.dao.model.LfZtryyjCopyEntity;
import com.mti.dao.model.LfZtryyjEntity;
import com.mti.service.ILfZtryyjsjCopyService;
import com.mti.service.ILfZtryyjsjService;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
/**
* @author hf
* @version 1.0
* @description: TODO
* @date 2020/12/10 14:49
*/
@Data
@AllArgsConstructor
@Service
public class AlarmDataDelAndBackupHandle {
@Autowired
private ILfZtryyjsjService iLfZtryyjsjService;
@Autowired
private ILfZtryyjsjCopyService iLfZtryyjsjCopyService;
@Transactional(rollbackFor = Exception.class)
public void delAndInsertData(List<LfZtryyjEntity> subListData, CountDownLatch downLatch) throws Exception {
try {
// 进行拆解封装
List<LfZtryyjCopyEntity> copyList = subListData.stream().map(e -> transObj(e)).collect(Collectors.toList());
List<String> ids = subListData.stream().map(LfZtryyjEntity::getWybs).collect(Collectors.toList());
//特意执行先删除再插入的操作 看结果师傅回滚
iLfZtryyjsjService.removeByIds(ids);
iLfZtryyjsjCopyService.saveBatch(copyList, 5000);
} catch (Exception e) {
throw new Exception();
} finally {
downLatch.countDown();
}
}
/**
* @return com.mti.dao.model.LfZtryyjCopyEntity
* @Author hf
* @Title: transObj
* @Param [e]
* @Date 2020/12/9 16:40
* @Desc 转换对象 将LfZtryyjEntity对象转换为LfZtryyjCopyEntity
*/
private LfZtryyjCopyEntity transObj(LfZtryyjEntity e) {
LfZtryyjCopyEntity entity = new LfZtryyjCopyEntity();
entity.setAlarmFlag(e.getAlarmFlag());
entity.setBusno(e.getBusno());
entity.setZjzp3(e.getZjzp3());
entity.setZjzp2(e.getZjzp2());
entity.setZjzp(e.getZjzp());
entity.setYjsj(e.getYjsj());
entity.setYjlx(e.getYjlx());
entity.setY(e.getY());
entity.setYjdSsfjCode(e.getYjdSsfjCode());
entity.setYjdPcsCode(e.getYjdPcsCode());
entity.setYjdd(e.getYjdd());
entity.setYjbs(e.getYjbs());
entity.setXsd(e.getXsd());
entity.setWybs(e.getWybs());
entity.setTx(e.getTx());
entity.setTicketno(e.getTicketno());
entity.setTbsj(e.getTbsj());
entity.setTargetUrl(e.getTargetUrl());
entity.setSjbs(e.getSjbs());
entity.setShotTime(e.getShotTime());
entity.setServiceName(e.getServiceName());
entity.setServiceCode(e.getServiceCode());
entity.setSendtime(e.getSendtime());
entity.setSendStationIden(e.getSendStationIden());
entity.setSendPro(e.getSendPro());
entity.setSendLng(e.getSendLng());
entity.setSendLat(e.getSendLat());
entity.setSendFlag(e.getSendFlag());
entity.setSendCity(e.getSendCity());
entity.setSeatno(e.getSeatno());
entity.setRyxm(e.getRyxm());
entity.setRlzp(e.getRlzp());
entity.setPrtname(e.getPrtname());
entity.setPersonUrl(e.getPersonUrl());
entity.setPcpcsdh(e.getPcpcsdh());
entity.setPcmjname(e.getPcmjname());
entity.setPcmjid(e.getPcmjid());
entity.setPcmjdh(e.getPcmjdh());
entity.setInOut(e.getInOut());
entity.setHandleFlag(e.getHandleFlag());
entity.setGxsj(e.getGxsj());
entity.setGlId(e.getGlId());
entity.setGlData(e.getGlData());
entity.setFaceUrl(e.getFaceUrl());
entity.setEndStationTime(e.getEndStationTime());
entity.setEndStationIden(e.getEndStationIden());
entity.setEndPro(e.getEndPro());
entity.setEndname(e.getEndname());
entity.setEndLng(e.getEndLng());
entity.setEndLat(e.getEndLat());
entity.setEndCity(e.getEndCity());
entity.setDeviceName(e.getDeviceName());
entity.setDepartment(e.getDepartment());
entity.setDdmc(e.getDdmc());
entity.setCurrentJur(e.getCurrentJur());
return entity;
}
}