都2202年了,还有人在Java多线程批量操作的时候不做事务控制?

利用多线程事务控制实现大批量数据库操作 导语 在数据库中如果需要对大量的数据进行批量修改,并不是一项简单的工作。而利用多线程事务控制可以帮助我们解决这些问题。本篇主要向大家介绍利用多线程来实现大批量数据库操作。 正文 公司业务中遇到一个需求,需要同时修改最多约5万条数据,而且还不支持批量或异步修改操作。于是只能写个for循环操作,但操作耗时太长,只能一步一步寻找其他解决方案。 具体操作如下: 1. 循环操作的代码 先写一个最简单的for循环代码,看看耗时情况怎么样。 /*** * 一条一条依次对50000条数据进行更新操作 * 阅读详情

​

前言

公司业务中遇到一个需求,需要同时修改最多约5万条数据,而且还不支持批量或异步修改操作。于是只能写个for循环操作,但操作耗时太长,只能一步一步寻找其他解决方案。

具体操作如下:

一、循环操作的代码

先写一个最简单的for循环代码,看看耗时情况怎么样。

/*** * 一条一条依次对50000条数据进行更新操作 * 耗时:2m27s,1m54s */ @Test void updateStudent() { List<Student> allStudents = studentMapper.getAll(); allStudents.forEach(s -> { //更新教师信息 String teacher = s.getTeacher(); String newTeacher = "TNO_" + new Random().nextInt(100); s.setTeacher(newTeacher); studentMapper.update(s); }); } 复制代码

循环修改整体耗时约 1分54秒,且代码中没有手动事务控制应该是自动事务提交,所以每次操作事务都会提交所以操作比较慢,我们先对代码中添加手动事务控制,看查询效率怎样。

二、使用手动事务的操作代码

修改后的代码如下

@Autowired private DataSourceTransactionManager dataSourceTransactionManager; @Autowired private TransactionDefinition transactionDefinition; /** * 由于希望更新操作 一次性完成,需要手动控制添加事务 * 耗时:24s * 从测试结果可以看出,添加事务后插入数据的效率有明显的提升 */ @Test void updateStudentWithTrans() { List<Student> allStudents = studentMapper.getAll(); TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); try { allStudents.forEach(s -> { //更新教师信息 String teacher = s.getTeacher(); String newTeacher = "TNO_" + new Random().nextInt(100); s.setTeacher(newTeacher); studentMapper.update(s); }); dataSourceTransactionManager.commit(transactionStatus); } catch (Throwable e) { dataSourceTransactionManager.rollback(transactionStatus); throw e; } } 复制代码

添加手动事务操控制后,整体耗时约 24秒,这相对于自动事务提交的代码,快了约5倍,对于大量循环数据库提交操作,添加手动事务可以有效提高操作效率。

三、尝试多线程进行数据修改

添加数据库手动事务后操作效率有明细提高,但还是比较长,接下来尝试多线程提交看是不是能够再快一些。

先添加一个Service将批量修改操作整合一下,具体代码如下:

StudentServiceImpl.java

@Service public class StudentServiceImpl implements StudentService { @Autowired private StudentMapper studentMapper; @Autowired private DataSourceTransactionManager dataSourceTransactionManager; @Autowired private TransactionDefinition transactionDefinition; @Override public void updateStudents(List<Student> students, CountDownLatch threadLatch) { TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); System.out.println("子线程:" + Thread.currentThread().getName()); try { students.forEach(s -> { // 更新教师信息 // String teacher = s.getTeacher(); String newTeacher = "TNO_" + new Random().nextInt(100); s.setTeacher(newTeacher); studentMapper.update(s); }); dataSourceTransactionManager.commit(transactionStatus); threadLatch.countDown(); } catch (Throwable e) { e.printStackTrace(); dataSourceTransactionManager.rollback(transactionStatus); } } } 复制代码

批量测试代码,我们采用了多线程进行提交,修改后测试代码如下:

@Autowired private DataSourceTransactionManager dataSourceTransactionManager; @Autowired private TransactionDefinition transactionDefinition; @Autowired private StudentService studentService; /** * 对用户而言,27s 任是一个较长的时间,我们尝试用多线程的方式来经行修改操作看能否加快处理速度 * 预计创建10个线程,每个线程进行5000条数据修改操作 * 耗时统计 * 1 线程数:1 耗时:25s * 2 线程数:2 耗时:14s * 3 线程数:5 耗时:15s * 4 线程数:10 耗时:15s * 5 线程数:100 耗时:15s * 6 线程数:200 耗时:15s * 7 线程数:500 耗时:17s * 8 线程数:1000 耗时:19s * 8 线程数:2000 耗时:23s * 8 线程数:5000 耗时:29s */ @Test void updateStudentWithThreads() { //查询总数据 List<Student> allStudents = studentMapper.getAll(); // 线程数量 final Integer threadCount = 100; //每个线程处理的数据量 final Integer dataPartionLength = (allStudents.size() + threadCount - 1) / threadCount; // 创建多线程处理任务 ExecutorService studentThreadPool = Executors.newFixedThreadPool(threadCount); CountDownLatch threadLatchs = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { // 每个线程处理的数据 List<Student> threadDatas = allStudents.stream() .skip(i * dataPartionLength).limit(dataPartionLength).collect(Collectors.toList()); studentThreadPool.execute(() -> { studentService.updateStudents(threadDatas, threadLatchs); }); } try { // 倒计时锁设置超时时间 30s threadLatchs.await(30, TimeUnit.SECONDS); } catch (Throwable e) { e.printStackTrace(); } System.out.println("主线程完成"); } 复制代码

多线程提交修改时,我们尝试了不同线程数对提交速度的影响,具体可以看下面表格,

​多线程修改50000条数据时 不同线程数耗时对比(秒)

根据表格,我们线程数增大提交速度并非一直增大,在当前情况下约在2-5个线程数时,提交速度最快(实际线程数还是需要根据服务器配置实际测试)。

四、基于两个CountDownLatch控制多线程事务提交

由于多线程提交时,每个线程事务时单独的,无法保证一致性,我们尝试给多线程添加事务控制,来保证每个线程都是在插入数据完成后在提交事务,

这里我们使用两个 CountDownLatch 来控制主线程与子线程事务提交,并设置了超时时间为 30 秒。我们对代码进行了一点修改:

@Override public void updateStudentsThread(List<Student> students, CountDownLatch threadLatch, CountDownLatch mainLatch, StudentTaskError taskStatus) { TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); System.out.println("子线程:" + Thread.currentThread().getName()); try { students.forEach(s -> { // 更新教师信息 // String teacher = s.getTeacher(); String newTeacher = "TNO_" + new Random().nextInt(100); s.setTeacher(newTeacher); studentMapper.update(s); }); } catch (Throwable e) { taskStatus.setIsError(); } finally { threadLatch.countDown(); // 切换到主线程执行 } try { mainLatch.await(); //等待主线程执行 } catch (Throwable e) { taskStatus.setIsError(); } // 判断是否有错误,如有错误 就回滚事务 if (taskStatus.getIsError()) { dataSourceTransactionManager.rollback(transactionStatus); } else { dataSourceTransactionManager.commit(transactionStatus); } } 复制代码

/** * 由于每个线程都是单独的事务,需要添加对线程事务的统一控制 * 我们这边使用两个 CountDownLatch 对子线程的事务进行控制 */ @Test void updateStudentWithThreadsAndTrans() { //查询总数据 List<Student> allStudents = studentMapper.getAll(); // 线程数量 final Integer threadCount = 4; //每个线程处理的数据量 final Integer dataPartionLength = (allStudents.size() + threadCount - 1) / threadCount; // 创建多线程处理任务 ExecutorService studentThreadPool = Executors.newFixedThreadPool(threadCount); CountDownLatch threadLatchs = new CountDownLatch(threadCount); // 用于计算子线程提交数量 CountDownLatch mainLatch = new CountDownLatch(1); // 用于判断主线程是否提交 StudentTaskError taskStatus = new StudentTaskError(); // 用于判断子线程任务是否有错误 for (int i = 0; i < threadCount; i++) { // 每个线程处理的数据 List<Student> threadDatas = allStudents.stream() .skip(i * dataPartionLength).limit(dataPartionLength) .collect(Collectors.toList()); studentThreadPool.execute(() -> { studentService.updateStudentsThread(threadDatas, threadLatchs, mainLatch, taskStatus); }); } try { // 倒计时锁设置超时时间 30s boolean await = threadLatchs.await(30, TimeUnit.SECONDS); if (!await) { // 等待超时,事务回滚 taskStatus.setIsError(); } } catch (Throwable e) { e.printStackTrace(); taskStatus.setIsError(); } mainLatch.countDown(); // 切换到子线程执行 studentThreadPool.shutdown(); //关闭线程池 System.out.println("主线程完成"); } 复制代码

本想再次测试一下不同线程数对执行效率的影响时,发现当线程数超过10个时,执行时就报错。具体错误内容如下:

Exception in thread "pool-1-thread-2" org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30055ms. at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:309) at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400) at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) at com.example.springbootmybatis.service.Impl.StudentServiceImpl.updateStudentsThread(StudentServiceImpl.java:58) at com.example.springbootmybatis.StudentTest.lambda$updateStudentWithThreadsAndTrans$3(StudentTest.java:164) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30055ms. at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:696) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:197) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:162) at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128) at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:265) ... 7 more 复制代码

错误的大致意思时,不能为数据库事务打开 jdbc Connection,连接在30s的时候超时了。由于前面启动的十个线程需要等待主线程完成后才能提交,所以一直占用连接未释放,造成后面的进程创建连接超时。

看错误日志中错误的来源是 HikariPool ,我们来重新配置一下这个连接池的参数,将最大连接数修改为100,具体配置如下:

# 连接池中允许的最小连接数。缺省值:10 spring.datasource.hikari.minimum-idle=10 # 连接池中允许的最大连接数。缺省值:10 spring.datasource.hikari.maximum-pool-size=100 # 自动提交 spring.datasource.hikari.auto-commit=true # 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟 spring.datasource.hikari.idle-timeout=30000 # 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒 spring.datasource.hikari.max-lifetime=1800000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒 复制代码

再次执行测试发现没有报错,修改线程数为20又执行了一下,同样执行成功了。

五、基于TransactionStatus集合来控制多线程事务提交

在同事推荐下我们使用事务集合来进行多线程事务控制,主要代码如下

@Service public class StudentsTransactionThread { @Autowired private StudentMapper studentMapper; @Autowired private StudentService studentService; @Autowired private PlatformTransactionManager transactionManager; List<TransactionStatus> transactionStatuses = Collections.synchronizedList(new ArrayList<TransactionStatus>()); @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class}) public void updateStudentWithThreadsAndTrans() throws InterruptedException { //查询总数据 List<Student> allStudents = studentMapper.getAll(); // 线程数量 final Integer threadCount = 2; //每个线程处理的数据量 final Integer dataPartionLength = (allStudents.size() + threadCount - 1) / threadCount; // 创建多线程处理任务 ExecutorService studentThreadPool = Executors.newFixedThreadPool(threadCount); CountDownLatch threadLatchs = new CountDownLatch(threadCount); AtomicBoolean isError = new AtomicBoolean(false); try { for (int i = 0; i < threadCount; i++) { // 每个线程处理的数据 List<Student> threadDatas = allStudents.stream() .skip(i * dataPartionLength).limit(dataPartionLength).collect(Collectors.toList()); studentThreadPool.execute(() -> { try { try { studentService.updateStudentsTransaction(transactionManager, transactionStatuses, threadDatas); } catch (Throwable e) { e.printStackTrace(); isError.set(true); }finally { threadLatchs.countDown(); } } catch (Exception e) { e.printStackTrace(); isError.set(true); } }); } // 倒计时锁设置超时时间 30s boolean await = threadLatchs.await(30, TimeUnit.SECONDS); // 判断是否超时 if (!await) { isError.set(true); } } catch (Throwable e) { e.printStackTrace(); isError.set(true); } if (!transactionStatuses.isEmpty()) { if (isError.get()) { transactionStatuses.forEach(s -> transactionManager.rollback(s)); } else { transactionStatuses.forEach(s -> transactionManager.commit(s)); } } System.out.println("主线程完成"); } } 复制代码

@Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class}) public void updateStudentsTransaction(PlatformTransactionManager transactionManager, List<TransactionStatus> transactionStatuses, List<Student> students) { // 使用这种方式将事务状态都放在同一个事务里面 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。 TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态 transactionStatuses.add(status); students.forEach(s -> { // 更新教师信息 // String teacher = s.getTeacher(); String newTeacher = "TNO_" + new Random().nextInt(100); s.setTeacher(newTeacher); studentMapper.update(s); }); System.out.println("子线程:" + Thread.currentThread().getName()); } 复制代码

由于这个中方式去前面方式相同,需要等待线程执行完成后才会提交事务,所有任会占用Jdbc连接池,如果线程数量超过连接池最大数量会产生连接超时。所以在使用过程中任要控制线程数量,

六、使用union连接多个select实现批量update

有些情况写不支持,批量update,但支持insert 多条数据,这个时候可尝试将需要更新的数据拼接成多条select 语句,然后使用union 连接起来,再使用update 关联这个数据进行update,具体代码演示如下:

update student,( (select 1 as id,'teacher_A' as teacher) union (select 2 as id,'teacher_A' as teacher) union (select 3 as id,'teacher_A' as teacher) union (select 4 as id,'teacher_A' as teacher) /* ....more data ... */ ) as new_teacher set student.teacher=new_teacher.teacher where student.id=new_teacher.id 复制代码

这种方式在Mysql 数据库没有配置 allowMultiQueries=true 也可以实现批量更新。

总结

  • 对于大批量数据库操作,使用手动事务提交可以很多程度上提高操作效率

  • 多线程对数据库进行操作时,并非线程数越多操作时间越快,按上述示例大约在2-5个线程时操作时间最快。

  • 对于多线程阻塞事务提交时,线程数量不能过多。

  • 如果能有办法实现批量更新那是最好

Java 多线程事务回滚 ——多线程插入数据库时事务控制 背景 日常项目中,经常会出现一个场景,同时批量插入数据库数据,由于逻辑复杂或者其它原因,我们无法使用sql进行批量插入,这个时候我们首先想到多线程并发插入,但是如何控制事务呢 … 直接上干货 实现效果 开启多条子线程,并发插入数据库 当其中一条线程出现异常,或者处理结果为非预期结果,则全部线程均回滚 代码实现 @Service public class CompanyUserBatchServ... 阅读详情

相关推荐

SpringBoot项目中控制线程池、多线程事务提交、回滚的方式

1、由于多线程每个线程都是一个异步任务,所以每个线程都是一个单独的事务,通常使用的声明式事务 @Transactional() 是无法控制多线程中事务的。成功写入10000条数据。插入数据过程中模拟出现异常,事务会全部回滚。此方式没有第一种方式可靠,推荐第一种方式。2、所以只能另寻解决方式。

hkl_Forever的博客 5788

Java多线程数据库事务提交控制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、循环操作的代码 二、使用事务的操作代码 三、尝试多线程进行数据修改 四、为多线程提交添加事务控制 总结 前言 公司业务中遇到一个需求,需要同时修改最多约5万条数据,而且还不支持批量或异步修改操作。循环操作耗时太长,为提高效率我进行了下面这个测试,具体操作如下: 一、循环操作的代码 /*** * 一条一条依次对50000条数据进行更新操作 * ...

JohnChen(Net) 6760

2024广东省职业技能大赛云计算——集群部署GitLab

题目是这样的:在Kubernetes集群中新建命名空间gitlab-ci,将GitLab部署到该命名空间下,Deployment和Service名称均为gitlab,以NodePort方式将80端口对外暴露为30880,设置GitLab服务root用户的密码为admin@123,将项目包demo-2048.tar.gz导入到GitLab中并命名为demo-2048。GitLab是一个功能强大且灵活的 DevOps 平台,为开发团队和企业提供了从代码管理到持续集成、交付和部署的一整套解决方案。

kuuuugua的博客 4398

Java 多线程如何做到事务控制

公司业务中遇到一个需求,需要同时修改最多约5万条数据,而且还不支持批量或异步修改操作。于是只能写个for循环操作,但操作耗时太长,只能一步一步寻找其他解决方案。对于大批量数据库操作,使用手动事务提交可以很多程度上提高操作效率多线程对数据库进行操作时,并非线程数越多操作时间越快,按上述示例大约在2-5个线程时操作时间最快。对于多线程阻塞事务提交时,线程数量不能过多。来源 | https://blog.youkuaiyun.com/qq273766764/article/details/119972911。

竹林幽深 3531

手把手教你用EG2153搭建开关电源:SOP-8封装驱动芯片的5个设计技巧

本文详细介绍了使用EG2153自振荡半桥驱动芯片搭建开关电源的五个核心设计技巧。内容涵盖从深入理解芯片工作机制、频率编程计算误区、SOP-8封装的热管理方案,到死区时间评估与外部保护电路设计,以及实战调试与故障排查指南,旨在帮助工程师实现稳定可靠的小功率电源设计。

weixin_29200485的博客 380

GIS国土工具实战:从地类分析到坐标转换,一站式解决项目难题

本文详细介绍了GIS国土工具在国土整治项目中的高效应用,涵盖地类分析、坐标转换、影像加载等核心功能。通过实战案例展示如何利用该工具快速处理shp与txt文件转换、智能比对三调二调数据,以及优化影像加载策略,显著提升项目效率。特别适合需要处理复杂国土数据的专业人员使用。

weixin_28732953的博客 335

springboot启动,报jdbc连接池的错误

2017-03-07 11:40:16.127 ERROR 31460 --- [pool-1-thread-1] o.a.tomcat.jdbc.pool.ConnectionPool      : Unable to create initial connections of pool. com.mysql.jdbc.exceptions.jdbc4.CommunicationsEx

jshaxxl的博客 4万+

量化策略分享之ST股弱转强,回测年化123%

本策略的核心是精选ST股票,国九条过滤,防止直接暴雷退市,只做ST股票的弱转强,弱转强的认定标准是前日涨停但昨日不涨停,昨日收盘价大于前一日最低价,昨日收盘价大于10日线,昨日成交量大于前一日的成交量但小于前一日成交量的10倍,股价大于1;这类股票强势,有资金介入,能获得超额收益。

qq_29301281的博客 1269

手写Spring事务

<!-- 配置事物 --> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="...

程序员 639

【原创】汇川H5U PLC控制伺服的方法

6、在线调试-进入伺服调试,可以在本软件上进行调试,可以实现原点回归、正向点动、反向电动、使能(这里使能打开时触摸屏上的使能不能打开,会冲突)、复位、停止(如下图所示)。5、在原点返回设置中一般情况下对原点信号、正限位、负限位、原点返回方向、原点返回方式进行设置,其他设置默认不改(如下图所示)。3、在单位换算设置上只需要修改脉冲数和移动量(根据伺服配套导轨上名牌进行设置),其他设置默认不改(如下图所示)。11、双击后右边出现编辑框 在上半部分定义变量(IN、INOUT、OUT、VAR)(如下图所示)。

Qinmingyue13的博客 6675

文章ACCEPT之后填写内容教程-Springer-Verlag即施普林格

1. 确认corresponding author通讯作者机构是否正确(最好细分到系,如搜不到系只填大学也可)这些信息因为在投稿的时候都填过,所以一般都没问题,可确认并继续。2. Co-Author: 这篇文章有没有其他作者,如果有就选yes,并确认投稿时所填的作者姓名和机构是否正确。这个也是如果前期都填对了就不用修改。3. Research funders: 问文章的研究有没有资助,没有就选no,有就选yes,并填写机构名称和grant/contact numbers。

ZhangJiqun&191cm&85kg 4796

Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.DataSourc

项目中使用了阿里的 Druid 数据库,刚开始很正常,后来发现出现了问题,问题如下: 日志比较多,重点有以下几个: 其他的我们截图看看: 上图打码的地方是公司的dao层查数据库的代码。意思很明白了,就是因为在进行查询的时候,连接已经关闭了,而且会一直刷出这样的日志。综合网上大家的意见,可能原因主要有以下几点: 博主给的答案是: 参考:Druid连接池自动关闭其实这个答案和上面一个的说法一致,不过这个给出了解决方案:是否在定时器中手动获取了 DataSource,然后使用后关闭了或者用完后长期不再用被连接池自

帝上无天的博客 2万+

23 RAG 为什么答不准:召回、分块、排序的常见坑

RAG 答不准时,不要先怪模型。本文把常见失败拆成召回不到、召回不准、分块不完整、排序靠后、上下文污染和生成不忠实六类,并给出从 Top-K 检查到评估集的排查流程。

老于的笔记的专栏 248

Java 多线程怎么做事务控制

Java 多线程怎么做事务控制

wgq2020的博客 7806

H3C BGP联盟实验

bgp,bgp联盟,bgp公认团体属性,

一只懒羊羊 971

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

spring 事务管理

一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是ACID: 原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。 一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。 隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。 持久性:一个事务一旦完成全部操作后,这个事务的结果必须是.

qq_31603875的博客 1761

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Spring中使用DataSourceTransactionManager手动提交或回滚事务

      在使用spring进行web开发时,虽然spring提供的注解方式可以方便的处理很多原来需要手动提交或回滚的事务,但是注解方式有自己使用的局限,比如在类的内部调用方法时,注解方式处理的事务就无法被触发,此时可能需要手动处理相关数据库的事务。本文记录在spring开发时使用Spring提供的DataSourceTransactionManager进行事务提交或回滚处理。主要步骤如下:1、...

yxhxj2006的专栏 1万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

org.springframework.jdbc.datasource.DriverManagerDataSource ORACLE11G

org.springframework.jdbc.datasource.DriverManagerDataSource ORACLE11G

qq 117791303 1415

解决多线程事务问题

spring的声明式事务在多线程式,并不会生效。可以使用spring提供的编程式事务解决。亲测有效,至于网上的提供的一些 生成线程屏障的方法 试了下不行,也不知道是不是我的问题。第三步:将上面的放入多线程中,线程池和new 线程都可以。第一步:使用spring提供的编程式事务。核心思路是为每一个线程都开辟一个事务。第二步:在代码逻辑处写入业务逻辑。

记录点点滴滴的成长。 4853

JAVA使用多线程操作集合中的数据(不会重复调用集合中的数据哦)--详解

当你想使用JAVA的多线程对一个集合进行处理的时候,我们可以将一个集合分成Thread份数据,每份数据交给一个线程执行 import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class TestApp { private static final String model = TestApp.class.getName(); public static voi

weixin_48960305的博客 4043

Java 多线程批量处理数据

在项目开发中需要处理100万多的数据,这些数据需要从mysql数据库中读取出来,再通过调用其他平台的接口推送数据。由于时间紧迫,数据需要在短时间内完成推送,采用单线程推送很慢,所以采用多线程推送来提高效率。

记录工作开发中遇到的技术难点,方便自己查看,也希望可以帮助到他人... 4123

Java基础:线程池

线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。合理利用线程池能够带来三个好处:降低资源消耗。提高响应速度。提高线程的可管理性。使用线程池中线程对象的步骤:创建线程池对象。 创建Runnable接口子类对象。(task) 提交Runnable接口子类对象。(take task) 关闭线程池(一般不做)。

时代各有不同,青春一脉相承。 584

关于线程池与事务的注意问题

关于线程池与事务的注意问题

guntun8987的博客 2312

Java使用线程池批量处理数据操作

1.如何保证数据按顺序批量处理 2.如何保证数据全部处理完统一返回 3.如何保证是多任务异步操作 4.如何提高运行效率,减少运行时间

weixin_44030476的博客 6552

Java多线程下使用TransactionTemplate控制事务

本文展示了在Java的多线程环境下使用Spring的TransactionTemplate控制事务的提交与回滚,当任何一个子线程出现异常时,所有子线程都将回滚。

cm777的博客 2833

java多线程事务处理

多线程事务

m0_49804107的博客 6063
上一篇: 什么是JVM系列的javaagent
下一篇: 捋一捋,让你知道什么是分布式事务解决方案
Java_LingFeng
博客等级 码龄4年 505粉丝 259原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值