鸿蒙应用开发学习:使用视频播放(Video)组件播放视频和音频文件

一、前言

播放音视频是手机的重要功能之一,近期我学习了在鸿蒙系统应用开发中实现音视频的播放功能,应用中使用到了视频播放(Video)组件,@ohos.file.picker(选择器)。特撰此文分享一下我的学习经历。

二、参考资料

本次开发学习,主要参考了以下三个资料。

1.鸿蒙arkts的video组件简单使用示例

第一个资料是在CSDN社区里搜到了一篇简绍Video组件使用的博文,有现成的代码示例,一开始我就是参考了这篇博文的代码开始了视频和音频播放的学习。

2.官方开发文档(3.1/4.0)-指南-UI开发-添加组件-视频播放(Video)

第二个资料是官方网站内Video组件的指南,关于如何实现播放手机内的视频和音频相关知识,我参考了这个指南中的一些内容。

3.官方开发文档(3.1/4.0)-API参考-ArkTS接口参考-文件管理-@ohos.file.picker(选择器)

第三个资料是官方网站提供的文件管理器接口资料,获取手机内的视频的路径和音频文件路径的方法来自于这篇文档。

三、实现过程

1.先照着别人的教程试着做

最开始,我参照第一个链接中的内容,做了一个播放视频和音频的简单应用,利用Tabs组件制作了几个页面。其中标题为视频1和视频2的页面是参考了示例代码制作的,这两个页面都是播放的网络视频,视频地址来自于第一个链接提供的代码,在真机上测试可以正常播放。

第一个页面的初始状态,带自定义的控制器,播放的网络视频,后面又做了改动

第二个页面是Video组件的基础使用方法,播放的网络视频。

第二个页面的代码

TabContent() {
          Column({ space: 20 }) {
            Text("播放网络视频")
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
            Video({
              src: "https://vd3.bdstatic.com/mda-pmj5ajqd7p4b6pgb/576p/h264/1703044058699262355/mda-pmj5ajqd7p4b6pgb.mp4?auth_key=1703138418-0-0-618ea72b33be241c96c6cff86c06e080&bcevod_channel=searchbox_feed&cr=1&cd=0&pd=1&pt=4&logid=0018430194&vid=9762003448174112444&abtest=all"
            }).width("100%").aspectRatio(1.3)
          }
        }.tabBar("视频2")

第三个页面计划实现播放本地视频功能,但由于我没有示例中对应的视频资源,就没有照着做,需要另外想办法。第四个页面要实现播放音频功能,示例中给的音频链接不能正常访问,也无法正常播放,也需要另外想办法。

2.对播放本地视频的页面进行改进

参考资料中第一个链接里的示例中播放本地视频部分,需要将视频文件保存到项目的resources/rawfile文件夹下,等于是将视频写死了,而我希望通过浏览手机文件进行选择,实现播放手机内的任一本地视频的目的,因此需要对软件进行改进。

首先,我对参考资料中第二个链接的内容进行了学习,该文档中关于加载本地视频的知识除了使用资源访问符$rawfile()引用视频资源方法外,还有通Data Ability提供的视频路径频路径访问本地视频的方法。但这个Data Ability组件,我看了相关资料也没弄明白怎么用。让此事进入了死胡同。

但我之前学习了显示手机上的图片功能时,参考过一篇博文“【鸿蒙应用ArkTS开发系列】- 选择图片、文件和拍照功能实现”。这篇博文介绍了从手机相册和手机文件夹中选择图片,并在应用中显示的方法。我照着实现了该功能。该应用在显示图片信息的同时还会显示图片文件的Uri信息。我利用该功能从相册里选中视频文件后,虽然不能在应用中显示视频,但是视频的Uri信息确显示了出来。

手机上的视频文件

通过上述的显示手机图片的应用,从相册内选择视频文件

虽然视频文件没有显示出来,但文件Uri还是提供出来了(这是另外一个显示图片的应用)。

我尝试将Uri信息写入我的本地视频播放代码中,在真机上测试,可以播放(见下图)。

关键代码

Video({
              src:  "datashare:///media/video/914"   // 手机视频的路径
            }).width("100%").aspectRatio(1.3)

通过上面的测试,说明只要获取到视频文件的Uri信息,并将其赋值给Video组件的src参数后,就可以播放了。接下来的开发步骤就是实现获取视频文件的Uri并赋值给Video组件的src参数。

我通过对官方文档的研究发现,使用@ohos.file.picker (选择器)可以实现对视频和音频文件的选择(相关内容见第三个链接)。其中选择视频文件要用到PhotoViewPicker。并且文档中有相应的示例代码。我对自己的应用进行了如下修改:

2.1 修改显示页面,添加了“选择文件”按钮组件和显示视频文件Uri的文本组件

TabContent() {
  Column({ space: 20 }) {
    Text("播放手机视频")
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .width('100%')
    Video({
      src: this.videoUri // 手机上的视频文件路径
    }).width("100%").aspectRatio(1.3)
    Button("选择文件")
      .onClick(() => {
        this.VideoPicker() // 自定义函数获取本地视频路径
      })
    Text("文件路径" + this.videoUri) // 显示视频文件路径
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .width('100%')
  }
}.tabBar("视频3")

2.2 添加了使用PhotoViewPicker选择器获取视频文件路径的函数

async VideoPicker() {
  try {
    let PhotoSelectOptions = new picker.PhotoSelectOptions();
    PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.VIDEO_TYPE; // 文件类型 .IMAGE_TYPE
    PhotoSelectOptions.maxSelectNumber = 1; // 可选择的文件数量
    let photoPicker = new picker.PhotoViewPicker();
    photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult) => {
      console.info('PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult));
      this.videoUri = PhotoSelectResult.photoUris[0] // 获取视频文件路径
    }).catch((err) => {
      console.error('PhotoViewPicker.select failed with err: ' + err);
    });
  } catch (err) {
    console.error('PhotoViewPicker failed with err: ' + err);
  }
}

修改代码后,就可以选择手机上的视频文件进行播放了。

3.对播放音频的页面进行改进

由于参考资料中第一个链接提供的网络音频文件不能正常访问,因此,我决定将播放音频的页面修改为播放本地音频。从手机获取上获取音频文件路径的方法是通过@ohos.file.picker (选择器)的AudioViewPicker来实现的,链接三的文档中同样有示例代码,复制过来稍加修改就可以了。

3.1页面代码修改如下

TabContent() {
  Column({ space: 20 }) {
    Text("播放手机音频")
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .width('100%')
    Video({
      src: this.audioUri // 手机上的音频文件路径
    }).width('100%').aspectRatio(1.3)
    Button("选择文件")
      .onClick(() => {
        this.AudioPicker() // 自定义函数获取本地音频路径
      })
    Text("文件路径" + this.audioUri) // 显示音频文件路径
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .width('100%')
  }
}.tabBar("音频")

3.2 添加了使用PhotoViewPicker选择器选择视频文件的函数

async AudioPicker() {
  try {
    let AudioSelectOptions = new picker.AudioSelectOptions();
    let audioPicker = new picker.AudioViewPicker();
    audioPicker.select(AudioSelectOptions).then((AudioSelectResult) => {
      console.info('AudioViewPicker.select successfully, AudioSelectResult uri: ' + JSON.stringify(AudioSelectResult));
      this.audioUri = AudioSelectResult[0] // 获取音频文件路径
    }).catch((err) => {
      console.error('AudioViewPicker.select failed with err: ' + err);
    });
  } catch (err) {
    console.error('AudioViewPicker failed with err: ' + err);
  }
}

修改代码后,就可以对手机上的音频文件进行选择和播放了(见下图)。

4.对第一个页面的进行调整

在观看了官网上关于Video组件的文档资料后(链接二),我又尝试着对第一个页面内进行了一些修改,主要是取消了默认控制器的显示;增加了显示播放进度的组件;调整了页面布局;将“移动进度到”按钮对应的进度参数从固定值“30”,改为了变量,增加了文本输入框,修改这个变量,使得该功能更灵活。

代码修改后:

TabContent() {
  Column({ space: 20 }) {
    Text("播放网络视频-带控制器")
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .width('100%')
    Video({
      controller: this.controller,
      currentProgressRate: this.speed,
      src: "https://vd4.bdstatic.com/mda-phegibuu9ba9nrpe/hd/cae_h264/1692171953345322752/mda-phegibuu9ba9nrpe.mp4?auth_key=1703502162-0-0-6fd1550e28060e61121ed6d2a773b68c&bcevod_channel=searchbox_feed&pd=1&cr=1&cd=0&pt=4&logid=0162714477&vid=1316841417577475878&abtest=all"
    })
      .controls(false)
      .width("100%")
      .aspectRatio(1.4)
      .onPrepared((event) => {
        this.durationTime = event.duration // 获取视频总时长
      })
      .onUpdate((event) => {
        this.currentTime = event.time // 视频播放时获取当前时间
      })
    // 播放进度显示
    Row() {
      Text(JSON.stringify(this.currentTime) + 's') // 文本形式显示播放进度
      // 滑动条形式显示播放进度
      Slider({
        value: this.currentTime,
        min: 0,
        max: this.durationTime
      })
        .onChange((value: number, mode: SliderChangeMode) => {
          this.controller.setCurrentTime(value);
        }).layoutWeight(1)
      Text(JSON.stringify(this.durationTime) + 's')
    }.width("100%")
    // 播放倍速滑动选择
    Row() {
      Slider({
        value: this.speed,
        min: 0.75,
        step: 0.25,
        max: 2,
        style: SliderStyle.InSet
      }).layoutWeight(1)
        .showSteps(true)
        .onChange(value => {
          this.speed = value
        })
      Text(this.speed + "倍速") // 文本形式显示播放速率信息
        .fontSize(14)
        .textAlign(TextAlign.Center)
    }.width("100%")
    // 自定义播放控制器
    Row({ space: 10 }) {
      Button("播放")
        .onClick(() => {
          this.controller.start()
        })
      Button("暂停")
        .onClick(() => {
          this.controller.pause()
        })
      Button("结束")
        .onClick(() => {
          this.controller.stop()
        })
    }
    // 移动进度控制
    Row({ space: 10 }) {
      Button("移动进度到")
        .onClick(() => {
          this.controller.setCurrentTime(parseInt(this.jumpToTime)) // 设置视频控制器当前时间,单位为秒
        })
      TextInput({ text: this.jumpToTime }).layoutWeight(1) // 文本输入框,输入要移动到的进度位置
        .onChange((value: string) => {
          this.jumpToTime = value
        })
      Text("s")
    }.width('60%')

  }.width('100%')
}.tabBar("视频1")
5.遗留的三个问题

开发学习到这里,让我对Video组件和@ohos.file.picker (选择器)有了一些基础的了解,但现在还存在三个问题需要在之后的学习中去解决。

第一个问题是播放网络视频都是在代码中写死了的。原因是,我暂时还没有办法从视频网站上获取到视频文件的网络地址,只能先按着别人的教程做,目的是验证功能,没有什么实际意义。

第二个问题是点击Video组件默认控制器右侧的全屏按钮后视频放大,如果视频是横屏,手机不会自动以横屏显示视频,且视频显示显示不全(如下图),对此,暂时没有找到相关的解决办法。


全屏显示后异常

第三个问题是经过测试发现,当前的代码不适合播放竖屏形式的视频,原因是Video组件内设置的长宽比为1.3或1.4(即横屏)。如果视频是竖屏形式的,在Video组件中播放时,组件会将视频上部和下部裁切掉,只保留中间的部分。

这三个问题,希望能在不久的将来找到解决方法,使得视频播放功能更实用。先记录在这里以备忘。

四、代码展示

最后展示本次学习的成果

import picker from '@ohos.file.picker';

@Entry
@Component
struct EasyVideoPlayPage {
  @State videoUri: string = "" // 视频文件地址
  @State audioUri: string = "" // 音频文件地址
  @State speed: number = 1 // 视频播放速率,默认为1倍速
  @State currentTime: number = 0; // 当前时间(秒)
  @State durationTime: number = 0; // 视频总时长(秒)
  @State jumpToTime: string = "0"; // 移动进度到(秒)
  controller: VideoController = new VideoController() // 视频控制器

  build() {
    Column() {

      Tabs() {
        TabContent() {
          Column({ space: 20 }) {
            Text("播放网络视频-带控制器")
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
            Video({
              controller: this.controller,
              currentProgressRate: this.speed,
              src: "https://vd4.bdstatic.com/mda-phegibuu9ba9nrpe/hd/cae_h264/1692171953345322752/mda-phegibuu9ba9nrpe.mp4?auth_key=1703502162-0-0-6fd1550e28060e61121ed6d2a773b68c&bcevod_channel=searchbox_feed&pd=1&cr=1&cd=0&pt=4&logid=0162714477&vid=1316841417577475878&abtest=all"
            })
              .controls(false)
              .width("100%")
              .aspectRatio(1.4)
              .onPrepared((event) => {
                this.durationTime = event.duration // 获取视频总时长
              })
              .onUpdate((event) => {
                this.currentTime = event.time // 视频播放时获取当前时间
              })
            // 播放进度显示
            Row() {
              Text(JSON.stringify(this.currentTime) + 's') // 文本形式显示播放进度
              // 滑动条形式显示播放进度
              Slider({
                value: this.currentTime,
                min: 0,
                max: this.durationTime
              })
                .onChange((value: number, mode: SliderChangeMode) => {
                  this.controller.setCurrentTime(value);
                }).layoutWeight(1)
              Text(JSON.stringify(this.durationTime) + 's')
            }.width("100%")
            // 播放倍速滑动选择
            Row() {
              Slider({
                value: this.speed,
                min: 0.75,
                step: 0.25,
                max: 2,
                style: SliderStyle.InSet
              }).layoutWeight(1)
                .showSteps(true)
                .onChange(value => {
                  this.speed = value
                })
              Text(this.speed + "倍速") // 文本形式显示播放速率信息
                .fontSize(14)
                .textAlign(TextAlign.Center)
            }.width("100%")
            // 自定义播放控制器
            Row({ space: 10 }) {
              Button("播放")
                .onClick(() => {
                  this.controller.start()
                })
              Button("暂停")
                .onClick(() => {
                  this.controller.pause()
                })
              Button("结束")
                .onClick(() => {
                  this.controller.stop()
                })
            }
            // 移动进度控制
            Row({ space: 10 }) {
              Button("移动进度到")
                .onClick(() => {
                  this.controller.setCurrentTime(parseInt(this.jumpToTime)) // 设置视频控制器当前时间,单位为秒
                })
              TextInput({ text: this.jumpToTime }).layoutWeight(1) // 文本输入框,输入要移动到的进度位置
                .onChange((value: string) => {
                  this.jumpToTime = value
                })
              Text("s")
            }.width('60%')

          }.width('100%')
        }.tabBar("视频1")

        TabContent() {
          Column({ space: 20 }) {
            Text("播放网络视频")
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
            Video({
              src: "https://vd3.bdstatic.com/mda-pmj5ajqd7p4b6pgb/576p/h264/1703044058699262355/mda-pmj5ajqd7p4b6pgb.mp4?auth_key=1703138418-0-0-618ea72b33be241c96c6cff86c06e080&bcevod_channel=searchbox_feed&cr=1&cd=0&pd=1&pt=4&logid=0018430194&vid=9762003448174112444&abtest=all"
            }).width("100%").aspectRatio(1.3)
          }
        }.tabBar("视频2")

        TabContent() {
          Column({ space: 20 }) {
            Text("播放手机视频")
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
            Video({
              src: this.videoUri // 手机上的视频文件路径
            }).width("100%").aspectRatio(1.3)
            Button("选择文件")
              .onClick(() => {
                this.VideoPicker() // 自定义函数获取本地视频路径
              })
            Text("文件路径" + this.videoUri) // 显示视频文件路径
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
          }
        }.tabBar("视频3")

        TabContent() {
          Column({ space: 20 }) {
            Text("播放手机音频")
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
            Video({
              src: this.audioUri // 手机上的音频文件路径
            }).width('100%').aspectRatio(1.3)
            Button("选择文件")
              .onClick(() => {
                this.AudioPicker() // 自定义函数获取本地音频路径
              })
            Text("文件路径" + this.audioUri) // 显示音频文件路径
              .fontSize(14)
              .textAlign(TextAlign.Center)
              .width('100%')
          }
        }.tabBar("音频")
      }.animationDuration(500)
    }
    .justifyContent(FlexAlign.Start)
    .width('100%')
    .backgroundColor('#EAEAEA')
    .padding(10) // 根 Column -end
  }

  // 视频文件选择器:代码来源于官方开发文档-API参考-ArkTS接口参考-文件管理-@ohos.file.picker-PhotoViewPicker,对源码进行了修改
  async VideoPicker() {
    try {
      let PhotoSelectOptions = new picker.PhotoSelectOptions();
      PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.VIDEO_TYPE; // 文件类型 .IMAGE_TYPE
      PhotoSelectOptions.maxSelectNumber = 1; // 可选择的文件数量
      let photoPicker = new picker.PhotoViewPicker();
      photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult) => {
        console.info('PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult));
        console.info('PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult.photoUris[0]));
        this.videoUri = PhotoSelectResult.photoUris[0] // 获取视频文件路径
      }).catch((err) => {
        console.error('PhotoViewPicker.select failed with err: ' + err);
      });
    } catch (err) {
      console.error('PhotoViewPicker failed with err: ' + err);
    }
  }

  // 音频文件选择器:代码来源于官方开发文档-API参考-ArkTS接口参考-文件管理-@ohos.file.picker-AudioViewPicker,对源码进行了修改
  async AudioPicker() {
    try {
      let AudioSelectOptions = new picker.AudioSelectOptions();
      let audioPicker = new picker.AudioViewPicker();
      audioPicker.select(AudioSelectOptions).then((AudioSelectResult) => {
        console.info('AudioViewPicker.select successfully, AudioSelectResult uri: ' + JSON.stringify(AudioSelectResult));
        this.audioUri = AudioSelectResult[0] // 获取音频文件路径
      }).catch((err) => {
        console.error('AudioViewPicker.select failed with err: ' + err);
      });
    } catch (err) {
      console.error('AudioViewPicker failed with err: ' + err);
    }
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

详解Linux例行性工作

例行性工作(计划任务) 场景: 生活中,我们有太多场景需要使用到闹钟,比如早上7点起床,下午4点开会,晚上8点购物,等等。再Linux系统里,我们同样也有类似的需求。比如我们…

创新企业成长模型:嘉绩咨询深化招商教育与系统策划

在当今企业发展与市场拓展的竞争激烈背景下,嘉绩咨询已凸显其在招商体系孵化领域的领先地位。集团不仅在招商教育、招商落地支持、陪跑孵化及渠道商学院搭建等业务领域提供全面的服务,同时构筑了与众不同的企业成长循环模型。 嘉绩咨询秉承其"教育策…

四、DMSP/OLS等夜间灯光数据贫困地区识别——相对误差相关折线图制作

一、前言 前文对于MPI和灯光指数拟合、误差分析,本文重点介绍地理加权分析,但是在此之前给大家介绍一下专业表格制作,其实专业的软件有很多像Orgin、棱镜等,到我们熟知的Excel,其实各有千秋,Excel入手容易…

软件杯 交通目标检测-行人车辆检测流量计数 - 软件杯

文章目录 0 前言1\. 目标检测概况1.1 什么是目标检测?1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 毕业设计…

mtk平台ATF介绍

1、链接地址 uboot ATF 2、工具链 ARM 64位平台需要aarch64工具链,可以在staging_dir/toolchain- aarch64_xxxxx中找到。另外dtc工具来为ATF编译.dts文件,一般在 Ubuntu中的device-tree-compiler包,编译后的u-boot/kernel源代码树中的脚本…

设计模式(工厂模式)

设计模式(工厂模式) 一、工厂模式介绍 在工厂模式中,父类决定生成示例的方式,但不决定所要生成的具体的类,具体的处理部分交给子类负责。这样就可以将生成示例的框架和生成示例的类解耦。 二、示例程序 以下示例程…

[壹],安卓开发环境搭建

1,下载JDK并安装 网址: Java Downloads | Oracle 下载完成,安装到自定义位置。 2,设置系统环境变量 2.1,新建环境变量JAVA_HOME 2.2,Path环境变量追加 %JAVA_HOME%\bin 2.3,验证安装效果 3,…

error Mixed spaces and tabs no-mixed-spaces-and-tabs报错

vue尚硅谷todolist案例 中报错如下: ERROR Failed to compile with 1 error 21:18:11 Module Error (from ./node_modules/eslint-loader/index.js): F:\文件\网页文件\code\source\vu…

UCRTBASED.DLL缺失怎么办?UCRTBASED.DLL文件的解决方法分享

UCRTBASED.DLL 是一个属于Microsoft Universal C Runtime (UCRT) 的动态链接库(DLL)文件。在Windows操作系统中,这个文件提供了一系列C和C标准库函数的实现,这些函数对于支持基于C或C开发的应用程序至关重要。 UCRT是微软为了统一…

揭秘:我的GPTs广告项目到底挣了多少银子?

写在前面 🌟 之前分享了GPTs接入广告赚取收益的项目保姆级教程: GPTs接入广告到提现成功全过程真实记录 ,很多粉丝朋友问,我GPTs广告项目,一共赚了多少钱,现在还能入场吗? 这篇文章,就来总结一下…

【web | CTF】BUUCTF [强网杯 2019]随便注

天命:这题考点有两个,第一个是闭合,第二个是叠堆注入 先探测一下是不是单引号闭合,其实我一开始以为是没有引号闭合的,毕竟是数字 经过测试,的确是单引号闭合 然后探测未知的东西,我习惯性直接…

雷卯的ESD管SDA3311DN可以替代AZ5883-01F ---国产化替代篇

已经有很多客户选用雷卯的 SDA3311DN替代Amazing的 AZ5883-01F,客户可以获得更好的价格和更快的交期。 SDA3311DN主要应用于对3.3V供电的静电浪涌防护等,特别是在一些受空间所限的小电子设备很受青睐。 雷卯的SDA3311DN优势: IPP大(65A) &…

【Python】Python Astar算法生成最短路径GPS轨迹

简介 最短路径问题是计算机科学中一个经典问题,它涉及找到图中两点之间距离最短的路徑。在实际应用中,最短路径算法用于解决广泛的问题,例如导航、物流和网络优化。 步骤 1:加载道路网络数据 要计算最短路径,我们需…

WebSocket:实现客户端与服务器实时通信的技术

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【分库分表】基于mysql+shardingSphere的分库分表技术

目录 1.什么是分库分表 2.分片方法 3.测试数据 4.shardingSphere 4.1.介绍 4.2.sharding jdbc 4.3.sharding proxy 4.4.两者之间的对比 5.留个尾巴 1.什么是分库分表 分库分表是一种场景解决方案,它的出现是为了解决一些场景问题的,哪些场景喃…

ERC20学习

ERC20简介 ERC20是一种代币标准,用于创建可替代的代币。 ERC20是在以太坊网络上实现的代币标准,它为数字资产或代币定义了一套规则和接口。这些符合ERC20标准的代币在性质上是完全相同的。即每一个代币都可以被另一个同类型的代币替代,这种属…

数据结构——线性表顺序表示详解

目录 1.线性表的类型定义 2.基本操作 3.线性表的存储结构 4.补充 1.元素类型说明 2.数组定义​编辑 3.c语言的内存动态分配 4.c的动态存储分配 5.c中的参数传递 引用类型作参数 6.顺序表基本操作的实现 1.线性表的初始化 代码示例: 2.销毁线性表&…

11. 搭建较通用的GoWeb开发脚手架

文章目录 导言一、加载配置二、初始化日志三、初始化MySQL连接四、初始化Redis连接五、初始化gin框架内置的校验器使用的翻译器六、注册路由七、 启动服务八、测试运行九:注意事项 代码地址:https://gitee.com/lymgoforIT/bluebell 导言 有了前述知识的…

【LV15 DAY8 多路复用及信号驱动】

一、多路复用 描述符: 文件描述符:设备文件、管道文件 socket描述符1.1 应用层:三套接口select、poll、epoll select:位运算实现 监控的描述符数量有限(32位机1024,64位机2048) 效率差 poll&#xff1a…

MySQL基础-----约束

目录 前言 一、概述 二、约束演示 三、外键约束 1.介绍 2.语法 四、删除/更新行为 1.CASCADE 2.SET NULL 前言 本期我们开始MySQL约束的学习,约束一般是只数据键对本条数据的约束,通过约束我们可以保证数据库中数据的正确、有效性和完整性。 下面…