融媒体服务中PBO进行多重采样抗锯齿(MSAA)

如果不理解pbo 那先去了解概念,在此不再解释,这是我为了做融合服务器viewpointserver做的一部分工作,融合服务器的功能是将三维和流媒体,AI融合在一起,viewpointserver会直接读取三维工程的文件,同时融合rtsp视频流,将视频流作为纹理给材质,最后赋值给三维模型如fbx的表面。由于没有窗口,三维作为服务运行,里面有一项工作就是三维的抗锯齿采集。

PBO(Pixel Buffer Object)进行多重采样抗锯齿(MSAA)的一般步骤

1 初始化 OpenGL 和 MSAA 帧缓冲:

1.1开启 MSAA:

在初始化 OpenGL 时,通过设置相关参数开启多重采样抗锯齿。例如,使用 glEnable(GL_MULTISAMPLE) 函数来启用 OpenGL 的多重采样功能。

1.2 创建帧缓冲:

创建一个帧缓冲对象(FBO),用于存储多重采样后的图像数据。这可以通过 glGenFramebuffers 和 glBindFramebuffer 等函数来完成。

1.3 配置 FBO 的附件:

为 FBO 配置颜色附件和深度附件。对于颜色附件,创建一个纹理,并将其绑定到 FBO 上;对于深度附件,可以创建一个渲染缓冲对象(RBO)并绑定到 FBO。确保纹理和 RBO 的尺寸与渲染窗口的尺寸相匹配。

2 渲染到 MSAA 帧缓冲:

2.1 绑定 MSAA 帧缓冲:

在渲染场景之前,使用 glBindFramebuffer 函数将之前创建的 MSAA FBO 绑定为当前的渲染目标。这样,后续的渲染操作将把图像数据渲染到 MSAA FBO 中。

2.2 进行常规渲染:

按照正常的 OpenGL 渲染流程绘制场景中的物体。由于启用了 MSAA,OpenGL 会在每个像素内进行多个子采样,以实现抗锯齿效果。

3 使用 PBO 读取 MSAA 数据:

创建 PBO:使用 glGenBuffers 函数创建一个 PBO,并使用 glBindBuffer 函数将其绑定到 GL_PIXEL_PACK_BUFFER 目标上。然后,使用 glBufferData 函数为 PBO 分配足够的内存空间,以存储从 MSAA FBO 读取的像素数据。
读取像素数据到 PBO:在渲染完成后,使用 glReadPixels 函数将 MSAA FBO 中的像素数据读取到 PBO 中。由于 PBO 的存在,这个操作可以在后台异步进行,减少对 CPU 的阻塞。

4 处理和解析 PBO 中的数据:

4.1 映射 PBO:

使用 glMapBuffer 函数将 PBO 映射到 CPU 可访问的内存空间,以便读取和处理像素数据。这将返回一个指向 PBO 内存的指针,可以通过该指针访问像素数据。

4.2 解析像素数据:

根据需要,对 PBO 中的像素数据进行处理和解析。例如,可以将像素数据转换为图像格式,以便保存为文件或进行其他操作。在处理像素数据时,需要考虑 MSAA 的子采样信息,通常需要对多个子采样点的颜色值进行合并或平均,以得到最终的抗锯齿效果。

4.3 取消映射 PBO:

完成对 PBO 数据的处理后,使用 glUnmapBuffer 函数取消对 PBO 的映射,释放 CPU 对 PBO 内存的访问。

5 显示或使用抗锯齿后的图像:

5.1 将处理后的像素数据显示在屏幕上:

如果需要在屏幕上显示抗锯齿后的图像,可以使用 glDrawPixels 或其他相关的 OpenGL 函数将处理后的像素数据绘制到默认的帧缓冲中,然后通过交换缓冲区来显示在屏幕上。

5.2 保存为图像文件:

可以将处理后的像素数据保存为图像文件,以便后续使用。这可以通过使用图像库(如 stb_image 库)来实现,将像素数据写入图像文件中。

使用深度缓冲的例子

以下使用qt来做,qt的优点是很多都是封装好的,比较容易实现,不用引入额外的库,当然我们也可以使用glfw来做,后面会给出例子

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QtWidgets/QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include "ui_MainWindow.h"QT_BEGIN_NAMESPACE
namespace Ui {class CMainWindow;
}
QT_END_NAMESPACEclass CMainWindow : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core
{Q_OBJECTpublic:CMainWindow(QWidget *parent = Q_NULLPTR);~CMainWindow();void initFBO();protected:void initializeGL();void paintGL();void resizeGL(int w, int h);private:QImage m_img;GLsizei m_width = 0;GLsizei m_height = 0;GLsizeiptr m_dataSize = 0;GLuint m_VBO = 0;GLuint m_VAO = 0;GLuint m_EBO = 0;GLuint m_texture = 0;GLuint m_frameBuffer = 0;GLuint m_RBO = 0;GLuint m_fVBO = 0;GLuint m_fVAO = 0;GLuint m_textureFBO = 0;QOpenGLShaderProgram *m_programScreen = nullptr;QOpenGLShaderProgram *m_shaderProgram = nullptr;
private:Ui::CMainWindow *ui;
};
#endif //MAINWINDOW_H
#include "MainWindow.h"CMainWindow::CMainWindow(QWidget* parent): QOpenGLWidget(parent), ui(new Ui::CMainWindow)
{ui->setupUi(this);m_img = QImage("2.jpg");//picturem_width = m_img.width();m_height = m_img.height();m_dataSize = m_width * m_height * 3;
}CMainWindow::~CMainWindow()
{delete ui;glDeleteVertexArrays(1, &m_VAO);glDeleteBuffers(1, &m_VBO);glDeleteBuffers(1, &m_EBO);glDeleteVertexArrays(1, &m_fVAO);glDeleteBuffers(1, &m_fVBO);glDeleteBuffers(1, &m_frameBuffer);glDeleteBuffers(1, &m_RBO);
}
void CMainWindow::initFBO()
{glGenFramebuffers(1, &m_frameBuffer);glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);glGenTextures(1, &m_textureFBO);glBindTexture(GL_TEXTURE_2D, m_textureFBO);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);//TODOglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, 0);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textureFBO, 0);glGenRenderbuffers(1, &m_RBO);glBindRenderbuffer(GL_RENDERBUFFER, m_RBO);glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_width, m_height);glBindRenderbuffer(GL_RENDERBUFFER, 0);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_RBO);if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)qDebug() << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" ;glBindFramebuffer(GL_FRAMEBUFFER, 0);char vertexShaderSource[] ="#version 450 core\n""layout (location = 0) in vec2 aPos;\n""layout (location = 1) in vec2 aTexCoords;\n""out vec2 TexCoords;\n""void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n""TexCoords = aTexCoords;\n""}\n";char fragmentShaderSource[] ="#version 450 core\n""out vec4 FragColor;\n""in vec2 TexCoords;\n""uniform sampler2D screenTexture;\n""void main()\n""{\n""   FragColor = texture(screenTexture, TexCoords);\n""}\n";m_programScreen = new QOpenGLShaderProgram;m_programScreen->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);m_programScreen->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);m_programScreen->link();m_programScreen->bind();m_programScreen->setUniformValue("screenTexture", 1);m_programScreen->release();float fb_Vertices[] = {// positions   // texCoords-1.0f,  1.0f,  0.0f, 1.0f,-1.0f, -1.0f,  0.0f, 0.0f,1.0f, -1.0f,  1.0f, 0.0f,-1.0f,  1.0f,  0.0f, 1.0f,1.0f, -1.0f,  1.0f, 0.0f,1.0f,  1.0f,  1.0f, 1.0f};glGenVertexArrays(1, &m_fVAO);glBindVertexArray(m_fVAO);glGenBuffers(1, &m_fVBO);glBindBuffer(GL_ARRAY_BUFFER, m_fVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(fb_Vertices), fb_Vertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)0);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(float)));glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);}void CMainWindow::initializeGL()
{this->initializeOpenGLFunctions();char vertexShaderSource[] ="#version 450 core\n""layout(location = 0) in vec3 aPos;\n""layout(location = 1) in vec3 aColor;\n""layout(location = 2) in vec2 aTexcood;\n""out vec3 vertexColor;\n""out vec2 m_tex;\n""void main()\n""{\n""   m_tex = aTexcood;\n""   vertexColor = aColor;\n""   gl_Position = vec4(aPos, 1.0);\n""}\n";char fragmentShaderSource[] ="#version 450 core\n""out vec4 FragColor;\n""in vec3 vertexColor;\n""in vec2 m_tex;\n""uniform sampler2D ourTexture;\n""void main()\n""{\n""   FragColor = texture2D(ourTexture, m_tex) * vec4(vertexColor, 1.0f);\n""}\n";m_shaderProgram = new QOpenGLShaderProgram;m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);m_shaderProgram->link();m_shaderProgram->bind();m_shaderProgram->setUniformValue("ourTexture", 0);m_shaderProgram->release();GLfloat vertices[] = {-1.0f, -1.0f,0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,1.0f, -1.0f,0.0f, 0.0f,1.0f,0.0f, 1.0f,0.0f,1.0f,  1.0f,0.0f, 1.0f,0.0f,0.0f, 1.0f,1.0f,-1.0f,  1.0f,0.0f, 0.0f,1.0f,1.0f, 0.0f,1.0f,};GLuint indices[] = {0,1,2,0,2,3};glGenVertexArrays(1, &m_VAO);glBindVertexArray(m_VAO);glGenBuffers(1, &m_VBO);glBindBuffer(GL_ARRAY_BUFFER, m_VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glGenBuffers(1, &m_EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(float)));glEnableVertexAttribArray(2);glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);glGenTextures(1, &m_texture);glBindTexture(GL_TEXTURE_2D, m_texture);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_img.bits());//TODOglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glGenerateMipmap(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, 0);//初始化FBOinitFBO();}void CMainWindow::paintGL()
{glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);glEnable(GL_DEPTH_TEST);glClearColor(0.5f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);m_shaderProgram->bind();glBindVertexArray(m_VAO);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, m_texture);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);m_shaderProgram->release();/********** 关键之处 ***********/GLuint fb = context()->defaultFramebufferObject();glBindFramebuffer(GL_FRAMEBUFFER, fb);glDisable(GL_DEPTH_TEST);glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glViewport(0, 0, m_width, m_height);m_programScreen->bind();glBindVertexArray(m_fVAO);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, m_textureFBO);glDrawArrays(GL_TRIANGLES, 0, 6);glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);m_programScreen->release();}void CMainWindow::resizeGL(int w, int h)
{glViewport(0, 0, w, h);
}

qt中采集场景如图
在这里插入图片描述

下面给出glfw的例子

glfw

首先初始化 OpenGL、GLFW 和 GLEW,也可以用glad,并创建了 MSAA FBO、颜色纹理、深度 RBO 和 PBO。然后,在渲染循环中,先将场景渲染到 MSAA FBO 中,再将 FBO 中的像素数据读取到 PBO 中,并对 PBO 中的像素数据进行处理。最后,清理资源并退出程序。当然实际应用中确实需要根据具体需求进行更多的错误处理和优化。

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <cstdlib>// 窗口尺寸
const int WIDTH = 800;
const int HEIGHT = 600;// 创建 PBO
GLuint pbo;
// 创建 MSAA FBO
GLuint fbo;
// 颜色纹理
GLuint colorTexture;
// 深度 RBO
GLuint depthRBO;void init() {// 初始化 GLFWif (!glfwInit()) {std::cerr << "Failed to initialize GLFW" << std::endl;exit(EXIT_FAILURE);}// 创建窗口GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "MSAA with PBO", nullptr, nullptr);if (!window) {std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate();exit(EXIT_FAILURE);}// 将窗口设置为当前上下文glfwMakeContextCurrent(window);// 初始化 GLEWglewExperimental = GL_TRUE;if (glewInit()!= GLEW_OK) {std::cerr << "Failed to initialize GLEW" << std::endl;exit(EXIT_FAILURE);}// 开启多重采样抗锯齿glEnable(GL_MULTISAMPLE);// 创建 FBOglGenFramebuffers(1, &fbo);glBindFramebuffer(GL_FRAMEBUFFER, fbo);// 创建颜色纹理glGenTextures(1, &colorTexture);glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, colorTexture);glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, WIDTH, HEIGHT, GL_TRUE);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorTexture, 0);// 创建深度 RBOglGenRenderbuffers(1, &depthRBO);glBindRenderbuffer(GL_RENDERBUFFER, depthRBO);glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, WIDTH, HEIGHT);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRBO);// 检查 FBO 是否完整if (glCheckFramebufferStatus(GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE) {std::cerr << "Failed to create FBO" << std::endl;exit(EXIT_FAILURE);}// 创建 PBOglGenBuffers(1, &pbo);glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);glBufferData(GL_PIXEL_PACK_BUFFER, WIDTH * HEIGHT * 4, nullptr, GL_STREAM_READ);
}void renderScene() {// 绑定 MSAA FBO 并渲染场景glBindFramebuffer(GL_FRAMEBUFFER, fbo);glViewport(0, 0, WIDTH, HEIGHT);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 在这里进行场景的绘制操作// 解除绑定 FBOglBindFramebuffer(GL_FRAMEBUFFER, 0);
}void processPixels() {// 将 MSAA FBO 中的像素数据读取到 PBOglBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);// 映射 PBO 到 CPU 可访问的内存GLubyte* pixels = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);if (pixels) {// 在这里处理像素数据,例如保存为图像或进行其他操作// 为了简单起见,这里只是打印一些像素信息for (int i = 0; i < 10; i++) {std::cout << "Pixel " << i << ": ("<< (int)pixels[4 * i] << ", "<< (int)pixels[4 * i + 1] << ", "<< (int)pixels[4 * i + 2] << ", "<< (int)pixels[4 * i + 3] << ")" << std::endl;}// 取消映射 PBOglUnmapBuffer(GL_PIXEL_PACK_BUFFER);}
}int main() {init();// 渲染循环while (!glfwWindowShouldClose(glfwGetCurrentContext())) {renderScene();processPixels();// 交换缓冲区并处理事件glfwSwapBuffers(glfwGetCurrentContext());glfwPollEvents();}// 清理资源glDeleteBuffers(1, &pbo);glDeleteTextures(1, &colorTexture);glDeleteRenderbuffers(1, &depthRBO);glDeleteFramebuffers(1, &fbo);glfwTerminate();return 0;
}

存文件测试

static void saveImage(GLuint& pbo, const std::string& filename, int width, int height) {glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);// 将帧缓冲区内容读取到 PBOglReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);// 映射 PBO 获取数据指针GLubyte* pixels = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);if (pixels){stbi_write_png(filename.c_str(), width, height, 4, pixels, width * 4);glUnmapBuffer(GL_PIXEL_PACK_BUFFER);}else{std::cerr << "Failed to map." << std::endl;}glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}

如下图所示,存的图像是倒立镜像的,实际上是正立的三角形,还没有将视频附上去,工作量有些大,等到下一个文章再写。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

英语词汇小程序小程序|英语词汇小程序系统|基于java的四六级词汇小程序设计与实现(源码+数据库+文档)

英语词汇小程序 目录 基于java的四六级词汇小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&a…

初始项目托管到gitee教程,开箱即用

0.本地仓库与远程仓库关联&#xff08;需先在gitee创建仓库&#xff09; ①打开powershell生成ssh key ssh-keygen -t ed25519 -C "Gitee SSH Key"-t key 类型-C 注释 生成成功如下&#xff0c;并按下三次回车 ②查看公私钥文件 ls ~/.ssh/输出&#xff1a; id_…

vulnhub-Web Developer 1靶机

vulnhub&#xff1a;Web Developer: 1 ~ VulnHub 导入靶机&#xff0c;放在kali同网段&#xff0c;扫描 靶机在192.168.114.129&#xff0c;扫描端口 有网站服务&#xff0c;访问 没什么东西&#xff0c;扫目录 真不少&#xff0c;访问一下&#xff0c;也只是一些普通的Wordpr…

【IEEE PDF eXpress】格式不对

目录 一、问题二、解决方法 一、问题 word的文档&#xff0c;用IEEE PDF eXpress网站生成pdf后&#xff0c;提交论文出现错误&#xff1a; Document validation failed due to the following errors: Content exceeds IEEE template margins for its format (Page 1:Bottom).…

我对软件工程的理解

1 引言 从事软件行业这么年&#xff0c;写了10年代码&#xff0c;又从事了多年的项目产品方面的工作&#xff0c;一些每天用到的软件工程的方法&#xff0c;虽然天天都在用但一些概念总感觉似是而非&#xff0c;正好借假期的时间&#xff0c;好好整理下&#xff0c;以供自己或…

【Golang】Go语言中时间time相关处理方法

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

认识动态规划算法和实践(java)

前言 动态规划算法里面最有意思的一个东西之一。动态规划初学肯定会有一定晦涩难懂。如果我们去网上搜索&#xff0c;动态规划的资料&#xff0c;它一开始都是将很多的理论&#xff0c;导致会认为很难&#xff0c;但是这个东西实际上是有套路的。 动态规划的英语是Dynamic Pr…

MySQL之分库分表后带来的“副作用”你是怎么解决的?

目录标题 一、垂直分表后带来的隐患二、水平分表后带来的问题1.多表联查问题2.增删改数据问题3.聚合操作问题 三、垂直分库后产生的问题1.跨库join问题2.分布式事务问题3.部分业务库依然存在的性能问题 四、水平分库后需要解决的问题1.聚合操作和连表问题2.数据分页问题3.ID主键…

10款好用的开源 HarmonyOS 工具库

大家好&#xff0c;我是 V 哥&#xff0c;今天给大家分享10款好用的 HarmonyOS的工具库&#xff0c;在开发鸿蒙应用时可以用下&#xff0c;好用的工具可以简化代码&#xff0c;让你写出优雅的应用来。废话不多说&#xff0c;马上开整。 1. efTool efTool是一个功能丰富且易用…

全球IP归属地查询-IP地址查询-IP城市查询-IP地址归属地-IP地址解析-IP位置查询-IP地址查询API接口

IP地址城市版查询接口 API是指能够根据IP地址查询其所在城市等地理位置信息的API接口。这类接口在网络安全、数据分析、广告投放等多个领域有广泛应用。以下是一些可用的IP地址城市版查询接口API及其简要介绍 1. 快证 IP归属地查询API 特点&#xff1a;支持IPv4 提供高精版、…

k8s 中微服务之 MetailLB 搭配 ingress-nginx 实现七层负载

目录 1 MetailLB 搭建 1.1 MetalLB 的作用和原理 1.2 MetalLB功能 1.3 部署 MetalLB 1.3.1 创建deployment控制器和创建一个服务 1.3.2 下载MealLB清单文件 1.3.3 使用 docker 对镜像进行拉取 1.3.4 将镜像上传至私人仓库 1.3.5 将官方仓库地址修改为本地私人地址 1.3.6 运行清…

【前端】-音乐播放器(源代码和结构讲解,大家可以将自己喜欢的歌曲添加到数据当中,js实现页面动态显示音乐)

前言&#xff1a;音乐播放器是前端开发中的一个经典项目&#xff0c;通过它可以掌握很多核心技术&#xff0c;如音频处理、DOM操作、事件监听、动画效果等。这个项目不仅能提升前端开发的技能&#xff0c;还能让开发者深入理解JavaScript与HTML的协同作用。 页面展示&#xff1…

Web安全 - 文件上传漏洞(File Upload Vulnerability)

文章目录 OWASP 2023 TOP 10导图定义攻击场景1. 上传恶意脚本2. 目录遍历3. 覆盖现有文件4. 文件上传结合社会工程攻击 防御措施1. 文件类型验证2. 文件名限制3. 文件存储位置4. 文件权限设置5. 文件内容检测6. 访问控制7. 服务器配置 文件类型验证实现Hutool的FileTypeUtil使用…

Python中的机器学习:从入门到实战

机器学习是人工智能领域的一个重要分支&#xff0c;它通过构建模型来使计算机从数据中学习并做出预测或决策。Python凭借其丰富的库和强大的生态系统&#xff0c;成为了机器学习的首选语言。本文将从基础到实战&#xff0c;详细介绍如何使用Python进行机器学习&#xff0c;涵盖…

【汇编语言】寄存器(CPU工作原理)(二)—— 汇编指令的基础操作

文章目录 前言正文——&#xff08;一气呵成解决本文内容&#xff09;结语 前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构、操作系统、微机原理&#xff09;的重要基础。但仅仅从课程的角度出发就太片面了&#xff0c;其实学习汇编语言可以深入理解计算机底…

Android Framework AMS(02)AMS启动及相关初始化5-8

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要涉及systemserver启动AMS及初始化AMS相关操作。同时由于该部分内容过多&#xff0c;因此拆成2个章节&#xff0c;本章节是第二章节&…

LabVIEW提高开发效率技巧----使用动态事件

在LabVIEW开发过程中&#xff0c;用户交互行为可能是多样且不可预知的。为应对这些变化&#xff0c;使用动态事件是一种有效的策略。本文将从多个角度详细介绍动态事件的概念及其在LabVIEW开发中的应用技巧&#xff0c;并结合实际案例&#xff0c;说明如何通过动态事件提高程序…

Vector不清晰点学习易错点

什么是迭代器 是一个广义指针它可以是指针&#xff0c;也可以是一个可对其执行类似指针得操作-如解除引用&#xff08;如operator*()&#xff09;和递增&#xff08;operator()&#xff09;STL中每个容器类都定义了一个合适的迭代器&#xff0c;该迭代器的类型是一个名为itera…

【Python游戏开发】贪吃蛇游戏demo拓展

拓展上一项目【Python游戏开发】贪吃蛇 实现穿墙效果 # 检测游戏是否结束 def check_gameover():global finished# 移除蛇头位置超过窗口判断for n in range(len(body) - 1):if(body[n].x snake_head.x and body[n].y snake_head.y):finished True # 状态检测 def ch…

html5 + css3(下)

目录 CSS基础基础认识体验cssCSS引入方式 基础选择器选择器-标签选择器-类选择器-id选择器-通配符 字体和文本样式1.1 字体大小1.2 字体粗细1.3 字体样式&#xff08;是否倾斜&#xff09;1.4 常见字体系列&#xff08;了解&#xff09;1.5 字体系列拓展-层叠性font复合属性文本…