jenkins+kubernetes+git+dockerhub构建devops云平台

Devops简介

k8s助力Devops在企业落地实践

传统方式部署项目为什么发布慢,效率低?

在这里插入图片描述

上线一个功能,有多少时间被浪费了?

在这里插入图片描述

如何解决发布慢,效率低的问题呢?

在这里插入图片描述

在这里插入图片描述

什么是Devops?

在这里插入图片描述

在这里插入图片描述

敏捷开发

提高开发效率,及时跟进用户需求,缩短开发周期。

敏捷开发包括编写代码和构建代码两个阶段,可以使用git或者svn来管理代码,用maven对代码进行构建。

持续集成(CI)

持续集成强调开发人员提交了新代码之后,立刻自动的进行构建、(单元)测试。根据测试结果,可以确定新代码和原有代码能否正确地集成在一起。持续集成过程中很重视自动化测试验证结果,对可能出现的一些问题进行预警,以保障最终合并的代码没有问题。

常见的持续集成工具:

  • Jenkins
    • Jenkins是用Java语言编写的,是目前使用最多和最受欢迎的持续集成工具,使用Jenkins,可以自动监测到git或者svn存储库代码的更新,基于最新的代码进行构建,把构建好的源码或者镜像发布到生产环境。Jenkins还有个非常好的功能:它可以在多台机器上进行分布式地构建和负载测试
  • TeamCity
  • Travis CI
  • Go CD
  • Bamboo
  • GitLab CI
  • Codeship

在这里插入图片描述

它的好处主要有以下几点:

  • 较早的发现错误:每次集成都通过自动化的构建(包括编译、发布、自动化测试)来验证,哪个环节出现问题都可以较早的发现
  • 快速的发现错误:每完成一部分代码的更新,就会把代码集成到主干中,这样就可以快速的发现错误,比较容易的定位错误
  • 提升团队绩效:持续集成中代码更新速度快,能及时发现小问题并进行修改,使团队能创造出更好的产品
  • 防止分支过多的偏离主干:经常持续集成,会使分支代码经常向主干更新,当单元测试失败或者出现bug,如果开发者需要在没有调试的情况下恢复仓库的代码到没有bug的状态,只有很小部分的代码会丢失

持续集成的目的是提高代码质量,让产品快速的更新迭代。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。

Martin Fowler说过:“持续集成并不能消除bug,而是让它们非常容易发现和纠正。”

持续交付

持续交付在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境的“类生产环境”中。交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。

如果所有的代码完成之后一起交付,会导致很多问题爆发出来,解决起来很麻烦,所以持续集成,也就是每更新一次代码,都向下交付一次,这样可以及时发现问题,及时解决,防止问题大量堆积。

持续部署

持续部署是指当交付的代码通过评审之后,自动部署到生产环境中。持续部署是持续交付的最高阶段。

在这里插入图片描述

k8s在Devops中的核心作用

docker和k8s的出现使devops变得更加普及,更加容易实现。在传统运维中我们服务时需要针对不同的环境去安装不同的版本,部署方式也杂、多。那么有了docker之后,一次构建、到处运行,只需要构建一次镜像,那么只要有docker的主机,就可以基于镜像把应用跑起来。

在至多微服务中,每天可能需要去处理各种服务的崩溃,而服务间的依赖调用关系也极其复杂,这队解决问题带来了很大的复杂度。要很好的解决这个问题,就需要用到容器编排工具。

kubernetes的出现主宰了容器编排的市场,也进化了过去的运维方式,将开发与运维联系的更加紧密。而且让devops这一角色变得更加清晰,它是目前可用的很流行的容器解决方案之一。

自动化

敏捷开发---->持续集成---->持续交付---->持续部署

多集群管理

可以根据客户需求对开发,测试,生产环境部署多套kubernetes集群,每个环境使用独立的物理资源,相互之间避免影响。

多环境一致性

kubernetes是基于docker的容器编排工具,因为容器的镜像是不可变的,所以镜像把OS、业务代码、运行环境、程序库、目录结构都包含在内,镜像保存在我们的私有仓库,只要用户从我们提供的私有仓库拉取镜像,就能保证环境的一致性。

实时反馈和智能化报表

每次集成或交付,都会第一时间将结果通过多途径的方式反馈给你,也可以定制适合企业专用的报表平台。

前情提要:

  • 我的节点以及k8s版本

在这里插入图片描述

  • 主从的ip:
ip
wentaomaster1192.168.184.10
wentaonode1192.168.184.20

在这里插入图片描述

在这里插入图片描述

安装nfs存储

#安装nfs并设置开机自启动,主从都需要安装
[root@wentaomaster1 ~]#yum install -y nfs-utils
[root@wentaomaster1 ~]#systemctl enable nfs --now
[root@wentaonode1 ~]#yum install -y nfs-utils
[root@wentaonode1 ~]#systemctl enable nfs --now

在这里插入图片描述

#配置nfs存储目录,仅在master节点配置
[root@wentaomaster1 ~]# vim /etc/exports
/data/v2 *(rw,no_root_squash)
#使nfs配置生效
[root@wentaomaster1 ~]# exportfs -arv

在这里插入图片描述

创建数据存储挂载

  • 创建项目所用的名称空间
[root@wentaomaster1 jenkins-k8s]# kubectl create namespace jenkins-k8s
namespace/jenkins-k8s created
  • 创建存储用的pv
[root@wentaomaster1 jenkins-k8s]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins-k8s-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteMany
  nfs:
    server: 192.168.184.10
    path: /data/v2
[root@wentaomaster1 ~]# kubectl apply -f pv.yaml

在这里插入图片描述

  • 创建pvc
[root@wentaomaster1 jenkins-k8s]# cat pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jenkins-k8s-pvc
  namespace: jenkins-k8s
spec:
  resources:
    requests:
      storage: 10Gi
  accessModes:
  - ReadWriteMany
[root@wentaomaster1 ~]# kubectl apply -f pvc.yaml

在这里插入图片描述

创建serviceaccount并RBAC授权

  • 创建一个服务账号sa并对其授权
[root@wentaomaster1 ~]# kubectl create sa jenkins-k8s-sa -n jenkins-k8s
#对sa服务账号授予系统角色cluster-admin的权限【RBAC】
[root@wentaomaster1 ~]# kubectl create clusterrolebinding jenkins-k8s-sa-cluster -n jenkins-k8s --clusterrole=cluster-admin --serviceaccount=jenkins-k8s:jenkins-k8s-sa

在这里插入图片描述

准备项目需要的镜像

  • 工作节点上,从dockerhub上拉取jenkins镜像(我用的2.418)
#用于安装jenkins用
[root@wentaonode1 ~]# docker pull jenkins/jenkins:2.418

在这里插入图片描述

  • 创建一个dockerfile构建镜像jenkins-slave-latest:v1
[root@wentaomaster1 slave]# cat dockerfile
FROM jenkins/jnlp-slave:4.13.3-1-jdk11
USER root
# 安装Docker
RUN apt-get update && apt-get install -y \
    docker.io
# 将当前用户加入docker用户组
RUN usermod -aG docker jenkins
RUN curl -LO https://dl.k8s.io/release/stable.txt
RUN curl -LO https://dl.k8s.io/release/$(cat stable.txt)/bin/linux/amd64/kubectl
RUN chmod +x kubectl
RUN mv kubectl /usr/local/bin/
ENV DOCKER_HOST unix:///var/run/docker.sock
#k8s中装好jenkins后,是有主从的,构建jenkins时候会在集群里再创建一个jenkins从,我用jenkins-slave-latest这个镜像来构建jenkins从
[root@wentaomaster1 slave]# docker build -t=jenkins-slave-latest:v1 .

在这里插入图片描述

安装jenkins

  • 给nfs的数据目录/data/v2做下权限
[root@wentaomaster1 ~]# chown -R 1000.1000 /data/v2

使用deployment控制器创建jenkins pod

[root@wentaomaster1 ~]# cat  jenkins-deploy.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  name: jenkins
  namespace: jenkins-k8s
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      serviceAccount: jenkins-k8s-sa
      containers:
      - name: jenkins
        image:  docker.io/jenkins/jenkins:2.418
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        - containerPort: 50000
          name: agent
          protocol: TCP
        resources:
          limits:
            cpu: 2000m
            memory: 2Gi
          requests:
            cpu: 500m
            memory: 512Mi
        livenessProbe:
          httpGet:
            path: /login
            port: 8080
          initialDelaySeconds: 60
          timeoutSeconds: 5
          failureThreshold: 12
        readinessProbe:
          httpGet:
            path: /login
            port: 8080
          initialDelaySeconds: 60
          timeoutSeconds: 5
          failureThreshold: 12
        volumeMounts:
        - name: jenkins-volume
          subPath: jenkins-home
          mountPath: /var/jenkins_home
      volumes:
      - name: jenkins-volume
        persistentVolumeClaim:
          claimName: jenkins-k8s-pvc

[root@wentaomaster1 ~]# kubectl apply -f jenkins-deploy.yaml

在这里插入图片描述

给jenkins pod前端加上service,对外部提供网络访问

[root@wentaomaster1 ~]# cat jenkins-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: jenkins-service
  namespace: jenkins-k8s
  labels:
    app: jenkins
spec:
  selector:
    app: jenkins
  type: NodePort
  ports:
  - name: web
    port: 8080
    targetPort: web
    nodePort: 30002
  - name: agent
    port: 50000
    targetPort: agent

[root@wentaomaster1 ~]# kubectl apply -f jenkins-service.yaml
#通过kubectl get svc -n 看到对外提供的端口是30002

在这里插入图片描述

登录jenkins web页面

  • 浏览器网址栏输入192.168.184.10:30002

在这里插入图片描述

  • 可以看到提示为:初始密码在跑jenkins的pod里面的/var/jenkins_home/secrets/initialAdminPassword文件中

在这里插入图片描述

  • 将密码复制后,点击继续

在这里插入图片描述

  • 选择“安装推荐的插件”

在这里插入图片描述

  • 安装完成之后,创建管理员用户

在这里插入图片描述

  • 实例配置不改,用默认url

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 更新kubernetes插件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 点击安装后,下滑到最下面,勾选安装后重启

在这里插入图片描述

  • 安装完成后,再安装jenkins自动化部署的ui界面Blue Ocean

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 输入之前设置的用户、密码,选择保持登录状态

在这里插入图片描述

在这里插入图片描述

jenkins对接kubernetes自动生成jenkins从节点

  • 新增一个云kubernetes

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 填写云kubernetes配置内容
    • 名称:kubernetes
    • kubernetes地址:https://192.168.184.10:6443
      • 6443是kubernetes apiserver的端口
    • kubernetes命名空间:jenkins-k8s

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Jenkins UI界面配置访问Dockerhub凭据

  • 添加dockerhub凭据

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

jenkins+k8s自动化发布项目

在这里插入图片描述

  • 准备好各个环境的命名空间
#创建开发、生产、测试的命名空间
[root@wentaomaster1 ~]# kubectl create ns devlopment
[root@wentaomaster1 ~]# kubectl create ns production
[root@wentaomaster1 ~]# kubectl create ns qatest

在这里插入图片描述

  • 创建流水线自动化发布任务,左侧栏点击新建任务

在这里插入图片描述

在这里插入图片描述

node('testtan') {
    stage('Clone') {
        echo "1.Clone Stage"
        git url: "https://github.com/twttwttwt/jenkins-sample/"
        script {
            build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
        }
    }
    stage('Test') {
      echo "2.Test Stage"

    }
    stage('Build') {
        echo "3.Build Docker Image Stage"
        sh "docker build -t twttwt/jenkins-demo:${build_tag} ."
    }
    stage('Push') {
        echo "4.Push Docker Image Stage"
        withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
            sh "docker login -u ${dockerHubUser} -p ${dockerHubPassword}"
            sh "docker push twttwt/jenkins-demo:${build_tag}"
        }
    }
    stage('Deploy to dev') {
        echo "5. Deploy DEV"
		sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-dev.yaml"
        sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-dev.yaml"
//        sh "bash running-devlopment.sh"
        sh "kubectl apply -f k8s-dev.yaml  --validate=false"
	}	
	stage('Promote to qa') {	
		def userInput = input(
            id: 'userInput',

            message: 'Promote to qa?',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "YES\nNO",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        if (userInput == "YES") {
            sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-qa.yaml"
            sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-qa.yaml"
//            sh "bash running-qa.sh"
            sh "kubectl apply -f k8s-qa.yaml --validate=false"
            sh "sleep 6"
            sh "kubectl get pods -n qatest"
        } else {
            //exit
        }
    }
	stage('Promote to pro') {	
		def userInput = input(

            id: 'userInput',
            message: 'Promote to pro?',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "YES\nNO",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        if (userInput == "YES") {
            sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-prod.yaml"
            sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-prod.yaml"
//            sh "bash running-production.sh"
            sh "cat k8s-prod.yaml"
            sh "kubectl apply -f k8s-prod.yaml --record --validate=false"
        }
    }
}


在这里插入图片描述

  • 点击保存后回到dashboard,可以看到已经多出来了一条任务,点击构建

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

[root@wentaomaster1 ~]# kubectl get pod -n production
[root@wentaomaster1 ~]# kubectl get pod -n devlopment
[root@wentaomaster1 ~]# kubectl get pod -n qatest

在这里插入图片描述

#通过上面可以看到jenkins对接k8s,可以把应用发布到k8s集群的开发、测试、生产环境了。

  • 访问github中index配置的web页面

在这里插入图片描述

devops自动化版本更新

  • 修改上图web页面的index文件

在这里插入图片描述

  • 此时访问web页面,暂时没有改动

在这里插入图片描述

  • 回到dashboard,重新执行一次pipeline文件

在这里插入图片描述

在这里插入图片描述

  • 可以看到,已成功更新

在这里插入图片描述

Devops自动化版本回滚

  • 新建任务

在这里插入图片描述

在这里插入图片描述

node('testtan') {
  stage('git clone') {
    git url: "https://github.com/twttwttwt/jenkins-rollout"
    sh "ls -al"
    sh "pwd"
}
  stage('select env') {
    def envInput = input(
      id: 'envInput',
      message: 'Choose a deploy environment',
      parameters: [
         [
             $class: 'ChoiceParameterDefinition',
             choices: "devlopment\nqatest\nproduction",
             name: 'Env'
         ]
     ]
)
echo "This is a deploy step to ${envInput}"
sh "sed -i 's/<namespace>/${envInput}/' getVersion.sh"
sh "sed -i 's/<namespace>/${envInput}/' rollout.sh"
sh "bash getVersion.sh"
// env.WORKSPACE = pwd()
// def version = readFile "${env.WORKSPACE}/version.csv"
// println version
}
  stage('select version') {
     env.WORKSPACE = pwd()
  def version = readFile "${env.WORKSPACE}/version.csv"
  println version
      def userInput = input(id: 'userInput',
                                        message: '选择回滚版本',
                                        parameters: [
            [
                 $class: 'ChoiceParameterDefinition',
                 choices: "$version\n",
                 name: 'Version'
       ]
      ]
)
       sh "sed -i 's/<version>/${userInput}/' rollout.sh"
}
  stage('rollout deploy') {
      sh "bash rollout.sh"
}
}


  • 保存后回到首页

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

《剑指Offer》--查缺补漏

C sizeof 赋值运算符函数 在C中可以用 struct 和 class 来定义类型。这两种类型有什么区别&#xff1f; 数组 面试题4&#xff1a;二维数组中的查找 暂留 字符串 C/C中每个字符串都以字符

在TMP中计算书名号《》高度的问题

1&#xff09;在TMP中计算书名号《》高度的问题 2&#xff09;FMOD设置中关于Virtual Channel Count&Real Channel Count的参数疑问 3&#xff09;Unity 2021.3.18f1 ParticleSystemTrailGeometryJob粒子拖尾系统崩溃 4&#xff09;XLua打包Lua文件粒度问题 这是第375篇UWA…

NR 2-STEP RA Absolute Timing Advance Command MAC CE的应用场景

3 GPP在 R2-2002413中将2-step RA引入&#xff0c;进而R16 38.321出现了 Absolute TAC MAC CE&#xff0c;在 NR Timing Advance(TA)_ntn rrc-CSDN博客 有提到这个MAC CE&#xff0c;当时以“absolute timing advance command MAC CE 在2-step RA的某个场景下使用”一笔带过&am…

前端架构: 脚手架命令行交互核心实现之inquirer和readline的应用教程

命令行交互核心实现 核心目标&#xff1a;实现命令行行交互&#xff0c;如List命令行的交互呢比命令行的渲难度要更大&#xff0c;因为它涉及的技术点会会更多它涉及以下技术点 键盘输入的一个监听 (这里通过 readline来实现)计算命令行窗口的尺寸清屏光标的移动输出流的静默 …

大数据集群管理软件 CDH、Ambari、DataSophon 对比

文章目录 引言工具介绍CDHAmbariDataSophon 对比分析 引言 大数据集群管理方式分为手工方式和工具方式&#xff0c;手工方式一般指的是手动维护平台各个组件&#xff0c;工具方式是靠大数据集群管理软件对集群进行管理维护。本文针对于常见的方法和工具进行比较&#xff0c;帮助…

langChain学习笔记(待续)

目录 IntroductionLLM的限制扩展理解&#xff1a;什么是机器学习扩展阅读&#xff1a;机器学习的流程 LangChain Introduction LLM的限制 大型语言模型&#xff0c;比如ChatGpt4&#xff0c;尽管已经非常强大&#xff0c;但是仍然存在一些限制&#xff1a; 知识更新&#xff…

SQL注入漏洞解析--less-7

我们先看一下第七关 页面显示use outfile意思是利用文件上传来做 outfile是将检索到的数据&#xff0c;保存到服务器的文件内&#xff1a; 格式&#xff1a;select * into outfile "文件地址" 示例&#xff1a; mysql> select * into outfile f:/mysql/test/one f…

在Golang中简化日志记录:提升性能和调试效率

最大化效率和有效故障排除&#xff1a;在Golang中简化日志记录 日志记录是软件开发的一个基本方面&#xff0c;有助于调试、监控和理解应用程序的流程。在Golang中&#xff0c;有效的日志记录实践可以显著提高性能并简化调试过程。本文探讨了优化Golang日志记录的技术&#xf…

51单片机晶振频率与定时中断产生pwn占空比

单片机中晶振频率为12MHZ的机器周期怎么算? 1、系统晶振频率是12M&#xff0c;则机器周期&#xff1d;12&#xff0f;12&#xff1d;1us&#xff1b; 2、定时1ms&#xff1d;1&#xff0a;1000&#xff1d;1000us&#xff1b; 3、工作在方式0下&#xff1a;最大计数值是2&a…

亚信安慧AntDB助力全链路实时化

实时数据平台&#xff0c;快速实现企业全链路实时化 引入数据仓库、数据挖掘、HTAP等先进理念&#xff0c;通过实时数据应用平台来装载庞大的信息量&#xff0c;进行实时分析处理&#xff0c;克服数据处理过程中的困难&#xff0c;是当下各企事业单位、互联网、金融&#xff0c…

Charles授权码生成器

若资金允许&#xff0c;请点击https://www.charlesproxy.com 购买正版 若资金允许&#xff0c;请点击https://www.charlesproxy.com 购买正版 若资金允许&#xff0c;请点击https://www.charlesproxy.com 购买正版 闲来无事&#xff0c;用GO语言写了个Charles授权码生成器。 使…

【Python笔记-设计模式】中介者模式

一、说明 中介者模式是一种行为设计模式&#xff0c;减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互&#xff0c;迫使它们通过一个中介者对象进行合作。 (一) 解决问题 降低系统中对象之间的直接通信&#xff0c;将复杂的交互转化为通过中介者进行的间接交…

Leetcoder Day26| 回溯part06:总结+三道hard题

332.重新安排行程 给定一个机票的字符串二维数组 [from, to]&#xff0c;子数组中的两个成员分别表示飞机出发和降落的机场地点&#xff0c;对该行程进行重新规划排序。所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必…

Rust调用同级目录中的rs文件和调用下级目录中的rs文件

一、Rust调用同级目录中的rs文件 Rust新建工程demo02&#xff0c;src文件夹下面新建test.rs文件&#xff0c;这样main.rs文件与它属于同级目录中。 关键点&#xff1a;导入test文件和test文件中的Ellipse模块 mod test;//导入test模块&#xff08;文件&#xff09; use test…

StarRocks实战——携程酒店实时数仓

目录 一、实时数仓 二、实时数仓架构介绍 2.1 Lambda架构 2.2 Kappa架构 三、携程酒店实时数仓架构 3.1 架构选型 3.2 实时计算引擎选型 3.3 OLAP选型 四、携程酒店实时订单 4.1 数据源 4.2 ETL数据处理 4.3 应用效果 4.4 总结 原文大佬的这篇实时数仓建设案例有借…

【数据结构】OJ面试题《设计循环队列》(题库+代码)

1.前言 本题需要结构体和数组的知识&#xff0c;记录每天的刷题&#xff0c;继续坚持&#xff01; 2.OJ题目训练 设计循环队列 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队…

将法律条文很美观的复制到word上

前言 目前很多法律条款都没有现成的PDF或者word格式的供大家下载&#xff0c;这个时候呢&#xff0c;领导又要求你帮他搞定&#xff0c;这就很。。。。 步骤 复制全部条款到word中使用wps的排版功能&#xff0c;将空格和空段落全部移除 3. 设置好你需要的格式 标题&#xff…

【mysql 数据库事务】开启事务操作数据库,写入失败后,不回滚,会有问题么? 这里隐藏着大坑,复试,面试时可以镇住面试老师!!!!

建表字段: CREATE TABLE user (id INT(11) NOT NULL AUTO_INCREMENT,nickname VARCHAR(32) NOT NULL COLLATE utf8mb4_general_ci,email VARCHAR(32) NOT NULL COLLATE utf8mb4_general_ci,status SMALLINT(6) UNSIGNED NULL DEFAULT NULL,password VARCHAR(256) NULL DEFAULT…

CAN总线协议基础知识概要

目录 概述 1 引子 1.1 一张图认识CAN总线 1.2 CAN物理层实现 1.3 CAN标准规格 2 CAN协议介绍 2.1 数据帧 2.2 遥控帧 2.3 错误帧 2.4 过载帧 2.5 帧间隔 3 详解数据帧&#xff08;Data Frame&#xff09; 3.1 仲裁场 3.2 识别符 3.2.1 RTR&#xff08;远程发送请…

【appium】App类型、页面元素|UiAutomator与appium|App元素定位

目录 一、App前端基础知识 1、App类型划分 2、App类型对比 3、App页面元素 App页面元素分为布局和控件两种 常见布局&#xff1a; 常见控件&#xff1a;定位软件&#xff1a;appium和sdk自带的uiautomatorviewer都可以定位 二、App元素定位 1、id定位 2、text定位 3…