入门系列之在Ubuntu 16.04使用Buildbot建立持续集成系统

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

本文由angel_郁发表于云+社区专栏

介绍

Buildbot是一个基于Python的持续集成系统,用于自动化软件构建,测试和发布过程。

在本教程中,我们将演示如何设置持续集成系统以自动测试对存储库的新更改。我们将使用一个简单的Node.js应用程序来演示测试过程和必要的配置。为了将我们的测试环境与Buildbot主机隔离,我们将创建一个Docker镜像作为Buildbot worker运行。然后,我们将配置Buildbot主服务器以观察GitHub存储库的更改,每次检测到新的更改时自动进行测试。

准备

要学习本教程,您需要:

  • 一个具有至少1 GB的RAM的Ubuntu16.04服务器,并包括一个可以使用sudo命令的非root 用户。

另外,在开始本教程之前需要完成以下内容:

  • 如何在Ubuntu上安装Buildbot

  • 安装Nginx

  • 在Ubuntu上使用SSL来保护Nginx

  • 给Buildbot加上SSL,使用Nginx做反向代理

  • 搭建Docker环境

在GitHub中使用fork示例存储库

在我们开始配置Buildbot之前,我们将看一下我们将用于本教程的示例存储库。

在您的Web浏览器中,访问我们将用于演示的GitHub上的hello hapi应用程序。这个应用程序是一个简单的“hello world”程序,带有一些单元和集成测试,用hapi编写的一个Node.js Web框架。

由于此示例用于演示各种持续集成系统,您可能会注意到一些文件用于为其他系统定义管道。对于Buildbot,我们将在服务器上而不是在存储库中定义构建步骤。

稍后,我们将在我们的存储库中为Buildbot设置webhook,以便更改将自动触发新测试。现在,我们需要创建自己的存储库分支。

单击屏幕右上角的Fork按钮:

imgGitHub fork 按钮

如果您是GitHub组织的成员,可能会询问您在哪里使用fork存储库:

img哪里使用fork存储库

选择帐户或组织后,存储库的副本将添加到您的帐户中:

img存储库的副本将添加到您的帐户

您将在Buildbot配置中使用fork的URL。现在我们有了一个存储库URL,我们可以开始配置Buildbot了。

为Buildbot设置Docker

我们将从设置Docker开始,以便Buildbot使用它来执行构建。首先,我们需要配置Docker和Buildbot之间的访问。之后,我们需要创建一个Docker镜像以用于我们的容器。

为Buildbot配置Docker访问

我们需要允许Buildbot和Docker在几个不同的级别进行通信。

首先,我们需要确保Buildbot进程可以访问Docker守护程序。我们可以通过将做到这一点buildbot用户的docker组:

$ sudo usermod -aG docker buildbot

下次重新启动Buildbot主服务器时,这个新组将可用于Buildbot,我们稍后会这样做。

我们还需要确保Buildbot知道如何与Docker通信。由于Buildbot是用Python编写的,它利用docker-py Python包而不是直接发出Docker命令。

您可以输入以下命令安装docker-py

$ sudo -H pip install docker-py

最后,我们需要打开从容器到主机系统和外部世界的网络访问。我们可以通过在防火墙中允许docker0的接口例外来实现此目的。

通过输入以下内容允许从docker0界面访问流量:

$ sudo ufw allow in on docker0

Buildbot和Docker现在应该能够有效地相互通信。

创建一个Docker镜像以用作Buildbot Worker

接下来,我们将创建一个Docker容器,用作Buildbot worker来运行我们的测试。Buildbot可以动态启动Docker容器以用作worker,但首先需要使用包含的一些Buildbot worker组件构建容器。

幸运的是,Buildbot项目提供了一个基本的Buildbot worker映像,该镜像已经配置了所有特定于Buildbot的需求。我们只需要将此镜像用作基础并安装我们项目所需的其他依赖项。

在我们的例子中,我们将使用的示例应用程序是Node.js应用程序,因此我们需要确保Node.js在镜像上可用。

要定义我们的镜像,请创建并打开Dockerfile在主目录中调用的文件:

$ nano ~/Dockerfile

在这个文件中,我们使用了基于Buildbot worker的镜像FROM buildbot/buildbot-worker:master。之后,我们可以切换到root用户安装Node.js,然后切换回buildbot用户运行实际命令:

〜/ Dockerfile

FROM buildbot/buildbot-worker:masterUSER root
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y nodejs
USER buildbot

完成后保存并关闭文件。

一旦我们拥有了Dockerfile,我们就可以从中构建我们的镜像。我们将调用镜像npm-worker来明确我们安装的额外依赖项:

$ docker build -t npm-worker - < ~/Dockerfile

Docker将根据我们在其中列出的命令开始构建您的镜像Dockerfile。它将下拉基本镜像及其依赖层,安装Node.js,然后将生成的环境保存到一个名为npm-worker的镜像中。

配置Buildbot主服务器

现在我们有了Docker镜像,我们可以配置Buildbot主机来使用它。

因为我们正在定义一个全新的构建过程,并且因为到目前为止我们对主配置的定制很少,所以我们将从头开始配置。为避免丢失当前信息,我们将原始文件移动到备份文件:

$ sudo mv /home/buildbot/master/master.cfg /home/buildbot/master/master.cfg.bak

显示备份文件的配置,以便我们可以复制一些重要值以在新配置中使用:

$ sudo cat /home/buildbot/master/master.cfg.bak

我们要转移到新配置的重要部分是用户凭据和权限。在输出中查找c['www']['authz']c['www']['auth']开头的配置部分:

. . .
c['www']['authz'] = util.Authz(allowRules = [util.AnyEndpointMatcher(role="admins")],roleMatchers = [util.RolesFromUsername(roles=['admins'], usernames=['Sammy'])]
)
c['www']['auth'] = util.UserPasswordAuth({'Sammy': 'Password'})
. . .

将这些行复制并保存在某处,以便以后可以引用它们。我们将这些详细信息添加到我们的新Buildbot主配置中,以保留我们的用户和身份验证设置。

现在,创建一个新master.cfg文件,我们可以在其中重新定义Buildbot实例的行为:

$ sudo nano /home/buildbot/master/master.cfg

我们将在此文件中定义新的Buildbot主配置。

设置基本项目配置

Buildbot配置文件实际上是一个Python模块,它以牺牲一些复杂性为代价提供了极大的灵活性。

我们将从一些基本配置开始。将以下行粘贴到您的文件中:

/home/buildbot/master/master.cfg

# -*- python -*-
# ex: set filetype=python:
from buildbot.plugins import *c = BuildmasterConfig = {}# Basic config
c['buildbotNetUsageData'] = None
c['title'] = "Hello Hapi"
c['titleURL'] = "https://github.com/your_github_name/hello_hapi"
c['buildbotURL'] = "https://buildmaster_domain_name/"
c['protocols'] = {'pb': {'port': 9989}}

该文件的顶部包含一些注释,许多文本编辑器能够解释这些注释以正确应用语法高亮显示。然后,我们从buildbot.plugins包中导入所有内容,以便我们可以使用工具来构建配置。

Buildbot配置全部由名为BuildmasterConfig的字典定义,因此我们将此变量设置为空字典以启动。

我们创建一个名为c的速记变量,设置为同一个字,以减少整个文件中所需的输入量。

下面的配置中需要注意的一些事项:

  • buildbotNetUsageData设置为None。如果要向开发人员报告使用情况数据,请将其更改为字符串"basic"

  • titletitleURL反映项目的名称和GitHub的仓库。使用指向您自己的fork的链接。

  • buildbotURL设置为Buildbot主服务器的SSL安全域名。记得从https://开始并以尾部斜杠/结束。

  • 与我们的上一个配置不同,该protocol定义并不会和本地主机绑定。我们需要通过Docker桥接网络docker0允许来自Docker容器的连接。

配置Docker Worker

接下来,我们需要定义我们的Docker worker。Buildbot将根据需要使用Docker来配置工作人员。为此,它需要知道如何连接到Docker以及使用哪个映象。

将以下内容粘贴到文件的底部:

/home/buildbot/master/master.cfg

. . .# Workers
c['workers'] = []
c['workers'].append(worker.DockerLatentWorker("npm-docker-worker", None,docker_host='unix://var/run/docker.sock',image='npm-worker',masterFQDN='buildmaster_domain_name'))

c['workers'] =[]行演示了我们在完成配置时将使用的基本约定。我们将配置字典中的键设置为空列表。然后,我们将元素附加到列表以实现实际配置。这使我们可以在以后添加其他元素。

为了定义我们的worker,我们创建一个worker.DockerLatentWorker实例并将其追加到worker列表中。我们将此工作者命名为npm-docker-worker,以便稍后在配置中引用它。然后我们将docker_host设置为Docker的套接字位置,并提供我们创建的Docker镜像的名称(在我们的例子中为npm-worker)。我们将masterFQDN设置为Buildbot master的域名,以确保容器可以到达主服务器,而不管服务器的内部主机名设置如何。

配置调度程序

接下来,我们将定义一个调度程序。Buildbot使用调度程序根据从变更源或更改挂钩收到的更改来决定何时以及如何运行构建(稍后我们将配置更改挂钩)。

将以下配置粘贴到文件的底部:

/home/buildbot/master/master.cfg

. . .# Schedulers
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(name="hello_hapi",change_filter=util.ChangeFilter(project='your_github_name/hello_hapi', branch='master'),treeStableTimer=3,builderNames=["npm"]))

我们使用相同的方法将配置附加到空列表中。在这种情况下,我们附加一个schedulers.SingleBranchScheduler实例。这允许我们在存储库中观察单个分支,并简化了配置。

我们将调度程序命名为“hello_hapi”以正确识别它。然后我们定义一个更改过滤器。来自不同来源的许多不同变更集可以交给调度程序。更改过滤器定义一组标准,用于确定此特定调度程序是否应处理相关更改。在我们的例子中,我们根据项目名称进行过滤,这将由GitHub webhook和我们希望观看的分支报告。

接下来,我们将treeStableTimer设置为3秒,该treeStableTimer确定等待其他更改的时间量。这有助于防止Buildbot为与密切相关的更改排队许多小型构建。最后,我们定义当更改符合我们的条件时应该使用的构建器的名称(我们将暂时定义此为构建器)。

为Node.js项目配置构建工厂

接下来,我们将配置一个用于处理Node.js项目的构建工厂。构建工厂负责定义构建或在我们的案例测试中应该采取的步骤。它通过定义util.BuildFactory实例然后添加应执行的顺序步骤来完成此操作。

将以下内容粘贴到文件的底部:

/home/buildbot/master/master.cfg

. . .# Build Factories
npm_f = util.BuildFactory()
npm_f.addStep(steps.GitHub(repourl='git://github.com/your_github_name/hello_hapi.git', mode='full', method='clobber'))
npm_f.addStep(steps.ShellCommand(command=["npm", "install"]))
npm_f.addStep(steps.ShellCommand(command=["npm", "test"]))

首先,我们定义一个名为npm_f的构建工厂。我们添加的第一步是steps.GitHub实例。在这里,我们设置应该下拉到构建器中的存储库。我们设置mode“full”method“clobber”以在每次提取新代码时完全清理我们的存储库。

我们添加的第二个和第三个步骤是steps.ShellCommand对象,它们定义在构建期间在存储库中运行的shell命令。在我们的例子中,我们需要运行npm install以收集项目的依赖项。之后,我们需要运行npm test以运行我们的测试套件。在大多数情况下,建议将命令定义为一个list (["npm","install"]),以防止shell对命令中的元素应用不需要的扩展。

配置构建器

一旦我们有一个添加了步骤的构建工厂,我们就可以设置一个构建器。构建器将我们已定义的许多元素绑定在一起,以确定构建的执行方式。

将以下配置粘贴到文件的底部:

/home/buildbot/master/master.cfg

. . .# Builders
c['builders'] = []
c['builders'].append(util.BuilderConfig(name="npm",workernames=["npm-docker-worker"],factory=npm_f))

我们将一个util.BuilderConfig对象附加到builders列表中。请记住,我们的构建工厂名为npm_f,我们的Docker工作者称为npm-docker-worker,我们定义的调度程序将把任务传递给名为npm的worker。。我们的构建器定义了这些元素之间的关系,以便我们的调度程序的更改将导致构建工厂步骤在Docker worker中执行。

配置数据库和Web界面

最后,我们可以配置数据库和Web界面设置。与之前的许多项目不同,这两个设置被定义为字典而不是列表。该db字典只指向/home/buildbot/master目录中已有的state.sqlite文件。www词典包含大量额外配置。

将以下内容粘贴到文件的底部。将您从原始Buildbot主配置中复制的身份验证信息替换为以下身份验证块:

/home/buildbot/master/master.cfg

. . .# Database
c['db'] = { 'db_url': "sqlite:///state.sqlite",}# Web Interface
c['www'] = dict(port=8010, plugins=dict(waterfall_view={}, console_view={}))# Auth info copied from the original configuration
c['www']['authz'] = util.Authz(allowRules = [util.AnyEndpointMatcher(role="admins")],roleMatchers = [util.RolesFromUsername(roles=['admins'], usernames=['Sammy'])]
)
c['www']['auth'] = util.UserPasswordAuth({'Sammy': 'Password'})
# End of auth info copied from the original configuration# GitHub webhook receiver
c['www']['change_hook_dialects'] = {'github': {'secret': 'your_secret_value','strict': True,}
}

在定义数据库设置之后,我们创建一个www字典,该字典首先定义要侦听的端口以及要包含在Web UI中的一些视图。接下来,我们添加从先前的Buildbot配置文件中提取的身份验证要求。

最后,我们在www字典中定义了一个名为change_hook_dialects的字典。我们使用它来定义一个GitHub更改挂钩,它将侦听来自GitHub的webhook消息。为您的机密选择一个安全密码,GitHub将使用该密码来验证它将发送的消息。

完成后,保存并关闭文件。

重新启动Buildbot Master以应用新配置

此时,我们已经完全重新配置了Buildbot主进程。我们需要重新启动Buildbot主进程来实现更改。

在我们这样做之前,检查我们的文件是否有重要的语法错误。由于我们从头开始重建配置,因此我们很可能会引入一些错误。

输入以下命令检查文件的语法:

$ sudo buildbot checkconfig /home/buildbot/master

该命令将报告它找到的任何问题。如果未找到任何错误,您将收到如下消息:

Config file is good!

如果报告了任何错误,请仔细阅读错误消息,以便更好地了解错误。再次打开配置文件以尝试解决任何问题。

如果不再出现任何错误,请输入以下命令重新启动Buildbot主服务:

$ sudo systemctl restart buildbot-master

输入以下命令检查操作是否成功:

$ sudo systemctl status buildbot-master
● buildbot-master.service - BuildBot master serviceLoaded: loaded (/etc/systemd/system/buildbot-master.service; enabled; vendor preset: enabled)Active: active (running) since Tue 2017-06-27 19:24:07 UTC; 2s agoMain PID: 8298 (buildbot)Tasks: 2Memory: 51.7MCPU: 1.782sCGroup: /system.slice/buildbot-master.service└─8298 /usr/bin/python /usr/local/bin/buildbot start --nodaemonJun 27 19:24:07 bb5 systemd[1]: Started BuildBot master service

如果服务能够成功重新启动,则会将其标记为活动状态。

在示例存储库中创建GitHub Webhook

现在Buildbot配置了一个Web端点来接受GitHub webhook帖子,我们可以为我们的fork配置一个webhook。

在Web浏览器中,导航到示例项目存储库的fork:

https://github.com/your_github_user/hello_hapi

单击“设置”选项卡以查看项目设置。在设置页面的左侧菜单中,单击Webhooks(GitHub可能会提示您在此过程中重新输入密码以确认您的身份):

img项目设置

单击右侧的“ 添加webhook”按钮以添加新的webhook。

下面的页面将包含一个用于定义webhook的表单。在Payload URL字段中,添加项目的GitHub更改的URL。这是通过指定https://协议,然后是Buildbot master的域名,然后是/change_hook/github构建的。

将内容类型设置为application/x-www-form-urlencoded。在“密码”字段中,输入您在Buildbot主配置文件中选择的秘密密码。您可以选中“Just push”事件触发器,勾选“Active”复选框:

img添加新的webhook

完成后,单击“ 添加webhook”按钮。

您将返回到项目的webhooks索引,在该索引中将显示您的新webhook。如果刷新几次,则应在webhook旁边显示绿色复选标记图标,表示邮件已成功传输:

imgwebhooks索引

如果您看到红色的X,请再次单击webhook,然后向下滚动到Recent Deliveries部分。如果您单击failed delivery,可以获得有关出现问题的更多信息。

测试Webhook

现在我们已经有了webhook,我们可以测试以确保当我们对存储库进行更改时,Buildbot会被警告,触发Docker中的构建,并且能够成功执行测试套件。

在GitHub fork的主页面中,单击绿色“克隆或下载”按钮左侧的“ 创建新文件 ”按钮:

img创建新文件

在随后的屏幕上,创建dummy_file并填写一些文本:

imgdummy_file

完成后,单击页面底部的“ 提交新文件”按钮。

接下来,访问您的Buildbot Web界面,如果您尚未通过身份验证,请登录。

根据您提交dummy_file到存储库后的时间长度,您可能会看到正在进行的构建,如下所示:

imgBuildbot 正在构建

如果构建已经完成,则它将位于“最近构建”部分中:

img构建完成

我们定义的构建器名称“npm”用于标记构建。在该示例中,我们还可以从先前的主配置中看到较早的样本构建器运行。

无论进度如何,单击构建器名称和内部版本号链接以访问构建详细信息页面。此视图包含有关所执行的构建的信息。我们添加到构建工厂的每个步骤都将显示在其自己的部分中:

img构建详细信息

如果单击某个步骤,将显示该命令的输出。如果出现问题,这可以帮助调试:

img调试输出

在上面的输出中,我们可以验证Buildbot是否在我们的测试套件中成功运行了三个测试。

如果构建未成功完成,您可能希望检查的其他一些区域是构建详细信息页面上的其他选项卡以及/home/buildbot/master/twistd.log文件。

调整Buildbot服务

在我们完成之前,我们应该对我们的Buildbot服务进行一些调整。

目前,我们为不再使用的工作人员定义了buildbot-worker服务(我们的Docker工作程序在需要时自动启动)。

我们应该停止并禁用old worker。

要停止正在运行的服务并禁止它在引导时启动,请输入:

$ sudo systemctl stop buildbot-worker
$ sudo systemctl disable buildbot-worker
Removed symlink /etc/systemd/system/buildbot-master.service.wants/buildbot-worker.service.

上面的输出结果表明工作人员下次启动时不会启动。要验证服务是否不再运行,请输入:

$ sudo systemctl status buildbot-worker
● buildbot-worker.service - BuildBot worker serviceLoaded: loaded (/etc/systemd/system/buildbot-worker.service; disabled; vendor preset: enabled)Active: inactive (dead)Jun 27 21:12:48 bb6 systemd[1]: Started BuildBot worker service.
Jun 27 21:55:51 bb6 systemd[1]: Stopping BuildBot worker service...
Jun 27 21:55:51 bb6 systemd[1]: Stopped BuildBot worker service.

我们应该做的最后一件事是在Buildbot主服务和Docker守护进程之间建立一个soft依赖项。由于Buildbot主服务无法在没有Docker的情况下配置new workers,因此我们应该定义此要求。

打开/ etc / systemd / system目录中的buildbot-master.service文件以调整服务文件:

$ sudo nano /etc/systemd/system/buildbot-master.service

[Unit]部分中,将docker.service添加到network.target项之后的After指令中。添加另一个名为docker.serviceWants指令。Wants建立了一个软依赖,而After指令建立了起始顺序:

/etc/systemd/system/buildbot-master.service

[Unit]
Description=BuildBot master service
After=network.target docker.service
Wants=docker.service[Service]
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/master
ExecStart=/usr/local/bin/buildbot start --nodaemon[Install]
WantedBy=multi-user.target

完成后保存并关闭文件。

重新加载systemd守护程序和服务以立即应用配置:

$ sudo systemctl daemon-reload
$ sudo systemctl restart buildbot-master

现在应该在Docker可用之后启动Buildbot主进程。

结论

在本教程中,我们将Buildbot配置为使用webhooks监听对GitHub存储库的更改。收到更改后,Buildbot会根据自定义Docker镜像启动容器以测试新提交。Docker镜像包含一个Buildbot工作器实例以及测试项目代码所需的依赖项。这允许Buildbot在对存储库进行更改时根据需要动态启动Buildbot worker。


参考文献:《How To Set Up Continuous Integration with Buildbot on Ubuntu 16.04》

问答

腾讯云服务器?

相关阅读

教你从0到1搭建小程序音视频

教你快速搭建一场发布会直播方案

移形换影 - 短视频色彩特效背后的故事

此文已由作者授权腾讯云+社区发布,原文链接:https://cloud.tencent.com/developer/article/1178239?fromSource=waitui

欢迎大家前往腾讯云+社区或关注云加社区微信公众号(QcloudCommunity),第一时间获取更多海量技术实践干货哦~

海量技术实践经验,尽在云加社区! https://cloud.tencent.com/developer?fromSource=waitui

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

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

相关文章

strapi 开源api 内容管理平台试用

strapi 是一个开源的api && 内容管理平台&#xff0c;功能操作起来还是比较方便简单的。 安装 使用docker && docker-compose 代码clonegit clone https://github.com/strapi/strapi-docker && cd strapi-docker 启动 docker-compose up -d 访问 首次初…

1.android体系结构介绍

一、Android的介绍 android介绍见百度百科&#xff1a;Android的介绍&#xff0c;度娘把Android介绍的这么清楚&#xff0c;如果谷歌是Android的爹&#xff0c;那度娘就是娘了。 二、Android的架构图 android系统主要分四层&#xff1a; 从上致下&#xff1a; 1、应用层 2、…

2.JVM和DVM之间的区别

1、JVM .java----->.class----->.jar 运行在内存的 栈 栈虚拟机 2、DVM .java----->.class------>.dex-----(加上其它资源文件)---->apk 运行在CPU的 寄存器 寄存器虚拟机 ---------------------------------------------------------- 3、DVM与JVM的区…

Node.js模块以及模块加载机制

2019独角兽企业重金招聘Python工程师标准>>> Node.js中的模块 在Node.js中&#xff0c;以模块为单位划分功能&#xff0c;通过一个完整的模块加载机制使得开发人员可以将应用程序划分为多个不同的部分。模块的使用可以提高代码重用率&#xff0c;提高应用程序的开发…

获取数据库名称dbName

2019独角兽企业重金招聘Python工程师标准>>> Autowired DataSource ds; connection ds.getConnection(); tring dbName connection.getCatalog(); connection.close(); 转载于:https://my.oschina.net/u/2351011/blog/1925838

mysql连接idea详细教程_idea配置连接数据库的超详细步骤

学习时&#xff0c;使用IDEA的时候&#xff0c;需要连接Database&#xff0c;连接时遇到了一些小问题&#xff0c;下面记录一下操作流程以及遇到的问题的解决方法。一、 连接操作简介&#xff1a;介绍如何创建连接&#xff0c;具体连接某个数据库的操作流程。1.1 创建连接打开i…

redis单节点安装

1、下载 redis &#xff1a;https://redis.io/ redis 提供的是 源码包&#xff0c;需要编译。 2、Linux下安装gcc 和 tcl tcl介绍 命令&#xff1a;yum install gcc tcl 3、将redis的源码包&#xff0c;放到 /usr/local/src 下 tar -zxvf redis-4.0.6.tar.gz 4、安装redi…

ManicTime软件破解

这款软件用来记录电脑上程序的运行时间。方便天天用电脑的查看&#xff1a;今天我的时间都去哪儿了&#xff1f; 专业版不免费&#xff0c;而且需要 67 美元。 免费版和专业版的区别 破解补丁和官方软件下载&#xff08;截止博文发布&#xff0c;官方最新版本 版本&#xff1…

mysql根据ID的顺序查找_求救:mysql 如何根据给定的 ID顺序查找结果?

各位大神&#xff0c;现在我遇到了一个难题需要你们的帮助。有下面两个表post表&#xff1a;文章表。record表:记录表&#xff0c;用于记录用户阅读顺序。record表 根据用户的阅读文章顺序用一个字段 postid 记录 post 表的主键ID&#xff0c;既 record.postid 的外键为 post.i…

python入坑指南_Rust入坑指南:万物初始

有没有同学记得我们一起挖了多少个坑&#xff1f;嗯…其实我自己也不记得了&#xff0c;今天我们再来挖一个特殊的坑&#xff0c;这个坑可以说是挖到根源了——元编程。元编程是编程领域的一个重要概念&#xff0c;它允许程序将代码作为数据&#xff0c;在运行时对代码进行修改…

maven引用公共包_使用github作为maven仓库存放发布自己的jar包依赖 实现多个项目公共部分代码的集中,避免团队中多个项目之间代码的复制粘贴...

使用github作为maven仓库存放发布自己的jar包依赖 实现多个项目公共部分代码的集中&#xff0c;避免团队中多个项目之间代码的复制粘贴。1、首先在本地maven位置的配置文件setting.xml(没有该文件就新建这个文件)中&#xff0c;添加配置maven仓库的地址。我用的是我的GitHub仓库…

WPF之鼠标滑动切换图片

原文:WPF之鼠标滑动切换图片在网上找了一会儿也没找到我想要的效果&#xff0c;还是自己动手&#xff0c;丰衣足食吧。 需求&#xff1a;当前面板中只显示一张图片&#xff0c;图片栏的下部有用来显示当前图片处于图片队列中的位置的圆球&#xff0c;并且点击下部栏内的圆球可以…

mysql in 子查询优化_mysql in 子查询 容易优化

mysql in 子查询 简单优化 大数量下&#xff0c;不要使用 in 嵌套子查询&#xff0c;性能很差&#xff0c;很容易卡死。 ? 简单调整方式如下&#xff1a; select uid,nick_name from uc_users where uid in(select fid from uc_follow where uid#uid#) ? 可拆解成&#xff1a…

谷歌浏览器插件入门示例

2019独角兽企业重金招聘Python工程师标准>>> 实现&#xff1a;任何网址实现图片下载和获取当前域名的cookies的json字符串。 图片下载是给小白用的&#xff0c;可以选中批量下载&#xff0c;获取cookies 是为了方便程序员调试用。 获取cookies: git地址&#xff1a;…

Fiddler中response乱码的解决方案

原文连接&#xff1a;http://blog.csdn.net/quiet_girl/article/details/50577828 ---------------------------------------------------------- 有时候我们看到Response中的HTML是乱码的&#xff0c; 这是因为HTML被压缩了&#xff0c; 我们可以通过两种方法去解压缩。 解决…

线程带来的风险

线程安全性问题 多线程环境下 多个线程共享一个资源对资源进行非原子性操作。 以上三者都存在就会发生线程安全性问题 如文中的卖火车票问题&#xff1a;http://blog.csdn.net/zengmingen/article/details/53217229 原因是&#xff1a;一行java代码转成.class字节码文件后是…

vue内引入语音播报功能

为什么80%的码农都做不了架构师&#xff1f;>>> 在vue项目中引入语音播报&#xff0c;使用的科大讯飞语音接入&#xff0c; 具体思路为每次接收到语音信息后存入一个数组&#xff0c;然后监听这个数组&#xff0c;开始冲第一个索引播放&#xff0c;并且同时根据vue…

Mysql中的触发器

原文地址&#xff1a;https://www.cnblogs.com/zyshi/p/6618839.html ---------------------------------------------------------什么是触发器 简单的说&#xff0c;就是一张表发生了某件事&#xff08;插入、删除、更新操作&#xff09;&#xff0c;然后自动触发了预先编写好…

下列选项中不符合python语言变量命名规则的是_学习Python第二日--基本概念和类型...

编程语言分类:解释型语言和编译型语言。解释型语言不会产生额外的文件,运行时一行一行的翻译。编译型语言需要产生一个额外的文件,是电脑能够识别的内容,运行后将产生额外的文件。 变量是可变的量,是它的值可以发生改变。变量的作用是保存值,保存的值可以是数据,而且保存…

优化mysql数据库_MySQL数据库十大优化技巧

WEB开发者不光要解决程序的效率问题&#xff0c;对数据库的快速访问和相应也是一个大问题。希望本文能对大家掌握MySQL优化技巧有所帮助。1. 优化你的MySQL查询缓存在MySQL服务器上进行查询&#xff0c;可以启用高速查询缓存。让数据库引擎在后台悄悄的处理是提高性能的最有效方…