9、Spring_事务管理

news2024/11/18 15:29:23

六、Spring 事务管理

1.Spring 事务简介

  • 事务概述:保证数据库操作同时成功或者同时失败

  • Spring 事务的概述:在数据层保证数据库操作同时成功或者同时失败

2.转账案例分析

  • 转账肯定有一个业务方法:给转出用户减钱,给转入用户加钱
  • 要求:
    • 要么同时成功要么同时失败

2.1Spring 平台事务管理器

  • 提供规范接口

    public interface PlatformTransactionManager {
        TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
    
        void commit(TransactionStatus var1) throws TransactionException;
    
        void rollback(TransactionStatus var1) throws TransactionException;
    }
    
  • 方法

    • void commit(TransactionStatus var1):用于提交事务
    • void rollback(TransactionStatus var1):用户事务回滚
  • 具体实现:DataSourceTransactionManager 来实现的,通过DataSource dataSource 以 JDBC 事务的方式来控制事务在这里插入图片描述

2.2转账案例分析

  • 业务分析

    • 在业务层需要保证事务的同时成功或者同时失败
    • 结果
      • 出现异常:张三转账给李四,比如中途出现问题,张三的钱和李四的钱应该不出现误差
      • 没有出现异常:张三转账给李四,没有出现问题,张三的钱正常减少,李四的钱正常增多
  • 提供service 方法

    public interface IAccountService {
        /**
         * 实现转账操作
         * @param srcId 转账人
         * @param deskId 接收人
         * @param money 转账金额
         */
        public void transfer(Long srcId,Long deskId,int money);
    }
    
  • 下载插件的官方地址 https://plugins.jetbrains.com/

  • 提供service 实现方法

    @Service
    public class AccountServiceImpl implements IAccountService {
    
        //会使用到 mapper
        @Autowired
        private AccountMapper mapper;
    
        public void transfer(Long srcId, Long deskId, int money) {
            mapper.outAccount(srcId,money);//转账扣钱
    
            mapper.inAccount(deskId,money);//接收转账钱
        }
    }
    
  • 提供 mapper 接口

    public interface AccountMapper {
        void outAccount(@Param("id") Long srcId, @Param("money") int money);
    
        void inAccount(@Param("id")Long deskId,@Param("money") int money);
    }
    
  • 提供 mapper.xml

    </update>
        <update id="outAccount">
        update account
        set money = money-#{money,jdbcType=INTEGER}
        where id = #{id,jdbcType=BIGINT}
        </update>
      <update id="inAccount">
        update account
        set money = money+#{money,jdbcType=INTEGER}
        where id = #{id,jdbcType=BIGINT}
      </update>
    
  • 测试

     @Test
        public void testMybatis(){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
            IAccountService bean = context.getBean(IAccountService.class);
            bean.transfer(1L,2L,500);
    
        }
    

3.基于注解的方式实现

3.1@EnableTransactionManagement

  • @EnableTransactionManagement:用于开启事务支持的,直接添加到spring 配置类

  • 说明

    名称@EnableTransactionManagement
    位置配置类上方
    作用设置当前spring环境支持事务
  • 修改配置类

    @Configuration
    @ComponentScan("cn.sycoder")
    @PropertySource("db.properties")
    @Import({JdbcConfig.class,MyBatisConfig.class})
    //开启事务支持
    @EnableTransactionManagement
    public class SpringConfig {
    }
    

3.2 配置事务管理,配置数据源

  • 如果不配置的话会报:找不到数据源错误
    在这里插入图片描述

  • PlatformTransactionManager

  • 代码

    public class JdbcConfig {
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
        @Value("${jdbc.driverClassName}")
        private String driverClassName;
        @Value("${jdbc.url}")
        private String url;
        //配置连接池
        @Bean
        public DataSource dataSource(){
            DruidDataSource source = new DruidDataSource();
            source.setUsername(username);
            source.setPassword(password);
            source.setDriverClassName(driverClassName);
            source.setUrl(url);
            return source;
        }
    
        @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource){
            DataSourceTransactionManager manager = new DataSourceTransactionManager();
            manager.setDataSource(dataSource);
            return manager;
        }
    }
    

3.3 @Transactional

  • @Transactional:为业务添加事务的

  • 说明

    名称@Transactional
    位置业务层接口上方,或者实现类上方,或者具体业务方法上方
    作用为当前的业务方法添加事务支持
  • 修改业务层

    • 业务方法上添加

      @Transactional
      public void transfer(Long srcId, Long deskId, int money) {
          mapper.outAccount(srcId,money);//转账扣钱
          System.out.println(1/0);
          mapper.inAccount(deskId,money);//接收转账钱
      }
      
    • 业务类上添加

      @Service
      @Transactional
      public class AccountServiceImpl implements IAccountService {
      
          //会使用到 mapper
          @Autowired
          private AccountMapper mapper;
      
      
          public void transfer(Long srcId, Long deskId, int money) {
              mapper.outAccount(srcId,money);//转账扣钱
              System.out.println(1/0);
              mapper.inAccount(deskId,money);//接收转账钱
          }
      }
      
    • 接口层添加

      @Transactional
      public interface IAccountService {
          /**
           * 实现转账操作
           * @param srcId 转账人
           * @param deskId 接收人
           * @param money 转账金额
           */
          public void transfer(Long srcId,Long deskId,int money);
      }
      

    4.事务角色

  • 在没有开启Spring事务之前:两条语句分别开启两个事务 T1 和 T2

    • 如果同时成功,T1和T2都会正常提交
    • 如果T1正常,T2之前抛出异常,就会出现T1能够正常转账,但是T2收不到钱,因为不是同一个事务导致金钱异常
    public void transfer(Long srcId, Long deskId, int money) {
        mapper.outAccount(srcId,money);//转账扣钱
        System.out.println(1/0);
        mapper.inAccount(deskId,money);//接收转账钱
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KE12TXbZ-1693295276398)(picture/image-20221105210048391.png)]

  • 开启Spring 事务管理之后

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZQEeOh60-1693295276399)(picture/image-20221105210911281.png)]

    • 在转账 transfer 方法上加入 @Transactional 注解之后,该方法会新建一个事务T
    • 把 mapper 中 outAccount 事务 T1 加入到 事务T中,把 mapper 中 inAccount 事务 T2 也加入到事务T中
    • 通过 @Transactional 注解统一了 transfer 方法的事务保证转账和入账方法变成同一事务操作

4.1事务管理员&事务协调员

  • 事务管理员:发起新事务,使用 @Transactional 注解开启事务
  • 事务协调员:加入新事务,保证多个事务变成同一事务下的操作

5.@Transactional 属性

5.1 readOnly

  • 概述:表示只读,没有写操作。可以通过这个属性告诉数据库我们没有写操作,从而数据库可以针对只读sql做优化操作

  • 使用

    @Transactional(readOnly = true)
    public Account selectById(Long id){
        return mapper.selectByPrimaryKey(id);
    }
    
  • 如果对于有写操作的使用这个属性,会报如下错误

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lhqysmIG-1693295276402)(picture/image-20221105212707549.png)]

5.2 timeout

  • 超时概述:事务再执行的时候,由于某些原因卡住,长时间占用数据库资源。此时很可能程序sql有问题,希望撤销事务,能够让事务结束,释放资源,即超时回滚。

  • 默认值是-1.-1表示用不回滚,单位是秒

  • int timeout() default -1;
    
  • 使用

    @Transactional(readOnly = true,timeout = 1)
        public Account selectById(Long id){
            try {
                Thread.sleep(10000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return mapper.selectByPrimaryKey(id);
        }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hamXB1vD-1693295276402)(picture/image-20221105213517098.png)]

5.3 rollbackFor&rollbackForClassName

  • 回滚概述:回滚策略,希望对于什么样的异常回顾

  • 注意:并不是所有的异常 Spring 都会回滚,Spring 只对 Error 异常和 RuntimeException 异常回滚

  • 使用

    @Transactional(rollbackFor = IOException.class)
        public void transfer(Long srcId, Long deskId, int money) throws IOException {
            mapper.outAccount(srcId,money);//转账扣钱
            if(true){
                throw new IOException("");
            }
            mapper.inAccount(deskId,money);//接收转账钱
        }
    
    @Transactional(rollbackForClassName = "IOException")
        public void transfer(Long srcId, Long deskId, int money) throws IOException {
            mapper.outAccount(srcId,money);//转账扣钱
            if(true){
                throw new IOException("");
            }
            mapper.inAccount(deskId,money);//接收转账钱
        }
    

5.4 noRollbackFor&noRollbackForClassName

  • 不会滚概述:出现这个异常不回滚

  • 使用

    @Transactional(noRollbackFor = ArithmeticException.class)
        public void transfer(Long srcId, Long deskId, int money) throws IOException {
            mapper.outAccount(srcId,money);//转账扣钱
            System.out.println(1/0);
            mapper.inAccount(deskId,money);//接收转账钱
        }
    
    @Transactional(noRollbackForClassName = "ArithmeticException")
        public void transfer(Long srcId, Long deskId, int money) throws IOException {
            mapper.outAccount(srcId,money);//转账扣钱
            System.out.println(1/0);
            mapper.inAccount(deskId,money);//接收转账钱
        }
    

5.5 isolation

  • 概述:设置事务隔离级别;

  • 如果不记得事务隔离级别,回去复习一下我讲的MySql

    • DEFAULT :默认隔离级别, 会采用数据库的隔离级别
    • READ_UNCOMMITTED : 读未提交
    • READ_COMMITTED : 读已提交
    • REPEATABLE_READ : 重复读取
    • SERIALIZABLE: 串行化
  • 使用

    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public Account selectById(Long id) throws IOException {
        return mapper.selectByPrimaryKey(id);
    }
    

5.6propagation

  • 事务传播行为:事务协调员对事务管理员所携带的事务的处理态度

  • 说明

    传播属性说明
    REQUIRED外围方法会开启新事务,内部方法会加入到外部方法的事务中
    SUPPORTS外围方法没有事务,则内部方法不执行事务
    MANDATORY使用当前事务,如果当前没有事务就抛异常
    REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起
    NOT_SUPPORTED不支持事务
    NEVER不支持事务,如果存在事务还会抛异常
    NESTED如果当前存在事务,则在嵌套事务内执行,如果不存在,执行REQUIRED类似操作
  • 实操

    • REQUIRED:T1和T2会加入T中

      @Transactional(propagation = Propagation.REQUIRED)//事务T
      public void transfer(Long srcId, Long deskId, int money) throws IOException {
          mapper.outAccount(srcId,money);//转账扣钱 //事务T1
          System.out.println(1/0);
          mapper.inAccount(deskId,money);//接收转账钱 //事务T2
      }
      
    • SUPPORTS:外围没事务,所以内部只执行自己的事务,T1 和 T2 单独执行

      public void transfer(Long srcId, Long deskId, int money) throws IOException {
              mapper.outAccount(srcId,money);//转账扣钱//事务T1
              System.out.println(1/0);
              mapper.inAccount(deskId,money);//接收转账钱//事务T2
          }
      
    • REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起

       @Transactional(propagation=Propagation.REQUIRES_NEW)
          public void outAccount(Long id,  int money){
              mapper.outAccount(id,money);//转账扣钱
          }
      
          @Transactional(propagation=Propagation.REQUIRES_NEW)
          public void inAccount(Long id,  int money){
              mapper.inAccount(id,money);//转账扣钱
          }
      
      public void transfer(Long srcId, Long deskId, int money) throws IOException {
          outAccount(srcId,money);
          inAccount(deskId,money);
          throw new RuntimeException();
      
      }
      
      • 这种情况上面一条语句能够正常执行
      @Transactional(propagation = Propagation.REQUIRES_NEW)
          public void outAccount(Long id, int money) {
              mapper.outAccount(id, money);//转账扣钱
          }
      
          @Transactional(propagation = Propagation.REQUIRES_NEW)
          public void inAccount(Long id, int money) {
              if (true)
                  throw new RuntimeException();
              mapper.inAccount(id, money);//转账扣钱
          }
      

6.基于XML事务

  • 导入依赖

    <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.17.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>5.2.17.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <!--            <scope>test</scope>-->
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.29</version>
            </dependency>
            <!--        spring 整合 mybatis 的包-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>
            <!--        mybatis 包-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
            </dependency>
            <!--        spring 操作 jdbc 包-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>4.3.29.RELEASE</version>
            </dependency>
        </dependencies>
    
  • 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="accountService" class="cn.sycoder.service.impl.AccountServiceImpl">
    <!--        <property name="mapper" ref="mapper"/>-->
        </bean>
        <!--    <bean id="mapper" class="cn.sycoder.mapper.AccountMapper"></bean>-->
    
        <aop:config>
            <aop:advisor advice-ref="tx" pointcut="execution(* cn.sycoder.service.impl.*.*(..))"></aop:advisor>
        </aop:config>
    
        <tx:advice id="tx" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="get*" read-only="true"/>
            </tx:attributes>
        </tx:advice>
    
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- (this dependency is defined somewhere else) -->
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        <context:property-placeholder location="db.properties"/>
    
    
    </beans>
    
  • 配置详解

    • 引入db.properties

      <context:property-placeholder location="db.properties"/>
      
    • 配置连接池

      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <property name="driverClassName" value="${jdbc.driverClassName}"/>
          <property name="url" value="${jdbc.url}"/>
          <property name="username" value="${jdbc.username}"/>
          <property name="password" value="${jdbc.password}"/>
      </bean>
      
    • 配置事务管理器

      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"/>
      </bean>
      
    • 配置 aop 事务增强

      <aop:config>
              <aop:advisor advice-ref="tx" pointcut="execution(* cn.sycoder.service.impl.*.*(..))"/>
      </aop:config>
              
      <tx:advice id="tx" transaction-manager="txManager">
          <tx:attributes>
              <tx:method name="get*" read-only="true"/>
          </tx:attributes>
      </tx:advice>    
      
  • 注意:如果你还想通过 xml 配置 mybatis ,那么你还需要把 mybatis 配置文件搞一份过来,通过xml 配置好 mybatis 之后,然后再获取 sqlSessionFactory 去获取 mapper 文件

  • 注意:spring 是面试重头戏,所以,你需要花时间认真巩固和复习,ioc 和 di 特别是对于常用注解,以及事务机制,aop 等都很爱问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/946577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java+Github+Jenkins部署

Java项目—Jenkins部署笔记 一&#xff0c;准备 一台服务器操作系统&#xff0c;示例为ubuntu 22.0.4 可运行lsb_release -a查看 二&#xff0c;安装 docker 更新软件包列表&#xff1a; sudo apt update安装必要的软件包&#xff0c;以便使用HTTPS通过APT下载软件包&#x…

财务大模型,产业路向何方?

无论过去还是将来&#xff0c;财务的角色和意义都不会被颠覆&#xff0c;只会被清晰化&#xff0c;只会回归到本源。 作者|思杭 编辑|皮爷 出品|产业家 “今年&#xff0c;我们被市场倒逼着做数字化转型。一切都被打乱了&#xff0c;像这样的转变是前所未有的。到了8月&…

泰迪大数据实训平台产品介绍

大数据产品包括&#xff1a;大数据实训管理平台、大数据开发实训平台、大数据编程实训平台等 大数据实训管理平台 泰迪大数据实训平台从课程管理、资源管理、实训管理等方面出发&#xff0c;主要解决现有实验室无法满足教学需求、传统教学流程和工具低效耗时和内部教学…

hadoop 学习:mapreduce 入门案例三:顾客信息与订单信息相关联(联表)

这里的知识点在于如何合并两张表&#xff0c;事实上这种业务场景我们很熟悉了&#xff0c;这就是我们在学习 MySQL 的时候接触到的内连接&#xff0c;左连接&#xff0c;而现在我们要学习 mapreduce 中的做法 这里我们可以选择在 map 阶段和reduce阶段去做 数据&#xff1a; …

聚合支付-第3章-支付宝支付接入指南

惠民支付 第3章讲义-支付宝接入指南 支付宝接入步骤: 1、进入网址https://open.alipay.com/develop/manage 2、扫码登录支付宝账号&#xff0c;控制台&#xff0c;最下边有一个沙箱环境 3、在“支付宝开放平台开发助手”软件中生成密钥&#xff0c;点击生成密钥&#xff0c;保…

Axure RP 8.1.0.3400(原型设计工具)

Axure RP 8是一款原型设计工具&#xff0c;它提供了丰富的功能和工具&#xff0c;帮助用户创建高质量的网页、移动应用和桌面软件原型。以下是Axure RP 8的一些特色介绍&#xff1a; 强大的交互设计&#xff1a;Axure RP 8支持创建复杂的动画和过渡效果&#xff0c;让你的原型更…

一文彻底扒光 Handler

作者&#xff1a;HenAndroid 典型的生产者-消费者模式。 Android跨进程要掌握的是Binder, 而同一进程中最重要的应该就是Handler 消息通信机制了。我这么说&#xff0c;大家不知道是否认同&#xff0c;如果认同&#xff0c;还希望能给一个关注哈。 Handler 是什么&#xff1f;…

AI智能语音识别模块(一)——离线模组介绍

文章目录 离线语音控制模块简介引脚定义开发平台总结 离线语音控制模块 简介 这是一款低成本&#xff0c;低功耗&#xff0c;小体积的高性价比离线语音识别开发板。能快速学习、验证离线语音控制各种外设&#xff0c;如继电器、LED灯&#xff0c;PWM调光等。 板载了Micro USB接…

MySQL DATE_SUB的实践

函数简介DATE_SUB()函数从DATE或DATETIME值中减去时间值(或间隔)。 下面说明了DATE_SUB()函数的语法&#xff1a; DATE_SUB(start_date,INTERVAL expr unit); DATE_SUB()函数接受两个参数&#xff1a; start_date是DATE或DATETIME的起始值。 expr是一个字符串&#xff0c;用于确…

哪个牌子的电视盒子好用?小编盘点复购率最高电视盒子排行榜

复购率可以体现出产品评价如何&#xff0c;电视盒子是我们经常要购买的数码产品&#xff0c;那么电视盒子哪些品牌的复购率最高&#xff1f;用户忠实度最高呢&#xff1f;想了解哪个牌子的电视盒子好用&#xff0c;可以看看小编根据复购情况整理的电视盒子排行榜&#xff1a; ●…

Weblogic漏洞(三)之 Weblogic 弱口令、任意文件读取漏洞

Weblogic 弱口令、任意文件读取漏洞 环境安装 此次我们实验的靶场&#xff0c;是vnlhub中的Weblogic漏洞中的weak_password靶场&#xff0c;我们 cd 到weak_password&#xff0c;然后输入以下命令启动靶场环境&#xff1a; docker-compose up -d输入以下的命令可以查看当前启…

问道管理:仙人指路最佳买入形态?

仙人指路是一种基于技能剖析的股票交易目标。许多投资者运用该目标来预测股票价格的上涨或下跌趋势。在买入股票时&#xff0c;仙人指路能够为投资者供给有用的信息&#xff0c;协助他们找到最佳的买入形状。本文将从多个视点剖析仙人指路的最佳买入形状。 一、仙人指路的基本原…

适合本地运营的同城团购优质商家圈子小程序开发演示

很火的一款适合本地同城运营的同城团购商家圈子小程序。有很多城市都有在用这个小程序做同城资源&#xff0c;实现完美变现。 小程序功能就是将本地商家邀请入驻&#xff0c;以团购的形式出售商家产品或服务套餐。借助微信的社交属性配合同城推广员可以迅速推广起来。 对于商…

网络安全法+网络安全等级保护

网络安全法 网络安全法21条 网络安全法31条 网络安全等级保护 网络安全等级保护分为几级? 一个中心&#xff0c;三重防护 等级保护2.0网络拓扑图 安全区域边界 安全计算环境 等保安全产品 物理机房安全设计

Autofac中多个类继承同一个接口,如何注入?与抽象工厂模式相结合

多个类继承同一个接口,如何注入&#xff1f;与抽象工厂模式相结合 需求: 原来是抽象工厂模式,多个类继承同一个接口。 现在需要使用Autofac进行选择性注入。 Autofac默认常识: Autofac中多个类继承同一个接口,默认是最后一个接口注入的类。 解决方案&#xff1a;(约定大于配…

nodepad++ 插件的安装

nodepad 插件的安装 一、插件安装二、安装插件&#xff1a;Json Viewer nodepad 有 插件管理功能&#xff0c;其中有格式化json以及可以将json作为树查看的插件&#xff1a; Json Viewer 一、插件安装 1、首先下载最新的notepad 64位【https://notepad-plus.en.softonic.com…

Java——一个简单的计算器程序

该代码是一个简单的计算器程序&#xff0c;使用了Java的图形化界面库Swing。具体分析如下&#xff1a; 导入必要的类和包&#xff1a; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Objects; import javax.…

Java 中数据结构HashMap的用法

Java HashMap HashMap 是一个散列表&#xff0c;它存储的内容是键值对(key-value)映射。 HashMap 实现了 Map 接口&#xff0c;根据键的 HashCode 值存储数据&#xff0c;具有很快的访问速度&#xff0c;最多允许一条记录的键为 null&#xff0c;不支持线程同步。 HashMap 是…

打通数字化供需“堵点”,828 B2B企业节推出企业应用一站购平台

当前&#xff0c;数字技术与实体经济深度融合&#xff0c;为千行百业注入新动力、拓展新空间。数据显示&#xff0c;2022年中国数字经济规模超过50万亿&#xff0c;占GDP比重超过40%&#xff0c;继续保持在10%的高位增长速度&#xff0c;成为稳定经济增长的关键动力。 为加速企…

智慧校园用电安全解决方案

随着科技的不断发展&#xff0c;智慧校园建设逐渐成为了教育行业的一大趋势。在这个过程中&#xff0c;电力系统作为校园基础设施的重要组成部分&#xff0c;其安全、稳定、高效的运行显得尤为重要。下面小编来为大家介绍下智慧校园用电安全解决方案吧! 一、智慧校园电力系统现…