本文介绍【Mybatis-plus】updateById()方法不能更新字段为null的原因及解决办法。
一、问题描述
在日常项目开发过程中,经常会使用MybatisPlus的
updateById()
方法,快速将接收到的参数或者查询结果中原本不为null的字段更新为null,并且该字段在数据库中可为null,这个时候使用updateById()并不能实现这个操作,不会报错,但是对应的字段并没有更新为null。
二、问题原因
大约 2 分钟
本文介绍【Mybatis-plus】updateById()方法不能更新字段为null的原因及解决办法。
在日常项目开发过程中,经常会使用MybatisPlus的
updateById()
方法,快速将接收到的参数或者查询结果中原本不为null的字段更新为null,并且该字段在数据库中可为null,这个时候使用updateById()并不能实现这个操作,不会报错,但是对应的字段并没有更新为null。
#!/bin/bash
export PATH=$PATH:/usr/sbin
## 脑裂检查及控制:第三方仲裁机制,使用ping网关ip方式
## 循环次数
CHECK_TIME=3
## 虚拟ip
VIP=$1
## 网关ip(根据实际环境修改)
GATEWAY=192.168.1.8
## 本机网卡
eth=enp2s0
## 服务器和网关通信状态 0=失败,1=成功
keepalived_communication_status=1
## 是否获取vip状态 0=失败,1=成功
get_vip_status=1
## keepalived服务状态 0=未运行,1=运行中
keepalived_service_status=1
## 服务状态运行中字符串
active_status_str='active (running)'
echo "开始执行脚本 check_gateway.sh $VIP;时间:"
date
## 查看是否获取vip状态
function check_get_vip_status() {
## 通过ip add命令查看ip信息,搜索$VIP,统计行数,是否等于1
if [ $(ip add | grep "$VIP" | wc -l) -eq 1 ]; then
get_vip_status=1
else
get_vip_status=0
fi
return $get_vip_status
}
## 检查通信状态
function check_keepalived_status() {
## 检测$VIP 能否ping通$GATEWAY:使用$eth网络设备(-I $eth),发送数据包5(-c 5),源地址$VIP询问目的地[vip] $GATEWAY [网关地址 公用参考ip](-s $VIP $GATEWAY) 日志不保存 >/dev/null 2>&1
/sbin/arping -I $eth -c 5 -s $VIP $GATEWAY >/dev/null 2>&1
## 判断上一步执行结果 等于0成功
if [ $? = 0 ]; then
keepalived_communication_status=1
else
keepalived_communication_status=0
fi
return $keepalived_communication_status
}
## 检查keepalived服务状态
function check_keepalived_service_status() {
## 通过systemctl status keepalived.service命令查看keepalived服务状态,搜索$active_status_str,统计行数,是否等于1
if [ $(systemctl status keepalived.service | grep "$active_status_str" | wc -l) -eq 1 ]; then
keepalived_service_status=1
else
keepalived_service_status=0
fi
return $keepalived_service_status
}
## 循环执行
## 判断$CHECK_TIME 不等于 0
while [ $CHECK_TIME -ne 0 ]; do
## 执行check_get_vip_status获取get_vip_status
check_get_vip_status
## 未获取vip
if [ $get_vip_status = 0 ]; then
## 修改CHECK_TIME值 结束循环
CHECK_TIME=0
## 检查服务状态 执行check_keepalived_service_status获取keepalived_service_status
if [ $keepalived_service_status = 0 ]; then
echo "执行脚本 check_gateway.sh $VIP;启动keepalived服务"
systemctl start keepalived.service
fi
echo "执行脚本 check_gateway.sh $VIP;执行结果:未获取vip,无需处理,脚本执行结束,时间:"
date
## 正常运行程序并退出程序
exit 0
fi
## $CHECK_TIME = $CHECK_TIME-1
let "CHECK_TIME -= 1"
## 执行check_keepalived_status获取keepalived_communication_status
check_keepalived_status
## 判断 $keepalived_communication_status = 1 通信成功
if [ $keepalived_communication_status = 1 ]; then
## 修改CHECK_TIME值 结束循环
CHECK_TIME=0
## 检查服务状态 执行check_keepalived_service_status获取keepalived_service_status
check_keepalived_service_status
if [ $keepalived_service_status = 0 ]; then
echo "执行脚本 check_gateway.sh $VIP;启动keepalived服务"
systemctl start keepalived.service
fi
echo "执行脚本 check_gateway.sh $VIP;GATEWAY=$GATEWAY,执行结果:通信正常,无需处理,脚本执行结束,时间:"
date
## 正常运行程序并退出程序
exit 0
fi
## 通信失败&&连续3次
if [ $keepalived_communication_status -eq 0 ] && [ $CHECK_TIME -eq 0 ]; then
## 关闭keepalived
echo "执行脚本 check_gateway.sh $VIP;关闭keepalived服务"
systemctl stop keepalived.service
echo "执行脚本 check_gateway.sh $VIP;GATEWAY=$GATEWAY,执行结果:通信失败&&连续3次 关闭keepalived,脚本执行结束,时间:"
date
## 非正常运行程序并退出程序
exit 1
fi
sleep 3
done
对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机。缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据库必然扛不住,它会报一下警,然后就挂了。此时,如果没有采用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。这就是缓存雪崩。
缓存雪崩的事前事中事后的解决方案如下:
// Jenkinsfile声明模板
pipeline {
// Agent: 表示整个流水线或特定阶段中的步骤和命令执行的位置
// Agent any 在任何可用的代理上执行流水线
// Agent none 表示该 Pipeline 脚本没有全局的 agent 配置。当顶层的 agent 配置为 none 时, 每个 stage 部分都需要包含它自己的 agent
agent any
// 全局变量,会在所有stage中生效
environment {
NAME= 'ZHANG'
// 动态变量 returnStdout: 将命令的执行结果赋值给变量,比如下述的命令返回的是 clang,此时 CC 的值为“clang”。
CC = """${sh(
returnStdout: true,
script: 'echo -n "clang"' //如果使用shell命令的echo赋值变量最好加-n取消换行
)}"""
// 动态变量 returnStatus: 将命令的执行状态赋值给变量,比如下述命令的执行状态为 1,此时 EXIT_STATUS 的值为 1
EXIT_STATUS = """${sh(
returnStatus: true,
script: 'exit 1'
)}"""
// 加密文本
AWS_ACCESS_KEY_ID = credentials('txt1')
AWS_SECRET_ACCESS_KEY = credentials('txt2')
}
// Options: Jenkins 流水线支持很多内置指令,比如 retry 可以对失败的步骤进行重复执行 n 次,可以根据不同的指令实现不同的效果。
// buildDiscarder : 保留多少个流水线的构建记录
// disableConcurrentBuilds : 禁止流水线并行执行,防止并行流水线同时访问共享资源导致流水线失败。
// disableResume : 如果控制器重启,禁止流水线自动恢复。
// newContainerPerStage : agent 为 docker 或 dockerfile 时,每个阶段将在同一个节点的新容器中运行,而不是所有的阶段都在同一个容器中运行。
// quietPeriod : 流水线静默期,也就是触发流水线后等待一会在执行。
// retry : 流水线失败后重试次数。
// timeout : 设置流水线的超时时间,超过流水线时间,job 会自动终止。如果不加 unit 参数默认为 1 分。
// timestamps : 为控制台输出时间戳。
options {
timeout(time: 1, unit: 'HOURS') // 超时时间1小时,如果不加unit参数默认为1分
timestamps() // 所有输出每行都会打印时间戳
buildDiscarder(logRotator(numToKeepStr: '3')) //保留三个历史构建版本
quietPeriod(10) // 注意手动触发的构建不生效
retry(3) // 流水线失败后重试次数
}
// Parameters: 提供了一个用户在触发流水线时应该提供的参数列表 只能定义在 pipeline 顶层。
// 插件: imageTag | gitParameter
parameters {
string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '1') // 执行构建时需要手动配置字符串类型参数,之后赋值给变量
text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '2') // 执行构建时需要提供文本参数,之后赋值给变量
booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '3') // 布尔型参数
choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '4') // 选择形式列表参数
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') // 密码类型参数,会进行加密
imageTag(name: 'DOCKER_IMAGE', description: '', image: 'kubernetes/kubectl', filter: '.*', defaultTag: '', registry: 'https://192.168.10.15', credentialId: 'harbor-account', tagOrder: 'NATURAL') //获取镜像名称与tag
gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
}
// 定时构建 注意: H 的意思不是 HOURS 的意思,而是 Hash 的缩写。主要为了解决多个流水线在同一时间同时运行带来的系统负载压力。
triggers {
cron('H */4 * * 1-5') // 周一到周五每隔四个小时执行一次
cron('H/12 * * * *') // 每隔12分钟执行一次
cron('H * * * *') // 每隔1小时执行一次
}
// 定义流水线
stages {
// 执行某阶段
stage('Build') {
steps {
echo 'Build'
}
}
stage('Stage For Build'){
// label: 以节点标签形式选择某个具体的节点执行 Pipeline 命令
agent { label 'role-master' }
steps {
sh """
echo 'role-master'
echo 'role-master'
"""
}
}
stage('Stage For Build'){
agent {
// node: 和 label 配置类似,只不过是可以添加一些额外的配置,比如 customWorkspace(设置默认工作目录)
node {
label 'role-master'
customWorkspace "/tmp/zhangzhuo/data"
}
}
steps {
sh "echo role-master > 1.txt"
}
}
agent {
// dockerfile: 使用从源码中包含的 Dockerfile 所构建的容器执行流水线或 stage
dockerfile {
filename 'Dockerfile.build' //dockerfile文件名称
dir 'build' //执行构建镜像的工作目录
label 'role-master' //执行的node节点,标签选择
additionalBuildArgs '--build-arg version=1.0.2' //构建参数
}
}
agent{
// docker: 相当于 dockerfile,可以直接使用 docker 字段指定外部镜像即可,可以省去构建的时间。比如使用 maven 镜像进行打包,同时可以指定 args
docker{
image '192.168.10.15/kubernetes/alpine:latest' //镜像地址
label 'role-master' //执行的节点,标签选择
args '-v /tmp:/tmp' //启动镜像的参数
}
}
// docker 的示例
stage('Example Build') {
agent { docker 'maven:3-alpine' }
steps {
echo 'Hello, Maven'
sh 'mvn --version'
}
}
stage('env1') {
// 定义在stage中的变量只会在当前stage生效,其他的stage不会生效
environment {
HARBOR = 'https://192.168.10.15'
}
steps {
sh "env"
}
}
stage('env1') {
options { // 定义在这里这对这个stage生效
timeout(time: 2, unit: 'SECONDS') // 超时时间2秒
timestamps() // 所有输出每行都会打印时间戳
retry(3) // 流水线失败后重试次数
}
steps {
sh "env && sleep 2"
}
}
// Parameters 测试
stage('git') {
steps {
// 使用gitParameter,必须有这个
git branch: "$BRANCH", credentialsId: 'gitlab-key', url: 'git@192.168.10.14:root/env.git'
}
}
// Input 字段可以实现在流水线中进行交互式操作
stage('Example') {
input {
message "还继续么?"
ok "继续"
submitter "alice,bob" // 可选,允许提交 input 操作的用户或组的名称,如果为空,任何登录用户均可提交 input;
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
}
}
steps {
echo "Hello, ${PERSON}, nice to meet you."
}
}
stage('Example Deploy') {
when {
// beforeAgent: 如果 beforeAgent 为 true,则会先评估 when 条件。在 when 条件为 true 时,才会进入该 stage
// beforeInput: 如果 beforeInput 为 true,则会先评估 when 条件。在 when 条件为 true 时,才会进入到 input 阶段;
// beforeOptions: 如果 beforeInput 为 true,则会先评估 when 条件。在 when 条件为 true 时,才会进入到 options 阶段;
// beforeOptions 优先级大于 beforeInput 大于 beforeAgent
beforeAgent true
branch 'main' // 多分支流水线,分支为main才会执行。
expression { BRANCH_NAME ==~ /(main|master)/ } // 并且 满足正则表达式
anyOf { // 并且 DEPLOY_TO 为 master 或 main
environment name: 'DEPLOY_TO', value: 'main'
environment name: 'DEPLOY_TO', value: 'master'
}
}
steps {
echo 'Deploying'
}
}
// Parallel: 很方便的实现并发构建
stage('Parallel Stage') {
failFast true // 表示其中只要有一个分支构建执行失败,就直接推出不等待其他分支构建
parallel {
stage('Branch A') {
steps {
echo "On Branch A"
}
}
stage('Branch B') {
steps {
echo "On Branch B"
}
}
stage('Branch C') {
stages {
stage('Nested 1') {
steps {
echo "In stage Nested 1 within Branch C"
}
}
stage('Nested 2') {
steps {
echo "In stage Nested 2 within Branch C"
}
}
}
}
}
}
// 静态变量
// Jenkins 有许多内置变量可以直接在 Jenkinsfile 中使用,可以通过 JENKINS_URL/pipeline/syntax/globals#env 获取完整列表。目前比较常用的环境变量如下
// BUILD_ID: 当前构建的 ID,与 Jenkins 版本 1.597+中的 BUILD_NUMBER 完全相同
// BUILD_NUMBER: 当前构建的 ID,和 BUILD_ID 一致
// BUILD_TAG: 用来标识构建的版本号,格式为: jenkins-{BUILD_NUMBER}, 可以对产物进行命名,比如生产的 jar 包名字、镜像的 TAG 等;
// BUILD_URL: 本次构建的完整 URL,比如: http://buildserver/jenkins/job/MyJobName/17/%EF%BC%9B
// JOB_NAME: 本次构建的项目名称
// NODE_NAME: 当前构建节点的名称;
// JENKINS_URL: Jenkins 完整的 URL,需要在 SystemConfiguration 设置;
// WORKSPACE: 执行构建的工作目录。
stage('STATIC_ENV') {
steps {
echo "$env.BUILD_ID"
echo "$env.BUILD_NUMBER"
echo "$env.BUILD_TAG"
}
}
//Post: 一般用于流水线结束后的进一步处理 | 一般情况下 post 部分放在流水线的底部
post {
// always: 无论 Pipeline 或 stage 的完成状态如何,都允许运行该 post 中定义的指令;
// changed: 只有当前 Pipeline 或 stage 的完成状态与它之前的运行不同时,才允许在该 post 部分运行该步骤;
// fixed: 当本次 Pipeline 或 stage 成功,且上一次构建是失败或不稳定时,允许运行该 post 中定义的指令;
// regression: 当本次 Pipeline 或 stage 的状态为失败、不稳定或终止,且上一次构建的 状态为成功时,允许运行该 post 中定义的指令;
// failure: 只有当前 Pipeline 或 stage 的完成状态为失败(failure),才允许在 post 部分运行该步骤,通常这时在 Web 界面中显示为红色
// success: 当前状态为成功(success),执行 post 步骤,通常在 Web 界面中显示为蓝色 或绿色
// unstable: 当前状态为不稳定(unstable),执行 post 步骤,通常由于测试失败或代码 违规等造成,在 Web 界面中显示为黄色
// aborted: 当前状态为终止(aborted),执行该 post 步骤,通常由于流水线被手动终止触发,这时在 Web 界面中显示为灰色;
// unsuccessful: 当前状态不是 success 时,执行该 post 步骤;
// cleanup: 无论 pipeline 或 stage 的完成状态如何,都允许运行该 post 中定义的指令。和 always 的区别在于,cleanup 会在其它执行之后执行。
always {
echo 'I will always say Hello again!'
}
failure {
echo 'I will failure say Hello again!'
}
}
}
}
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
分布式,没有单点依赖,用C编写,性能较好
## AWK统计access.log,记录每分钟访问超过60次的ip
awk '{print $1}' access.log | sort | uniq -cd | awk '{if($1>60)print $0}'
# 1. awk '{print $1}' access.log 取出access.log的第一列即为ip。
# 2. sort | uniq -cd 去重和排序
# 3. awk '{if($1>60)print $0}' 判断重复的数量是否超过60个,超过60个就展示出来
Nginx (engine x) 是一个轻量级的、高性能的、基于 Http 的、反向代理服务器,静态 web 服务器。
代理服务器: