语法: select * from table_name force index (index_name) where conditions; 使用 关键字 force
1 2 3 |
#########mysql强制使用指定索引查询 SELECT * FROM `yrd_pay_flow` FORCE INDEX(`idx_trxn_date`) WHERE trxn_date > '2017-08-12 59:59:59' AND trxn_date < '2016-06-23 00:00:00'; |
from:https://www.cnblogs.com/pc-boke/articles/9916986.html
View Details缘由 我们在使用spring boot开发的服务中,一般会选择打包成单体的fatjar来发布服务,这在传统的部署方式下是非常方便的,但是当我们选择使用docker这种容器化的方式来部署应用的时候,却有一点点的不便之处,因为这个单体的jar一般都比较大,每次镜像push到仓库和从仓库拉取都需要比较长的时间。 原因是什么了? docker的一大特色就是镜像的存储是分层的,参考下面这张官图 我们在Dockerfile中的每一个指令会对应到镜像的每一层,docker在更新镜像时,只会推送变更过的层,当它计算出来这一层的摘要和之前的版本一致时,会复用上一次打包镜像时的缓存,会极大的提高打包镜像以及镜像push/pull操作的速度。 那么问题来了,当我们springboot打包出来的单体jar的时候,每次编译这个jar都会发生变化,对应的存储层也会发生变化,push和pull操作时都需要重新推送,而且这个jar一般都不小,一个典型的应用会在100M左右,对应用部署和发布的速度会有比较大的影响。 稍作思考,很容易就能发现这个肥大的jar文件里面,大部分其实都是固定不变的各种依赖库,我们真正每次编译会变化的业务代码部分其实很小很小,可能也就只有几百KB,只要能将这两部分分离,变成docker镜像中的两层,一定能极大的提升镜像发布的速度 牛刀小试 首先拿来动手尝试的是一个springboot admin的项目,项目的结构是这样的: 使用最常见的打包方式:
1 2 3 4 |
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> |
会生成一个32M的jar文件,优化之前的Dockerfile非常简单:
1 2 3 4 5 6 7 8 |
FROM openjdk:11.0.5-stretch as builder RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone VOLUME /tmp COPY target/*.jar ./app.jar CMD ["/bin/bash", "-c", "java -jar -server app.jar"] EXPOSE 8080 |
可以看到这种方式在构建v2版本的镜像时,会重新copy整个完整的jar 如果要拆开这个单体的jar,有两种方式,一是修改mvn打包的配置,将lib包放在独立的文件夹下,在这里我们考虑到项目众多,尽量减少修改,选择了在Docker打包镜像时,解压打包出来的jar包,将其中的内容分开来copy,修改后的Dockerfile如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#采用docker的分阶段构建方式,第一阶段负责解压jar包 FROM openjdk:11.0.5-stretch as builder RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone VOLUME /tmp WORKDIR /target ADD target/*.jar app.jar RUN jar xf app.jar #这里分别copy解压后的内容 FROM openjdk:11.0.5-stretch VOLUME /tmp WORKDIR /app COPY --from=builder target/BOOT-INF/lib ./lib COPY --from=builder target/org/ ./org COPY --from=builder target/META-INF/ ./META-INF COPY --from=builder target/BOOT-INF/classes ./classes CMD ["/bin/bash", "-c", "java -cp .:./classes/:./lib/* -server org.springframework.boot.loader.JarLauncher"] EXPOSE 8080 |
看看修改后的效果: 在copy lib目录时,是直接using cache的。来看看push的时候效果对比 首先是优化前的push: 可以看到在push v2的时候还是会push一个33MB的层,虽然其实我们一行代码没有修改。 然后是优化后的: 可以看到这一次仅仅只推送了一个13KB的层,推送的速度快了非常多,同理也可以想象的到,我们在拉取镜像更新版本时速度会快很多。 路遇荆棘 在针对springboot-admin这个最简单的项目的优化取得很好的效果之后,就开始准备照搬到其他的项目中,没想到同样的方式怎么折腾都无效,分离之后的lib目录依然会每次需要全量重新push。出问题的项目结构大概是这样的: 一个常见的多模块mvn项目,有common,domain,rest-client,rest-server 这4个子模块,其中rest-server会依赖common和domain这两个子模块,打包出来的jar是在rest-server这个模块中。 究竟是什么鬼了? 终得正果 苦苦思索一番之后,lib目录既然不能复用上一次的cache,那一定是因为里面的内容有变化,遂将jar包解压,进到lib目录,真凶果然在此: 项目自身的3个子模块在每次编译的时候也会做为jar包放到lib目录下,这3个jar包每次编译都会有变化,所以导致这一层的cache失效。 找到问题之后,解决的思路就很简单了,将这种jar单独copy到一个目录下即可,修改后的Dockerfile如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
FROM openjdk:11.0.5-stretch as builder RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone VOLUME /tmp WORKDIR /target ADD target/*.jar app.jar RUN jar xf app.jar #创建一个snapshot目录,把snapshot的jar复制过去 RUN mkdir BOOT-INF/snapshot RUN mv BOOT-INF/lib/*SNAPSHOT.jar BOOT-INF/snapshot/ FROM openjdk:11.0.5-stretch VOLUME /tmp WORKDIR /app COPY --from=builder target/BOOT-INF/lib ./lib COPY --from=builder target/org/ ./org COPY --from=builder target/META-INF/ ./META-INF #单独复制snapshot这一层 COPY --from=builder target/BOOT-INF/snapshot ./snapshot COPY --from=builder target/BOOT-INF/classes ./classes CMD ["/bin/bash", "-c", "java -cp .:./classes/:./lib/*:./snapshot/* -server org.springframework.boot.loader.JarLauncher"] EXPOSE 8089 |
这样修改之后效果就和上面单模块的项目一样了,至此,基本完成了springboot项目的docker镜像优化,在jenkins的流水线上可以将原来镜像push的时间从1分钟以上优化到10s左右 未来之路 在整个优化的过程中,发现springboot2.3 M1版本已经有针对性的优化方案,增加了LAYERED_JAR的打包格式,未来可期。 具体可参考下文: www.jdon.com/53738 注: 本文中举例的两个项目案例,可在github上找到:github.com/yishh/sprin… 作者:thor_lee 链接:https://juejin.cn/post/6844904119338008583 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Details遇到的问题: 公司java项目按老的方式打包出来一个fat jar,100MB, 推送到腾讯云镜像仓库很慢,8分钟。。。走的是公网,专线暂时还没配置好 以前是内网harbor,速度还不明显。 归根究底,一次推送100MB是个不合理的事情 思路: 了解spring boot打包,期望将依赖的libs 和 业务代码拆分 优化dockerfile,充分利用缓存 解决问题: 先修改spring-boot-maven-plugin,只打包业务代码。网上有些是配置exclude,我试了,恶心到了。。那么多包挨个找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!--<mainClass>cn.qg.clotho.Bootstrap</mainClass>--> <layout>ZIP</layout> <!--<executable>true</executable>--> <includes> <include> <groupId>${project.groupId}</groupId> <artifactId>${project.artifactId}</artifactId> </include> </includes> </configuration> </plugin> |
新增maven-dependency-plugin,将依赖移到libs目录下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <type>jar</type> <includeTypes>jar</includeTypes> <includeScope>runtime</includeScope> <outputDirectory>${project.build.directory}/libs</outputDirectory> </configuration> </execution> </executions> </plugin> |
优化dockerfile 参考 https://medium.com/@nieldw/caching-maven-dependencies-in-a-docker-build-dca6ca7ad612 ,牛逼
1 2 3 4 5 6 7 8 9 10 11 12 13 |
FROM mvn3.5 as builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY src/ /build/src/ RUN mvn package FROM jdk1.8 EXPOSE 80 CMD exec java -Dloader.path="/home/libs/" -jar /home/app.jar COPY --from=builder /build/target/*.jar /home/app.jar COPY --from=builder /build/target/libs /home/libs/ |
搞定。最终代码变化每次推送也就1MB多 启动命令 java -Dloader.path="libs/" -jar app.jar 作者:小猋_a8f1 链接:https://www.jianshu.com/p/32456eea0488 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Details在这容器化的世界里,我们已经很少直接通过文件发布来运行asp.net core程序了。现在大多数情况下,我们都会使用docker来运行程序。在使用docker之前,我们往往需要打包我们的应用程序。asp.net core程序的镜像打包,网上有很多教程,其中大多数是使用sdk这个镜像来直接打包。打出来的包有好几百MB,3.1 SDK打出来的包甚至超过了1GB。那么有什么办法来缩小我们打出来的镜像吗?最小能缩小到多少呢?这篇文章就来介绍下如何缩小asp.net core 打包出来镜像的大小。 新建asp.net core 程序 新建一个asp.net core应用程序,用来演示打包。首先我们演示下如果使用dotnet sdk5.0来打包 docker 镜像。 sdk:5.0
1 2 3 4 5 6 7 8 |
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /app COPY /. /app RUN dotnet restore -s https://nuget.cdn.azure.cn/v3/index.json WORKDIR /app/CoreDockerImageSizeTest RUN dotnet publish -o ./out -c Release EXPOSE 5000 ENTRYPOINT ["dotnet", "out/CoreDockerImageSizeTest.dll"] |
在项目根目录下新建一个Dockerfile文件,文件内容如上。这个Dockerfile比较简单,使用dotnet sdk:5.0最为底层包来构建,这也是最傻瓜的打包方式。那么看看这个镜像打出来有多大吧。
1 |
docker build . -t coredockerimagesizetest_0.1 |
使用docker build命令进行打包。
1 2 |
REPOSITORY TAG IMAGE ID CREATED SIZE coredockerimagesizetest_0.1 latest 14aea8e0c1d5 5 seconds ago 643MB |
使用docker images命令来查看镜像列表,我们发现我们打出来的镜像居然有643MB,真的很大。如果是内网还好一点,如果在镜像存在docker hub等第三方仓库,这得下半天。显然这个镜像太大了,接下来看我们如何进行优化。 sdk:5.0-buster-slim 最新的VisualStudio内置了docker工具,可以自动为我们生成Dockerfile文件。我们来看看它生成的镜像文件有多大。 右键解决方案=>添加=>Docker支持=>Linux 。 选择完成后VS会为我们自动添加一个Dockerfile在根目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base WORKDIR /app EXPOSE 5000 FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build WORKDIR /src COPY ["CoreDockerImageSizeTest/CoreDockerImageSizeTest.csproj", "CoreDockerImageSizeTest/"] RUN dotnet restore "CoreDockerImageSizeTest/CoreDockerImageSizeTest.csproj" COPY . . WORKDIR "/src/CoreDockerImageSizeTest" RUN dotnet build "CoreDockerImageSizeTest.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "CoreDockerImageSizeTest.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "CoreDockerImageSizeTest.dll"] |
这个自动生成的Dockerfile使用了sdk:5.0-buster-slim这个镜像进行build跟publish,使用aspnet:5.0-buster-slim这个runtime级别的镜像做为final底包。从名字来看,很明显slim代表着轻量。让我们试试这个Dockerfile打出来的包有多大。
1 2 |
REPOSITORY TAG IMAGE ID CREATED SIZE coredockerimagesizetest_0.2 latest 0a24618f6ece 11 seconds ago 210MB |
使用docker build命令进行打包。使用docker images命令查看镜像的大小,这个镜像的大小为210MB。果然比上面的镜像小了很多。那么是否还能继续缩小镜像的大小呢?继续往下看。 5.0-alpine 除了使用buster-slim镜像,我们还可以选择更加小巧的alpine镜像来打包。alpine镜像是继续alpine linux创建的镜像,所以它更加轻量级更加小巧。 关于alpine linux可以查看这篇:Alpine Linux 与 CentOS 有什么区别? 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS base WORKDIR /app EXPOSE 5000 FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build WORKDIR /src COPY ["CoreDockerImageSizeTest/CoreDockerImageSizeTest.csproj", "CoreDockerImageSizeTest/"] RUN dotnet restore "CoreDockerImageSizeTest/CoreDockerImageSizeTest.csproj" COPY . . WORKDIR "/src/CoreDockerImageSizeTest" RUN dotnet build "CoreDockerImageSizeTest.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "CoreDockerImageSizeTest.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "CoreDockerImageSizeTest.dll"] |
修改Dockerfile使用aspnet:5.0-alpine及sdk:5.0-alpine来构建这个镜像。
1 2 |
REPOSITORY TAG IMAGE ID CREATED SIZE coredockerimagesizetest_0.3 latest db34d613e21a 12 seconds ago 108MB |
使用docker build命令进行打包。使用docker images命令查看镜像的大小,这个镜像的大小为108MB。现在这个镜像已经比我们第一次打包减少了500多MB了。那么还能更小吗?请往下看。 runtime-deps:5.0-alpine 最新的.net core程序支持自宿主及单文件发布。如果采用以上发布形式,那么我们可以选择使用runtime-deps:5.0-alpine做为最终底包来打包我们的镜像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS base WORKDIR /app EXPOSE 5000 FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build WORKDIR /src COPY ["CoreDockerImageSizeTest/CoreDockerImageSizeTest.csproj", "CoreDockerImageSizeTest/"] RUN dotnet restore "CoreDockerImageSizeTest/CoreDockerImageSizeTest.csproj" COPY . . WORKDIR "/src/CoreDockerImageSizeTest" RUN dotnet build "CoreDockerImageSizeTest.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "CoreDockerImageSizeTest.csproj" -c Release -o /app/publish \ --runtime alpine-x64 \ --self-contained true \ /p:PublishTrimmed=true \ /p:PublishSingleFile=true FROM mcr.microsoft.com/dotnet/runtime-deps:5.0-alpine AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["./CoreDockerImageSizeTest"] |
修改Dockerfile,使用/runtime-deps:5.0-alpine做为final镜像。
1 2 |
REPOSITORY TAG IMAGE ID CREATED SIZE coredockerimagesizetest_0.5 latest dab1289626f9 6 seconds ago 54.6MB |
使用docker build命令进行打包。使用docker images命令查看镜像的大小,这个镜像的大小为54.6MB。 总结 通过以上演示,我们的镜像大小从一开始的600多MB缩小到了54MB。一般生产我主要选择buster-slim这个镜像来打包。如果选择runtime-deps打包,打出来的包是最小的,虽然演示项目是可以运行的,但是本人没有在生产使用过,还请谨慎使用。 代码在这:CoreDockerImageSizeTest from:https://www.cnblogs.com/kklldog/p/netcore-docker-image-size.html
View Details就一句话:
1 |
SELECT * from PrjOlc WHERE (Prj,SubID) in (SELECT Prj,SubID FROM SP where stage='设计' and 负责人 = 'XXX000') |
from:https://www.cnblogs.com/ShengunErshu/p/14239690.html
View Details下午跑程序,在插入mysql时突然报错: ”The table‘xxxx’is full“ 而之前一直没问题的。 上网查了一下,都说临时表的问题,需要设置”tmp_table_size“: tmp_table_size 如果内存内的临时表超过该值,MySQL自动将它转换为硬盘上的MyISAM表。如果你执行许多高级GROUP BY查询并且有大量内存,则可以增加tmp_table_size的值。 http://www.2cto.com/database/201106/92968.html 感觉与我们服务器情况不太相符:我们没用到临时表,而且tmp_table_size已经非常大了。 再查到: mysql出现"the table is full"的问题,一般有两个原因: 一 .You are using the MEMORY (HEAP) storage engine; in this case you need to increase the value of the max_heap_table_size system variable. See Section 5.1.3, “Server System Variables”. 于是就修改Mysql的配置文件/etc/my.cnf,在[mysqld]下添加/修改两行: tmp_table_size = 256M max_heap_table_size = 256M 系统默认是16M,修改完后重启mysql 二.硬盘空间满了,清理硬盘即可. http://linux.net527.cn/fuwuqiyingyong/Mysql_shujuku/2011/1003/44014.html 在服务器df了一下,果然硬盘空间不够了,已经使用了100%。 追查下来,发现是mysql的日志文件将硬盘撑爆了,有大量的mysql-bin.000XXX之类的日志文件。 如何处理?很简单: (1)清除这些日志文件 (2)如果不需要的话,可以关闭mysql的bin-log功能。 具体操作: 这是数据库的操作日志,例如UPDATE一个表,或者DELETE一些数据,即使该语句没有匹配的数据,这个命令也会存储到日志文件中,还包括每个语句执行的时间,也会记录进去的 这样做主要有以下两个目的: 1:数据恢复 如果你的数据库出问题了,而你之前有过备份,那么可以看日志文件,找出是哪个命令导致你的数据库出问题了,想办法挽回损失。 2:主从服务器之间同步数据 主服务器上所有的操作都在记录日志中,从服务器可以根据该日志来进行,以确保两个同步。 处理方法分两种情况: 1:只有一个mysql服务器,那么可以简单的注释掉这个选项就行了。 vi /etc/my.cnf把里面的log-bin这一行注释掉,重启mysql服务即可。 2:如果你的环境是主从服务器,那么就需要做以下操作了。 A:在每个从属服务器上,使用SHOW SLAVE STATUS来检查它正在读取哪个日志。 B:使用SHOW MASTER LOGS获得主服务器上的一系列日志。 C:在所有的从属服务器中判定最早的日志,这个是目标日志,如果所有的从属服务器是更新的,就是清单上的最后一个日志。 D:清理所有的日志,但是不包括目标日志,因为从服务器还要跟它同步。 清理日志方法为: PURGE MASTER LOGS […]
View Details一,对记录的操作 1.创建有json字段的表
1 2 |
-- 创建表 CREATE TABLE t_json(id INT PRIMARY KEY, sname VARCHAR(20) , info JSON); |
2.插入记录
1 2 3 4 5 6 |
-- 插入含有json数组的记录 INSERT INTO t_json(id,sname,info) VALUES( 1, 'name1', JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME())); -- 插入含有json对象的记录 INSERT INTO t_json(id,sname,info) VALUES( 2, 'name2', JSON_OBJECT("age", 20, "time", now())); INSERT INTO t_json(id,sname,info) VALUES( 3, 'name3', '{"age":20, "time":"2018-07-14 10:52:00"}'); |
3.查询记录
1 2 3 4 5 |
-- 查询记录 SELECT sname,JSON_EXTRACT(info,'$.age') FROM t_json; SELECT sname,info->'$.age' FROM t_json; -- 查询key SELECT id,json_keys(info) FROM t_json; |
4.修改记录
1 2 3 4 5 6 7 8 |
-- 增加键 UPDATE t_json SET info = json_set(info,'$.ip','192.168.1.1') WHERE id = 2; -- 变更值 UPDATE t_json SET info = json_set(info,'$.ip','192.168.1.2') WHERE id = 2; -- 删除键 UPDATE t_json SET info = json_remove(info,'$.ip') WHERE id = 2; |
二,创建json值函数 1.JSON_ARRAY 生成json数组
1 2 3 |
-- JSON_ARRAY(val1,val2,val3...) -- 生成一个包含指定元素的json数组。 SELECT JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME()); -- [1, "abc", null, true, "10:37:08.000000"] |
2.JSON_OBJECT 生成json对象
1 2 3 |
-- JSON_OBJECT(key1,val1,key2,val2...) -- 生成一个包含指定K-V对的json object。如果有key为NULL或参数个数为奇数,则抛错。 SELECT JSON_OBJECT('age', 20, 'time', now()); -- {"id": 87, "name": "carrot"} |
3.JSON_QUOTE 加"号
1 2 3 |
-- JSON_QUOTE(json_val) -- 将json_val用"号括起来。 SELECT JSON_QUOTE('[1,2,3]'); -- "[1,2,3]" |
三,搜索json值函数 1.JSON_CONTAINS 指定数据是否存在
1 2 3 4 |
set @j = '{"a": 1, "b": 2, "c": {"d": 4}}'; -- JSON_CONTAINS(json_doc, val[, path]) -- 查询json文档是否在指定path包含指定的数据,包含则返回1,否则返回0。如果有参数为NULL或path不存在,则返回NULL。 SELECT JSON_CONTAINS(@j, '4', '$.c.d'); -- 1 |
2.JSON_CONTAINS_PATH 指定路径是否存在
1 2 3 4 5 |
-- JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...) -- 查询是否存在指定路径,存在则返回1,否则返回0。如果有参数为NULL,则返回NULL。 -- one_or_all只能取值"one"或"all",one表示只要有一个存在即可;all表示所有的都存在才行。 SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e'); -- 1 SELECT JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.c.d'); -- 1 |
3.JSON_EXTRACT 查找所有指定数据
1 2 3 4 5 6 |
-- JSON_EXTRACT(json_doc, path[, path] ...) -- 从json文档里抽取数据。如果有参数有NULL或path不存在,则返回NULL。如果抽取出多个path,则返回的数据封闭在一个json array里。 set @j2 = '[10, 20, [30, 40]]'; SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]'); -- 20 SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]'); -- [20, 10] SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]'); -- [30, 40] |
4.JSON_KEYS 查找所有指定键值
1 2 3 4 5 |
-- JSON_KEYS(json_doc[, path]) -- 获取json文档在指定路径下的所有键值,返回一个json array。如果有参数为NULL或path不存在,则返回NULL。 SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}'); -- ["a", "b"] SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b'); -- ["c"] SELECT id,json_keys(info) FROM t_json; |
5.JSON_SEARCH 查找所有指定值的位置
1 2 3 4 5 6 7 8 9 10 11 12 |
-- JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...]) -- 查询包含指定字符串的paths,并作为一个json array返回。如果有参数为NUL或path不存在,则返回NULL。 -- one_or_all:"one"表示查询到一个即返回;"all"表示查询所有。 -- search_str:要查询的字符串。 可以用LIKE里的'%'或‘_’匹配。 -- path:在指定path下查。 SET @j3 = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]'; SELECT JSON_SEARCH(@j3, 'one', 'abc'); -- "$[0]" SELECT JSON_SEARCH(@j3, 'all', 'abc'); -- ["$[0]", "$[2].x"] SELECT JSON_SEARCH(@j3, 'all', 'abc', NULL, '$[2]'); -- "$[2].x" SELECT JSON_SEARCH(@j3, 'all', '10'); -- "$[1][0].k" SELECT JSON_SEARCH(@j3, 'all', '%b%'); -- ["$[0]", "$[2].x", "$[3].y"] SELECT JSON_SEARCH(@j3, 'all', '%b%', NULL, '$[2]'); -- "$[2].x" |
四,修改json值函数 1.JSON_ARRAY_APPEND 指定位置追加数组元素
1 2 3 4 5 6 7 8 |
-- JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...) -- 在指定path的json array尾部追加val。如果指定path是一个json object,则将其封装成一个json array再追加。如果有参数为NULL,则返回NULL。 SET @j4 = '["a", ["b", "c"], "d"]'; -- SELECT JSON_ARRAY_APPEND(@j4, '$[1][0]', 3); -- ["a", [["b", 3], "c"], "d"] SET @j5 = '{"a": 1, "b": [2, 3], "c": 4}'; SELECT JSON_ARRAY_APPEND(@j5, '$.b', 'x'); -- {"a": 1, "b": [2, 3, "x"], "c": 4} SELECT JSON_ARRAY_APPEND(@j5, '$.c', 'y'); -- {"a": 1, "b": [2, 3], "c": [4, "y"]} SELECT JSON_ARRAY_APPEND(@j5, '$', 'z'); -- [{"a": 1, "b": [2, 3], "c": 4}, "z"] |
2.JSON_ARRAY_INSERT 指定位置插入数组元素
1 2 3 4 5 6 7 |
-- JSON_ARRAY_INSERT(json_doc, path, val[, path, val] ...) -- 在path指定的json array元素插入val,原位置及以右的元素顺次右移。如果path指定的数据非json array元素,则略过此val;如果指定的元素下标超过json array的长度,则插入尾部。 SET @j6 = '["a", {"b": [1, 2]}, [3, 4]]'; SELECT JSON_ARRAY_INSERT(@j6, '$[1]', 'x'); -- ["a", "x", {"b": [1, 2]}, [3, 4]] SELECT JSON_ARRAY_INSERT(@j6, '$[100]', 'x'); -- ["a", {"b": [1, 2]}, [3, 4], "x"] SELECT JSON_ARRAY_INSERT(@j6, '$[1].b[0]', 'x'); -- ["a", {"b": ["x", 1, 2]}, [3, 4]] SELECT JSON_ARRAY_INSERT(@j6, '$[0]', 'x', '$[3][1]', 'y'); -- ["x", "a", {"b": [1, 2]}, [3, "y", 4]] |
3.JSON_INSERT 指定位置插入
1 2 3 4 |
-- JSON_INSERT(json_doc, path, val[, path, val] ...) -- 在指定path下插入数据,如果path已存在,则忽略此val(不存在才插入)。 SET @j7 = '{ "a": 1, "b": [2, 3]}'; SELECT JSON_INSERT(@j7, '$.a', 10, '$.c', '[true, false]'); -- {"a": 1, "b": [2, 3], "c": "[true, false]"} |
4.JSON_REPLACE 指定位置替换
1 2 3 |
-- JSON_REPLACE(json_doc, path, val[, path, val] ...) -- 替换指定路径的数据,如果某个路径不存在则略过(存在才替换)。如果有参数为NULL,则返回NULL。 SELECT JSON_REPLACE(@j7, '$.a', 10, '$.c', '[true, false]'); -- {"a": 10, "b": [2, 3]} |
5.JSON_SET 指定位置设置
1 2 3 |
-- JSON_SET(json_doc, path, val[, path, val] ...) -- 设置指定路径的数据(不管是否存在)。如果有参数为NULL,则返回NULL。 SELECT JSON_SET(@j7, '$.a', 10, '$.c', '[true, false]'); -- {"a": 10, "b": [2, 3], "c": "[true, false]"} |
6.JSON_MERGE 合并
1 2 3 4 5 6 7 8 9 |
-- JSON_MERGE(json_doc, json_doc[, json_doc] ...) -- merge多个json文档。规则如下: -- 如果都是json array,则结果自动merge为一个json array; -- 如果都是json object,则结果自动merge为一个json object; -- 如果有多种类型,则将非json array的元素封装成json array再按照规则一进行mege。 SELECT JSON_MERGE('[1, 2]', '[true, false]'); -- [1, 2, true, false] SELECT JSON_MERGE('{"name": "x"}', '{"id": 47}'); -- {"id": 47, "name": "x"} SELECT JSON_MERGE('1', 'true'); -- [1, true] SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); -- [1, 2, {"id": 47}] |
7.JSON_REMOVE 指定位置移除
1 2 3 4 |
-- JSON_REMOVE(json_doc, path[, path] ...) -- 移除指定路径的数据,如果某个路径不存在则略过此路径。如果有参数为NULL,则返回NULL。 SET @j8 = '["a", ["b", "c"], "d"]'; SELECT JSON_REMOVE(@j8, '$[1]'); -- ["a", "d"] |
8.JSON_UNQUOTE 去"号
1 2 3 |
-- JSON_UNQUOTE(val) -- 去掉val的引号。如果val为NULL,则返回NULL。 SELECT JSON_UNQUOTE("\"123\""); -- 123 |
五,返回json值属性的函数 1.JSON_DEPTH 深度
1 2 3 4 5 6 |
-- JSON_DEPTH(json_doc) -- 获取json文档的深度。如果参数为NULL,则返回NULL。 -- 空的json array、json object或标量的深度为1。 SELECT JSON_DEPTH('{}'), JSON_DEPTH('[]'), JSON_DEPTH('true'); -- 1 1 1 SELECT JSON_DEPTH('[10, 20]'), JSON_DEPTH('[[], {}]'); -- 2 2 SELECT JSON_DEPTH('[10, {"a": 20}]'); -- 3 |
2.JSON_LENGTH 长度
1 2 3 4 5 6 7 8 9 |
-- JSON_LENGTH(json_doc[, path]) -- 获取指定路径下的长度。如果参数为NULL,则返回NULL。 -- 长度的计算规则: -- 标量的长度为1; -- json array的长度为元素的个数; -- json object的长度为key的个数。 SELECT JSON_LENGTH('[1, 2, {"a": 3}]'); -- 3 SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}'); -- 2 SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b'); -- 1 |
[…]
View Details【0】需求 【0.1】需求描述 数据库中 num字段值为: 实现的效果:需要将一行数据变成多行 【0.2】实现的SQL
1 2 3 4 5 6 |
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1) AS num FROM mysql.help_topic WHERE help_topic_id < LENGTH('7654,7698,7782,7788')-LENGTH(REPLACE('7654,7698,7782,7788',',',''))+1 |
涉及的知识点 【1】字符串拆分: SUBSTRING_INDEX(str, delim, count) 参数解说 解释 str 需要拆分的字符串 delim 分隔符,通过某字符进行拆分 count 当 count 为正数,取第 n 个分隔符之前的所有字符; 当 count 为负数,取倒数第 n 个分隔符之后的所有字符。 举例
1 2 3 4 5 |
(1)获取第2个以逗号为分隔符之前的所有字符。 SELECT SUBSTRING_INDEX('7654,7698,7782,7788',',',2); <img class="medium-zoom-image" src="https://img2020.cnblogs.com/blog/1302413/202102/1302413-20210223175157464-1078941390.png" alt="" data-mce-src="https://img2020.cnblogs.com/blog/1302413/202102/1302413-20210223175157464-1078941390.png"> |
1 2 3 |
(2)获取最后一个到倒数第2个以逗号分隔符之后的所有字符 SELECT SUBSTRING_INDEX('7654,7698,7782,7788',',',-2); |
所以,我们的核心代码中的 -1 ,就是获取以逗号为分隔符的最后一个值;也就是7788 【2】替换函数:replace( str, from_str, to_str) 参数名 解释 str 需要进行替换的字符串 from_str 需要被替换的字符串 to_str 需要替换的字符串 2. 举例
1 2 3 |
(1)将分隔符逗号替换为空。 SELECT REPLACE('7654,7698,7782,7788',',',''); |
【3】获取字符串长度:LENGTH( str ) 参数名 解释 str 需要计算长度的字符串 举例
1 2 3 4 |
(1)获取 ‘7654,7698,7782,7788’ 字符串的长度 SELECT LENGTH('7654,7698,7782,7788') <img src="https://img2020.cnblogs.com/blog/1302413/202102/1302413-20210223175618490-72037422.png" alt="" data-mce-src="https://img2020.cnblogs.com/blog/1302413/202102/1302413-20210223175618490-72037422.png"> |
【4】实现的原理解析 【4.0】实现SQL 需要解析的SQL
1 2 3 4 5 6 |
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1) AS num FROM mysql.help_topic WHERE help_topic_id < LENGTH('7654,7698,7782,7788')-LENGTH(REPLACE('7654,7698,7782,7788',',',''))+1 |
此处利用 mysql 库的 help_topic 表的 help_topic_id 来作为变量,因为 help_topic_id 是自增的,当然也可以用其他表的自增字段辅助。 help_topic 表: 注意,这个辅助表的ID最大长度只有642;如果过长的字符串,可能需要借助其他自增的辅助表(可以是现有表,也可以自己造一个 1,2,3,4 递增的行即可) […]
View Details最近在运行的项目出现了一个线上事故,有人反映商城的东西下不了单了,到后台看了一下,果然报了一个错 Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1046 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.; ]; Packet for query is too large (1046 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.; nested exception is com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1046 > 1024). You can change this value on the server by setting the max_allowed_packet' variable. 其实上面的报错信息就给出了解决方案了,原来mysql根据配置文件会限制server接受的数据包大小。如果一次插入数据库中的数据太大的话就会失败,官方也有这方面的介绍 官方介绍 用命令行查看show VARIABLES like '%max_allowed_packet%';果然max_allowed_packet太小了 解决方法 1、修改配置文件(推荐) 在mysql中的my.ini文件中(在programdata隐藏文件中),修改max_allowed_packet的值 比如:max_allowed_packet=128M 然后重启mysql就可以 2、命令行中设置 set global max_allowed_packet = […]
View Detailsconsul consul用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 什么叫服务治理发现?起初我们的服务比较单一,各服务之间通过接口就能访问。后面服务越来越复杂出现了分布式,为了不引起单点问题,必然是多服务部署,如果还用原来的方式直接连接,那么在某个服务挂掉或者修改了信息,就会导致连接失败。如果连接端能够不去关心具体的服务配置,他只要连接到那个服务,后续的工作由其它服务保证,包括负载均衡、健康检查等,保证总有可用的连接那就行了,consul就是做这个的,当然,它的功能远不止这些,这里只是以服务发现为例。 与它同类的东西,还有Eureka、zooKeeper、etcd等也能做这些事,说不上谁好谁坏,看场景挑合适的吧,不过Eureka现在已经闭源了,这个还是建议不要去用这个了。 consul下载 consule的安装超级简单,去官方下载地址Download ,找到自已对应系统的压缩包,解压后里面就一个文件consul, 将这个文件放到你的PATH中,就能直接用了。 验证下安装成功没有, 看到下面的提示就行了。
1 2 3 |
$ consul version Consul v1.7.2 Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents) |
consul的CLI操作 consul提供了cli的命令操作,如启动代理、键值存储、注册/注销服务、加入集群等,这个consul提供的HTTP的API操作也是一样的,只是这里都是shell的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$ consul Usage: consul [--version] [--help] <command> [<args>] Available commands are: acl Interact with Consul's ACLs agent Runs a Consul agent catalog Interact with the catalog config Interact with Consul's Centralized Configurations connect Interact with Consul Connect debug Records a debugging archive for operators event Fire a new event exec Executes a command on Consul nodes force-leave Forces a member of the cluster to enter the "left" state info Provides debugging information for operators. intention Interact with Connect service intentions join Tell Consul agent to join cluster keygen Generates a new encryption key keyring Manages gossip layer encryption keys kv Interact with the key-value store leave Gracefully leaves the Consul cluster and shuts down lock Execute a command holding a lock login Login to Consul using an auth method logout Destroy a Consul token created with login maint Controls node or service maintenance mode members Lists the members of a Consul cluster monitor Stream logs from a Consul agent operator Provides cluster-level tools for Consul operators reload Triggers the agent to reload configuration files rtt Estimates network round trip time between nodes services Interact with services snapshot Saves, restores and inspects snapshots of Consul server state tls Builtin helpers for creating CAs and certificates validate Validate config files/directories version Prints the Consul version watch Watch for changes in Consul |
Agent启动 consul是通过Agent来运行的,Agent又分为Server Agent和Client Agent两种类型,这两类型基本上是没区别的,Server Agent会将服务的消息存储起来,至少要启动一个Server Agent,为了防止单点,集群环境中推荐3-5个。 Client Agent主要用于注销服务、健康检查及转发Server Agent的查询等,它相当于一个代理,所以他必须在集群的每台主机上都要运行。 先看下Agent的常用配置
1 |
$ consul agent --help |
--server 定义运行server agent --data-dir 配置consul数据存储路径 --bootstrap-expect :期望的server节点数目,consul一直等到指定sever数目的时候才会引导整个集群 --bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0 --node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名 --ui: web的管理ui,查看服务和节点 --config-dir:配置文件目录,所有以.json结尾的文件都会被加载,可以是服务或consul自身的配置 --client:提供HTTP、DNS、RPC等服务,默认是127.0.0.1,不对外提供服务,如果需要则改成0.0.0.0 我本地没有虚拟机,也没用Docker操作,所以,如果要同时启动Server和Client的话,我就用的改端口的方式,当然生产环境肯定就没有这个了,它都是一台机器启动一个Agent, 这里只是测试用的。 启动一个Server Agent
1 |
$ consul agent --server=true --ui=true --data-dir=/tmp/consul --node=server1 --dev |
上面的 --server表示以server方式,--ui 会开启一个web ui管理界面, --dev 表示开发者模式,不需要ACL验证。不然那个web ui的打不开会报没有权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
==> Starting Consul agent... Version: 'v1.7.2' Node ID: 'f6272369-098a-1412-ed86-6e2076c1e5e4' Node name: 'server1' Datacenter: 'dc1' (Segment: '<all>') Server: true (Bootstrap: false) Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600) Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302) Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false ==> Log data will now stream in as it occurs: 2020-04-01T14:28:52.579+0800 [DEBUG] agent.tlsutil: Update: version=1 2020-04-01T14:28:52.580+0800 [DEBUG] agent.tlsutil: OutgoingRPCWrapper: version=1 2020-04-01T14:28:52.580+0800 [INFO] agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:f6272369-098a-1412-ed86-6e2076c1e5e4 Address:127.0.0.1:8300}]" 2020-04-01T14:28:52.580+0800 [INFO] agent.server.raft: entering follower state: follower="Node at 127.0.0.1:8300 [Follower]" leader= 2020-04-01T14:28:52.581+0800 [INFO] agent.server.serf.wan: serf: EventMemberJoin: server1.dc1 127.0.0.1 2020-04-01T14:28:52.581+0800 [INFO] agent.server.serf.lan: serf: EventMemberJoin: server1 127.0.0.1 2020-04-01T14:28:52.581+0800 [INFO] agent.server: Adding LAN server: server="server1 (Addr: tcp/127.0.0.1:8300) (DC: dc1)" 2020-04-01T14:28:52.581+0800 [INFO] agent.server: Handled event for server in area: event=member-join server=server1.dc1 area=wan 2020-04-01T14:28:52.581+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8600 network=tcp 2020-04-01T14:28:52.582+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8600 network=udp 2020-04-01T14:28:52.582+0800 [INFO] agent: Started HTTP server: address=127.0.0.1:8500 network=tcp 2020-04-01T14:28:52.582+0800 [INFO] agent: Started gRPC server: address=127.0.0.1:8502 network=tcp 2020-04-01T14:28:52.582+0800 [INFO] agent: started state syncer ==> Consul agent running! |
启动Client Agent
1 |
$ consul agent --data-dir=/tmp/consul_client --join=127.0.0.1:8301 --serf-lan-port=8303 --serf-wan-port=8305 --dns-port=8601 --server-port=8304 --http-port=8503 --server=false --config-dir=./consul.d --enable-script-checks --node=client1 |
上面有一个--join表示加入到集群中,写server agent的地址就行。 config-dir的配置目录下面一个服务的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "service":{ "name":"web", "tags":[ "local" ], "port":80, "check":{ "name":"ping", "args":["/usr/bin/curl","-s", "http://localhost/"], "interval":"10s" } } } |
上面的命令运行后,会启动一个名字为“web"的服务,并提供健康检查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
==> Starting Consul agent... Version: 'v1.7.2' Node ID: 'e1c8f283-f5c4-27e7-c29c-64666df1c52b' Node name: 'client1' Datacenter: 'dc1' (Segment: '') Server: false (Bootstrap: false) Client Addr: [127.0.0.1] (HTTP: 8503, HTTPS: -1, gRPC: -1, DNS: 8601) Cluster Addr: 192.168.0.103 (LAN: 8303, WAN: 8305) Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false ==> Log data will now stream in as it occurs: 2020-04-01T00:00:49.227+0800 [INFO] agent.client.serf.lan: serf: EventMemberJoin: client1 192.168.0.103 2020-04-01T00:00:49.231+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8601 network=udp 2020-04-01T00:00:49.232+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8601 network=tcp 2020-04-01T00:00:49.232+0800 [INFO] agent: Started HTTP server: address=127.0.0.1:8503 network=tcp ==> Joining cluster... 2020-04-01T00:00:49.232+0800 [INFO] agent: (LAN) joining: lan_addresses=[127.0.0.1:8301] 2020-04-01T00:00:49.233+0800 [WARN] agent.client.memberlist.lan: memberlist: Refuting a dead message (from: client1) 2020-04-01T00:00:49.233+0800 [INFO] agent.client.serf.lan: serf: EventMemberJoin: server1 127.0.0.1 2020-04-01T00:00:49.233+0800 [INFO] agent.client: adding server: server="server1 (Addr: tcp/127.0.0.1:8300) (DC: dc1)" 2020-04-01T00:00:49.233+0800 [INFO] agent: (LAN) joined: number_of_nodes=1 2020-04-01T00:00:49.233+0800 [INFO] agent: Join completed. Initial agents synced with: agent_count=1 2020-04-01T00:00:49.233+0800 [INFO] agent: started state syncer ==> Consul agent running! 2020-04-01T00:00:49.235+0800 [INFO] agent: Synced node info 2020-04-01T00:00:49.235+0800 [INFO] agent: Synced service: service=web 2020-04-01T00:00:53.316+0800 [INFO] agent: Synced check: check=service:web |
查看下,启动的Agent
1 2 3 4 |
$ ./consul members Node Address Status Type Build Protocol DC Segment server1 127.0.0.1:8301 alive server 1.7.2 2 dc1 <all> client1 127.0.0.1:8303 alive client 1.7.2 2 dc1 <default> |
web管理界面 可以查看服务的定义和节点,访问[web管理界面](http://127.0.0.1:8500/ui) HTTP API consul除了提供DNS外,还提供Http的操作,如注册服务、查看节点、查看服务信息等,一般都是通过API来操作的。 如我上面定义的 "web"服务,通过下面的API查询,就能得到具体的IP地址和端口,这样就能直接连到那台服务了。 其它更详情API操作,可以自已去参照官方的文档 API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
$ curl http://127.0.0.1:8500/v1/catalog/service/web [ { "ID": "e1c8f283-f5c4-27e7-c29c-64666df1c52b", "Node": "client1", "Address": "127.0.0.1", "Datacenter": "dc1", "TaggedAddresses": { "lan": "127.0.0.1", "lan_ipv4": "127.0.0.1", "wan": "127.0.0.1", "wan_ipv4": "127.0.0.1" }, "NodeMeta": { "consul-network-segment": "" }, "ServiceKind": "", "ServiceID": "web", "ServiceName": "web", "ServiceTags": [ "local" ], "ServiceAddress": "", "ServiceWeights": { "Passing": 1, "Warning": 1 }, "ServiceMeta": {}, "ServicePort": 80, "ServiceEnableTagOverride": false, "ServiceProxy": { "MeshGateway": {}, "Expose": {} }, "ServiceConnect": {}, "CreateIndex": 15, "ModifyIndex": 15 } ] |
from:https://zhuanlan.zhihu.com/p/122340918
View Details