SpringBoot一个提升N倍性能的操作

 环境:springboot2.3.9.RELEASE + JPA + MySQL

创新互联是一家集网站建设,溆浦企业网站建设,溆浦品牌网站建设,网站定制,溆浦网站建设报价,网络营销,网络优化,溆浦网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

一般我们在spring项目中都是在方法或者是类上添加事务支持,如下使用方式:

 
 
 
 
  1. @Transactional 
  2. public Account deduction(Long id, BigDecimal money) { 
  3.         Optional op = accountDAO.findById(id); 
  4.       if (!op.isPresent()) { 
  5.           throw new RuntimeException("不存在"); 
  6.       } 
  7.       account.setMoney(account.getMoney().subtract(money)) ; 
  8.           return accountDAO.saveAndFlush(account) ; 

 以上应该是我们在项目中使用事务的姿势了。这里是方法级别的事务,当方法执行的时候通过动态代理打开事务,执行代码,提交事务/回滚事务,执行的逻辑大体如下:

 
 
 
 
  1. transaction.begin(); 
  2. method.invoke(xxxx); 
  3. transaction.commit(); / transaction.rollback(); 

 在上面举的示例比较简单,整个操作就是计算扣减金额,然后更新数据。这个业务也就是在保存数据的时候需要使用到事务,其它的一些计算是不需要在一个事务中的。想象下如果我们这里保存操作之上的代码,计算逻辑是个非常复杂的逻辑可能需要消耗好几秒甚至是十几秒而实际保存操作可能就几毫秒就完成了。我们又知道这方法级的事务在执行的时候是要先获取一个Connection对象(数据库连接对象的)然后打开事务(设置自动提交为false,connection.setAutoCommit(false));说到这你应该能想到,从获取一个Connection对象到释放需要几秒甚至是十几秒的时间,而占用的这些时间中大部分的时间都是与事务无关的操作也就是说是不需要事务的,而我们的数据库连接对象本身就是很宝贵及有限的,这就造成了我们系统的资源浪费,系统的吞吐量非常的低。接下来我们就来通过编程的方式控制事务提供系统的吞吐量。

模拟常规的事务,展现低吞吐量操作

数据库连接配置:

 
 
 
 
  1. spring: 
  2.   datasource: 
  3.     driverClassName: com.mysql.cj.jdbc.Driver 
  4.     url: jdbc:mysql://localhost:3306/x?serverTimezone=GMT%2B8 
  5.     username: root 
  6.     password: xxxx 
  7.     type: com.zaxxer.hikari.HikariDataSource 
  8.     hikari: 
  9.       minimumIdle: 1 
  10.       maximumPoolSize: 1 
  11.       autoCommit: true 
  12.       idleTimeout: 30000 
  13.       poolName: MasterDatabookHikariCP 
  14.       maxLifetime: 1800000 
  15.       connectionTimeout: 30000 
  16.       connectionTestQuery: SELECT 1 

 这里把数据库连接池配置为1个。

Service中模拟耗时的操作

 
 
 
 
  1. @Transactional 
  2. public Account deduction(Long id, BigDecimal money) { 
  3.         System.out.println("Service 当前执行线程:" + Thread.currentThread().getName() + ", id = " + id + ", money = " + money) ; 
  4.         Account account = accountDAO.findById(id).orElse(null) ; 
  5.         if (account == null) { 
  6.             return null ; 
  7.         } 
  8.         try { 
  9.             TimeUnit.SECONDS.sleep(10) ; 
  10.         } catch (InterruptedException e) { 
  11.             e.printStackTrace(); 
  12.         } 
  13.         account.setMoney(account.getMoney().subtract(money)) ; 
  14.         return accountDAO.saveAndFlush(account) ; 

 Controller接口

 
 
 
 
  1. @GetMapping("/deduction") 
  2.     public Object deductionAction(Long id, BigDecimal money) { 
  3.         System.out.println("Controller 当前线程:" + Thread.currentThread().getName()) ; 
  4.         return accountService.deduction(id, money) ; 
  5.     } 

 启动两个浏览器测试,观察控制台的输出

两个浏览器都还在转圈,没有响应。

 控制台展示Controller方法都进入了,但是Service方法只进入了一个,因为我们的连接池只配置了一个,另外一个在等待可用的连接对象。而上面我也说了,其实Service中很长的一个计算耗时是不需要事务的,即便没有连接对象可用,我们也应该让这些不需要事务的操作也进行执行。接下来修改代码。

编程事务,提高系统吞吐量

 
 
 
 
  1. @Resource 
  2.     private TransactionTemplate transactionTemplate ; 
  3.      
  4.     public Account deduction(Long id, BigDecimal money) { 
  5.         System.out.println("Service 当前执行线程:" + Thread.currentThread().getName() + ", id = " + id + ", money = " + money) ; 
  6.         Account account = accountDAO.findById(id).orElse(null) ; 
  7.         if (account == null) { 
  8.             return null ; 
  9.         } 
  10.         try { 
  11.             TimeUnit.SECONDS.sleep(10) ; 
  12.         } catch (InterruptedException e) { 
  13.             e.printStackTrace(); 
  14.         } 
  15.         // 以上业务代码执行可能是个很耗时的操作。 
  16.         return transactionTemplate.execute(new TransactionCallback() { 
  17.             @Override 
  18.             public Account doInTransaction(TransactionStatus status) { 
  19.                 try { 
  20.                     account.setMoney(account.getMoney().subtract(money)) ; 
  21.                     return accountDAO.saveAndFlush(account) ; 
  22.                 } catch (Exception e) { 
  23.                     logger.error("发生错误:{}", e) ; 
  24.                     status.setRollbackOnly() ; 
  25.                 } 
  26.                 return null ; 
  27.             } 
  28.         }) ; 
  29.     } 

 这里把方法上的事务注解删了,把需要事务的操作通过编程的方式包装,在Service中注入

TransactionTemplate对象,SpringBoot项目已经自动为我们配置好了,自动装配类:

TransactionAutoConfiguration.java

测试:

浏览器都还在转圈中,查看控制台:

2个Service方法都进去了,基本连接池只有一个连接对象,但是也不妨碍我非事务的代码执行,通过这样的改造,我们的系统吞吐量是不是提升了N呢?

本文标题:SpringBoot一个提升N倍性能的操作
当前网址:http://www.gawzjz.com/qtweb2/news45/6695.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联