Springboot的@Transactional 注解实现数据库事务处理
一、注解式事务
1、启动类
添加@EnableTransactionManagement开启事务
2、业务类添加注解
- @Transactional 数据库事务注解
- propagation 事务传播行为配置
- REQUIRED(0) 如果当前已经有事务则使用该事务,如果没有则新建一个事务
- SUPPORTS(1) 如果当前有事务则使用当前事务,如果没有则无事务
- MANDATORY(2) 如果当前有事务则使用当前事务,如果没有则报错
- REQUIRES_NEW(3) 如果当前已经有事务则挂起当前事务另建一个事务,如果没有事务则新建一个事务
- NOT_SUPPORTED(4) 即当前方法必须不在事务中,如果当前有事务则挂起
- NEVER(5) 当前方法不应该在事务中运行,如果有,就抛异常
- NESTED(6) 如果当前有事务运行,则再这个事务中嵌套运行(即外部事务回滚会导致内部事务回滚,内部事务回滚则不会影响外部事务),如果没有事务则另起一个事务,并在事务中运行
- isolation 事务的隔离级别,事务的隔离级别默认是跟随数据库的事务隔离级别
- DEFAULT 默认级别,默认跟随数据库的隔离级别
- READ_UNCOMMITTED 读未提交
- READ_COMMITTED 读已提交
- REPEATABLE_READ 可重复读(mysql默认级别)
- SERIALIZABLE 串行化
- timeout 事务超时设置,默认是30秒
- readOnly 设置事务为只读事务,true为只读,false为可读写,默认为false
- true 只读
- false 可读写,默认为可读写
- rollbackFor/rollbackForClassName 回滚异常类
- noRollbackFor/noRollbackForClassName 不会滚异常类
- value/transactionManager 指定事务管理器
- PlatformTransactionManager 事务管理器接口
- DataSourceTransactionManager 但数据源事务管理器
- JtaTransactionManager JTA事务管理器
- HibernateTransactionManager Hibernate框架事务管理器
- propagation 事务传播行为配置
// 使用较为简单
@Service
@Transactional(readOnly = true,rollbackFor = {RuntimeException.class,BizException.class})
public class UserService {
//标注在方法上,作为类内部方法局部
@Transactional(readOnly = false,rollbackFor = Exception.class)
public Integer updates(User blues,User zhangsan) throws Exception{
// ... do somethings
}
}
3、事务传播行为介绍
(1) Propagation.REQUIRED
- Spring默认传播行为是reuqired
- 当前有事务,使用当前事务
- 当前没有事务,创建新事物,即保证当前方法在事务中
(2)Propagation.REQUIRES_NEW
- 当前没有事务,创建事务运行
- 当前有事务,创建新事物,即存在两个独立的事务
- 不管当前方法是否有事务,都会创建一个新事物,即存在两个独立事务
(3)Propagation.SUPPORTED
- 当前有事务时,使用当前事务,
- 当前没有事务时,无事务运行
(4)Propagation.NOT_SUPPORTS
- 当前存在事务,则挂起事务,无事务运行
- 当前不存在事务,直接运行
- 即当前方法不支持事务
(4)Propagation.MANDATORY
- 当前存在事务,使用当前事务运行
- 当前不存在事务,抛出异常
- 即当前传播中必须有事务
(5)Propagation.NEVER
- 当前有事务,则抛异常
- 当前没有事务,正常运行
(7)Propagation.NEWSTED
- 当前有事务,在当前事务下创建一个嵌套事务,外层事务异常,内外层事务都回滚,内存事务异常,则只回滚内存事务,外层事务不会回滚
- 当前没有事务,则创建一个事务
二、@Transcation注解事务不生效场景
1、不生效场景总览
- 数据库引擎不支持事务
- mysql的ISAM不支持事务
- 注解的类是非public修饰的方法上,
- 底层使用了动态代理,并规定了访问权限是public
- 注解的方法被标注为final类型
- 由于底层使用了动态代理,如果设置为final就表示不能生成动态代理对象
- 注解的属性rollbackFor设置错误,
- 默认是RuntimeException以及子类,如果需要支持其他异常需要指明在rollbackFor属性内
- 注解的属性propagation设置错误:
- 默认是REQUIRE,如果设置为NOT_SUPPORT,会因为有事务抛出异常,如果是MANDATORY 则会因为外层没有事务的话导致报错
- 注解的方法内异常被手动捕获
- 底层是方法根据抛出的异常决定是否回滚,如果被捕获了,没有抛出,外层自然拿不到异常
- 同一个方法内自调用,导致失效
- 注解的方法所属的类没有被spring管理
- 比如所在类没有使用@Controller,@Service,@Componment,@Bean等注解
- 注解的方法内部采用了多线程调用
- 根据事务底层原理,即子线程的状态,主流程线程不能影响到
- 嵌套事务导致回滚失效
- 根据嵌套事务定义,内存事务回滚不会导致外层事务回滚,外层事务回滚,内存事务也会回滚
(1)方法内自调用导致的事务失效场景
这种场景比较隐蔽,也是比较容易出现问题的场景
@Service
public class UserService{
@Autowired
private UserMapper userMapper;
@Transcational
public void add(User user){
userMapper.insertUser(user);
//失效场景之一:方法内直接调用
updateStatus(user);
}
@Transcational
public void updateStatus(User user){
user.setStatus(1);
userMapper.update(user);
}
}
//解决方式:另外新家一个业务类调用add
@Service
public class ServiceB {
@Resource
UserService userService
@Transcational
public void add(user user){
userService.add(user);
}
}
(2)方法二:在该类中注入自己
@Service
public class UserService{
@Autowired
private UserMapper userMapper;
@Resource
private UserService userService;
@Transcational
public void add(User user){
userMapper.insertUser(user);
userService.updateStatus(user);
}
@Transcational
public void updateStatus(User user){
user.setStatus(1);
userMapper.update(user);
}
}
(3)方法三:通过AOPContent类或者SpringContext类
@Service
public class UserService{
@Autowired
private UserMapper userMapper;
@Resource
private UserService userService;
@Transcational
public void add(User user){
userMapper.insertUser(user);
//方式一,使用SpringContext调用
SpringContext.getBean(this.getClass()).doConvert(convertBO);
//方式二:使用AopContext,不推荐,需要强转
//((AssetsConvertService)AopContext.currentProxy()).execute(convertBO);
}
@Transcational
public void updateStatus(User user){
user.setStatus(1);
userMapper.update(user);
}
}
7、使用注解式事务需要注意的点
- @Transactional 只能被应用到public,非final方法上。
- 用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上
@Transactional( rollbackFor={Exception.class,其它异常})
.如果让unchecked例外不回滚:@Transactional(notRollbackFor=RunTimeException.class)
- @Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅@Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是``元素的出现 开启 了事务行为。
- @Transactional注解的方法,如果要捕获异常一定要注意,可以在catch方法里面再抛出一个异常,这样外层事务也能够回滚
三、关于注解事务可能造成脏读的解决方案
1、脏数据出现场景伪代码
@Service
public class AccountService{
@Autowired
private AccountMapper accountMapper;
@Autowired
private AccountService accountService;
@Transactional
public void deduct(DeductDTo deductDto){
//外层:幂等校验
RequestValidate(deductDto);
//中层:分布式锁校验
RLock lock = redissonClient.getLock("account_lock_"+deductDto.getAcctId());
boolean lockSuccess = lock.tryLock(60, TimeUnit.SECONDS);
if(!lockSuccess){
throw new BizException("获取锁超时");
}
try{
accountService.doDeduct(deductDto);
}finally{
lock.unlock();//释放锁
}
}
public void doDeduct(DeductDTo deductDto){
//第一步查询
Account account = accountMapper.getById(deductDto.getAccId());
//第二步,变更account
Long afterBalance = account.getBalance()-deductDto.getTransNum();
if(afterBalance<0){
throw new BizException("余额不足");
}
account.setBalance(afterBalance);
accountMapper.update(account);
//第三步:记录交易记录
AccountTranLog tranLog = buildTranLog(deductDto,account);
accountMapper.saveTranLog(tranLog);
}
}
2、出现脏数据的原因分析
- 事务请求突破了接口幂等防范,导致相同的请求在短时间内进入到方法中执行
- 事务请求突破了分布式锁防范,分布式锁时间设置过段,或者执行完成后释放了锁
- 第一次请求在事务没有提交时,第二次请求已经读取了Account数据脏数据,随后第一次请求事务提交,第二次事务提交,突破了事务设置
3、场景的解决方案
(1)采用乐观锁的方式(推荐)
修改doDeduct方法,采用乐观锁方式
public void doDeduct(DeductDTo deductDto){
//第一步查询
Account account = accountMapper.getById(deductDto.getAccId());
//第二步,变更account
Long afterBalance = account.getBalance()-deductDto.getTransNum();
if(afterBalance<0){
throw new BizException("余额不足");
}
//注意这里需要将原有的值进行一次CAS乐观锁比较
LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<Account>()
.set(Account::getBalance,afterBalance)
.eq(Account::getAccId,account.getAccId())
.eq(Account::getBalance,account.getBalance());
Boolean aboolean = accountMapper.update(updateWrapper);
//如果更新失败则进行回滚
if(!aBllean){
throw new BizException("扣减账户余额失败");
}
//第三步:记录交易记录
AccountTranLog tranLog = buildTranLog(deductDto,account);
accountMapper.saveTranLog(tranLog);
}
(2)缩小事务范围(推荐)
将 @Transactional 放到doDeduct上,这样缩小事务范围,这样就不会因为分布式锁被释放导致第二次请求进入到事务方法
@Transactional
public void doDeduct(DeductDTo deductDto){
// ... ...
}
(3)使用悲观锁(不推荐)
使用synchroinzed,这样会导致整个并发变慢
public synchroinzed void doDeduct(DeductDTo deductDto){
// ... ...
}
四、编程式事务
1、创建一个编程式事务的配置类
添加这个类,根据知己需要修改切入点,然后放到能被spring boot扫描到的包下即可
@Aspect
@Configuration
public class GlobalTransactionAdviceConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.example.demo.service..*.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttr_REQUIRED_READONLY.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("add*", txAttr_REQUIRED);
source.addTransactionalMethod("insert*", txAttr_REQUIRED);
source.addTransactionalMethod("save*", txAttr_REQUIRED);
source.addTransactionalMethod("create*", txAttr_REQUIRED);
// ... ... 根据方法名称匹配设置对应的事务
source.addTransactionalMethod("select*", txAttr_REQUIRED_READONLY);
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
2、添加User的AOP类
如果事务不在Service下面,而是在Controller中
切入点为controller时,如何使用编程式事务管理控制事务
@Component
@Aspect
public class ResUserAspect {
@Autowired
private IPartnerService partnerService;
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
private TransactionStatus transactionStatus;
// 验证切入点为service时,AOP编程中的事务问题
@Pointcut("execution(public * com.example.demo.controllers.UserController.insertUser(..))")
private void insertUser(){}
@Before(value = "insertUser()")
public void before(){
//在切入点程序执行之前手动开启事务 - 必须的操作
transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
}
//切入点为controller时的事务验证
@Transactional
@AfterReturning(pointcut = "insertUser()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
if (!(result instanceof JSONMsg)){
System.out.println(result.getClass());
return;
}
JSONMsg jsonMsg = (JSONMsg) result;
try{
if (jsonMsg.getCode() == 200){
ResPartner partner = new ResPartner();
ResUser user = (ResUser) jsonMsg.getData();
partner.setId(user.getId());
partner.setName(user.getName());
partner.setDisplayName(user.getLogin());
int a = 1/0;
int i = partnerService.add(partner);
System.out.println(i);
}
platformTransactionManager.commit(transactionStatus); // 手动提交事务
System.out.println("提交事务");
}catch (Exception e){
platformTransactionManager.rollback(transactionStatus); // 出现异常,回滚事务
System.out.println("回滚事务");
System.out.println(e.getMessage());
//修改返回数据
jsonMsg.setCode(400);
jsonMsg.setMsg(e.getMessage());
}
}
}
五、编程式事务
1、函数式编程式事务工具类
@Slf4j
public class TransactionKit {
private TransactionKit() {}
public static <R> R enableTrans(Supplier<R> supplier, int timeout) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
rbta.setIsolationLevel(Isolation.DEFAULT.value());
// 单位秒
rbta.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);
rbta.setReadOnly(false);
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
rollbackRules.add(new RollbackRuleAttribute(RuntimeException.class));
rbta.setRollbackRules(rollbackRules);
PlatformTransactionManager txManager = SpringContext.getBean(PlatformTransactionManager.class);
TransactionStatus transactionStatus = txManager.getTransaction(rbta);
try {
R rs = supplier.get();
txManager.commit(transactionStatus);
return rs;
} catch (Exception e) {
log.error("", e);
if(TransactionSynchronizationManager.isActualTransactionActive()) {
txManager.rollback(transactionStatus);
}
throw e;
}
}
public static void enableTrans(Runnable runnable, int timeout) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
rbta.setIsolationLevel(Isolation.DEFAULT.value());
// 单位秒
rbta.setTimeout(timeout);
rbta.setReadOnly(false);
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
rollbackRules.add(new RollbackRuleAttribute(RuntimeException.class));
rbta.setRollbackRules(rollbackRules);
PlatformTransactionManager txManager = SpringContext.getBean(PlatformTransactionManager.class);
TransactionStatus transactionStatus = txManager.getTransaction(rbta);
try {
runnable.run();
txManager.commit(transactionStatus);
} catch (Exception e) {
log.error("", e);
if(TransactionSynchronizationManager.isActualTransactionActive()) {
txManager.rollback(transactionStatus);
}
throw e;
}
}
/**
* 开启事务
*/
public static <R> R enableTrans(Supplier<R> supplier) {
return enableTrans(supplier, TransactionDefinition.TIMEOUT_DEFAULT);
}
public static void enableTrans(Runnable runnable) {
enableTrans(runnable, TransactionDefinition.TIMEOUT_DEFAULT);
}
public static void doAroundTxCommit(Runnable taskBeforeCommit, Runnable taskAfterCommit) {
if(TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager
.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void beforeCommit(boolean readOnly) {
if(readOnly || taskBeforeCommit != null) {
log.info("事务提交前执行任务 >>>");
taskBeforeCommit.run();
}
}
@Override
public void afterCommit() {
if(taskAfterCommit != null) {
log.info("事务提交后执行任务 >>>");
taskAfterCommit.run();
}
}
});
} else {
// 无事务 则直接执行
if(taskBeforeCommit != null) {
taskBeforeCommit.run();
}
if(taskAfterCommit != null) {
taskAfterCommit.run();
}
}
}
public static void doBeforeTxCommit(Runnable taskBeforeCommit) {
if(TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager
.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void beforeCommit(boolean readOnly) {
if(readOnly || taskBeforeCommit != null) {
log.info("事务提交前执行任务 >>>");
taskBeforeCommit.run();
}
}
});
} else {
// 无事务 则直接执行
if(taskBeforeCommit != null) {
taskBeforeCommit.run();
}
}
}
public static void doAfterTxCommit(Runnable taskAfterCommit) {
if(TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager
.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
if(taskAfterCommit != null) {
log.info("事务提交后执行任务 >>>");
taskAfterCommit.run();
}
}
});
} else {
// 无事务 则直接执行
if(taskAfterCommit != null) {
taskAfterCommit.run();
}
}
}
}
六、多线程中使用事务
主要思路:通过多线程的闭锁实现对并发事务的整体控制
1、事务线程池工具类
public class ThreadPoolTool<T> {
public void excuteTask(DataSourceTransactionManager transactionManager,
List data, int threadCount, Map<String, Object> params, Class clazz) {
if (data == null || data.size() == 0) {
return;
}
int batch = 0;
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
//监控子线程的任务执行
CountDownLatch childMonitor = new CountDownLatch(threadCount);
//监控主线程,是否需要回滚
CountDownLatch mainMonitor = new CountDownLatch(1);
//存储任务的返回结果,返回true表示不需要回滚,反之,则回滚
BlockingDeque<Boolean> results = new LinkedBlockingDeque<Boolean>(threadCount);
RollBack rollback = new RollBack(false);
try {
LinkedBlockingQueue<List> queue = splitQueue(data, threadCount);
while (true) {
List list = queue.poll();
if (list == null) {
break;
}
batch++;
params.put("batch", batch);
Constructor constructor = clazz.getConstructor(new Class[]{CountDownLatch.class, CountDownLatch.class, BlockingDeque.class, RollBack.class, DataSourceTransactionManager.class, Object.class, Map.class});
ThreadTask task = (ThreadTask) constructor.newInstance(childMonitor, mainMonitor, results, rollback, transactionManager, list, params);
executor.execute(task);
}
// 1、主线程将任务分发给子线程,然后使用childMonitor.await();阻塞主线程,等待所有子线程处理向数据库中插入的业务。
childMonitor.await();
System.out.println("主线程开始执行任务");
//根据返回结果来确定是否回滚
for (int i = 0; i < threadCount; i++) {
Boolean result = results.take();
if (!result) {
//有线程执行异常,需要回滚子线程
rollback.setNeedRoolBack(true);
}
}
// 3、主线程检查子线程执行任务的结果,若有失败结果出现,主线程标记状态告知子线程回滚,然后使用mainMonitor.countDown();将程序控制权再次交给子线程,子线程检测回滚标志,判断是否回滚。
mainMonitor.countDown();
} catch (Exception e) {
log.error(e.getMessage());
} finally {
//关闭线程池,释放资源
executor.shutdown();
}
}
/**
* 队列拆分
*/
private LinkedBlockingQueue<List<Object>> splitQueue(List<Object> data, int threadCount) {
LinkedBlockingQueue<List<Object>> queueBatch = new LinkedBlockingQueue();
int total = data.size();
int oneSize = total / threadCount;
int start;
int end;
for (int i = 0; i < threadCount; i++) {
start = i * oneSize;
end = (i + 1) * oneSize;
if (i < threadCount - 1) {
queueBatch.add(data.subList(start, end));
} else {
queueBatch.add(data.subList(start, data.size()));
}
}
return queueBatch;
}
}
2、子线程城执行事务
public abstract class ThreadTask implements Runnable {
private CountDownLatch childMonitor;
private CountDownLatch mainMonitor;
private BlockingDeque<Boolean> resultList;
private RollBack rollback;
private Map<String,Object> params;
protected Object obj;
protected DataSourceTransactionManager transactionManager;
protected TransactionStatus status;
public ThreadTask(CountDownLatch childCountDown,
CountDownLatch mainCountDown,
BlockingDeque<Boolean> result,
RollBack rollback,
DataSourceTransactionManager transactionManager,
Object obj,
Map<String,Object> params) {
this.childMonitor = childCountDown;
this.mainMonitor = mainCountDown;
this.resultList = result;
this.rollback = rollback;
this.transactionManager = transactionManager;
this.obj = obj;
this.params = params;
initParam();
}
/**
* 事务回滚
*/
private void rollBack() {
System.out.println(Thread.currentThread().getName()+"开始回滚");
transactionManager.rollback(status);
}
/**
* 事务提交
*/
private void submit() {
System.out.println(Thread.currentThread().getName()+"提交事务");
transactionManager.commit(status);
}
protected Object getParam(String key){
return params.get(key);
}
/**
* 初始化方法:作用是把线程池工具任务执行类所需的外部资源通过 ThreadTask.class的构造方法中 Map<String,Obejct> params参数进行初始化传递进来
*/
public abstract void initParam();
/**
* 执行任务,返回false表示任务执行错误,需要回滚
* @return
*/
public abstract boolean processTask();
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"子线程开始执行任务");
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
status = transactionManager.getTransaction(def);
Boolean result = processTask();
//向队列中添加处理结果
resultList.add(result);
//2、使用childMonitor.countDown()释放子线程锁定,同时使用mainMonitor.await();阻塞子线程,将程序的控制权交还给主线程。
childMonitor.countDown();
try {
//等待主线程的判断逻辑执行完,执行下面的是否回滚逻辑
mainMonitor.await();
} catch (Exception e) {
log.error(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+"子线程执行剩下的任务");
//3、主线程检查子线程执行任务的结果,若有失败结果出现,主线程标记状态告知子线程回滚,然后使用mainMonitor.countDown();将程序控制权再次交给子线程,子线程检测回滚标志,判断是否回滚。
if (rollback.isNeedRoolBack()) {
rollBack();
}else{
//事务提交
submit();
}
}
}
3、线程标记类
@Data
public class RollBack {
public RollBack(boolean needRoolBack) {
this.needRoolBack = needRoolBack;
}
private boolean needRoolBack;
}
4、线程池工具
/**
* 多线程处理任务类
*/
public class TestTask extends ThreadTask {
/**
分批处理的数据
*/
private List<Object> objectList;
/**
* 可能需要注入的某些服务
*/
private TestService testService;
public TestTask(CountDownLatch childCountDown, CountDownLatch mainCountDown, BlockingDeque<Boolean> result, RollBack rollback, DataSourceTransactionManager transactionManager, Object obj, Map<String, Object> params) {
super(childCountDown, mainCountDown, result, rollback, transactionManager, obj, params);
}
@Override
public void initParam() {
this.objectList = (List<Object>) getParam("objectList");
this.testService = (TestService) getParam("testService");
}
/**
* 执行任务,返回false表示任务执行错误,需要回滚
* @return
*/
@Override
public boolean processTask() {
try {
for (Object o : objectList) {
testService.list();
System.out.println(o.toString()+"执行自己的多线程任务逻辑");
}
return true;
} catch (Exception e) {
return false;
}
}
}
5、使用示例
/**
* 执行多线程任务方法
*/
public void testThreadTask() {
try {
int threadCount = 5;
//需要分批处理的数据
List<Object> objectList = new ArrayList<>();
Map<String,Object> params = new HashMap<>();
params.put("objectList",objectList);
params.put("testService",testService);
//调用多线程工具方法
threadPoolTool.excuteTask(transactionManager,objectList,threadCount,params, TestTask.class);
}catch (Exception e){
throw new RuntimeException(e.getMessage());
}
}