首页 文章 精选 留言 我的

精选列表

搜索[鸿蒙实践],共10000篇文章
优秀的个人博客,低调大师

Redis实践(十五)-开发规范

1 key设计 看看这个 embstr 是啥,即内部编码 2 value 设计 value 设计 bigkey bigkey 的危害 网络阻塞 慢查询 节点数据不均衡 反序列消耗 发现 bigkey 应用方发现 redis-cli bigkeys scan + debug object 主动报警 内核统计 3 发现 bigkey 的方法 bigkey 发现 应用方发现 redis-cli bigkeys scan + debug object 主动报警 内核统计 4 bigkey 删除 bigkey 删除-Java bigkey 预防 总结 5 选择合适的数据结构 一个例子,三种方案 方案一 方案二 方案三 三种方案的内存对比 三种方案内存分析 三种方案优缺点对比 6 键值的生命周期的管理 7 命令使用技巧 8 Java客户端优化 9 连接池参数说明 如何预估最大连接池

优秀的个人博客,低调大师

Flutter React编程范式实践

作者:闲鱼技术-匠修Flutter Widget的设计灵感来源于React,是一款原生就立足于响应式的UI框架。本文基于Flutter特点,试图结合闲鱼在Flutter的工程应用来谈下我们对Flutter React编程范式的思考和践行。 Reactive的诞生 谈起UI总会讲到MVC,它出现的时间很早,那时候还没有普及现代GUI广泛使用的事件驱动(消息循环)模型,所以很长的时间内,MVC都在进化,不断的被重新定义。到现在MVC已经是一个很宽泛的概念了。使用基础的MVC作为框架来开发容易出现模块职责边界模糊,逻辑调用方向混乱。GUI框架进化后,将用户事件的分发处理集成到了View模块中,由此出现了MVP,MVP职责划分较清晰,逻辑调用方向也比较好把握,但是很繁琐,开发效率不高。再随着Web的发展,标记语言被应用于界面描述,开始出现逻辑

优秀的个人博客,低调大师

python svm pca实践二

继上一片的内容,这片来·讲一下sklearn来进行简单的人脸识别,这里用的方法是pca和svm 先导入必要的包和数据集 import numpy as np import matplotlib.pyplot as plt from scipy import stats from sklearn.decomposition import PCA from sklearn.svm import SVC from sklearn import datasets lfw_people = datasets.fetch_lfw_people(min_faces_per_person=70, \ resize=0.4) sklearn的人脸数据集包含5千多个不同人的人脸,但有些人的人脸只包含一张, n_samples, h, w = lfw_people.images.shape print('height and width of images:', h, w) # The images in X have been collapsed into a 1D array # just like for the handwritten digits X = lfw_people.data # X.shape[0] tells you the number of images (faces); # this is the same as n_samples ahove # X.shape[1] gives the number of pixels for each image # or, "features" print('X.shape', X.shape) n_features = X.shape[1] # the label/target to predict is the id of the person -- y is an integer y = lfw_people.target # target_names are actually names target_names = lfw_people.target_names print('target_names.shape', target_names.shape) print('target_names', target_names) # n_classes gives the number of people # Different from the number of faces (n_samples)!! n_classes = target_names.shape[0] print("Total dataset size:") print("n_samples (number of faces): {0}".format(n_samples)) # n_features = 1850, which is 50x37, the dimension of the images. print("n_features (number of pixels): {0}".format(n_features)) print("n_classes (number of people): {0}".format(n_classes)) 通过打印可以看到数据集人脸的尺寸为50x37,为7类共1288张人脸 pca = PCA(n_components=4,whiten = True) X_proj = pca.fit_transform(X[:500]) print("eigen vector",pca.components_) print("...") print('eigen value', pca.explained_variance_[:2]) print(np.var(X_proj[:,0])) print(np.var(X_proj[:,1])) 取500组数据将其降维为4个维度,并进行归一化处理 explained_variance_,它代表降维后的各主成分的方差值。方差值越大,则说明越是重要的主成分 from sklearn import svm def plot_faces(n_features): # nside = 1 X = lfw_people.data # fig, axes = plt.subplots(nside, nside, figsize=(8, 8)) plt.imshow(X[5].reshape(50,37)) plot_faces(n_features= 16) plt.show() 试着打一下其中的一幅图片 Xtrain = lfw_people.data[:1000] Xtest = lfw_people.data[1000:,] ytrain = lfw_people.target[:1000] ytest = lfw_people.target[1000:,] # Xtest = X[select_idx].reshape(1, -1) # test_img = X[select_idx] # ytest = y[select_idx] # n_comp = 50 pca = PCA(n_comp, whiten = True) pca.fit(Xtrain) # pca.fit(Xtest) Xtrain_proj = pca.transform(Xtrain) # projecting test data onto pca axes Xtest_proj = pca.transform(Xtest) print(Xtrain_proj.shape) print(Xtest_proj.shape) # ************************************* The SVM Section ******************************** # instantiating an SVM classifier clf = svm.SVC(gamma=0.001, C=100.) # apply SVM to training data and draw boundaries. clf.fit(Xtrain_proj, ytrain) # Use SVM-determined boundaries to make # a prediction for the test data point. ypred = clf.predict(Xtest_proj) correct = np.sum(ytest == ypred) print(correct/288*100) 接下来之前载入的数据用pca和svm进行训练识别,在1288个数据中取前1000组为训练集,后288个为测试集,pca将维为50维,并用训练集训练的模型对测试集进行预测,最后的测试精度为:81.25%,相对于现状流行的深度学习来说精度还是差了一点。

优秀的个人博客,低调大师

PouchContainer Goroutine Leak 检测实践

0. 引言 PouchContainer 是阿里巴巴集团开源的一款容器运行时产品,它具备强隔离和可移植性等特点,可用来帮助企业快速实现存量业务容器化,以及提高企业内部物理资源的利用率。 PouchContainer 同时还是一款 golang 项目。在此项目中,大量运用了 goroutine 来实现容器管理、镜像管理和日志管理等模块。goroutine 是 golang 在语言层面就支持的用户态 “线程”,这种原生支持并发的特性能够帮助开发者快速构建高并发的服务。 虽然 goroutine 容易完成并发或者并行的操作,但如果出现 channel 接收端长时间阻塞却无法唤醒的状态,那么将会出现 goroutine leak 。 goroutine leak 同内存泄漏一样可怕,这样的 goroutine 会不断地吞噬资源,导致系统运行变慢

优秀的个人博客,低调大师

python svm pca实践(一)

好久没写博客了 这里主要用python的sklearn包,来进行简单的svm的分类和pca的降维 svm是常用的分类器,其核心是在分类的时候找到一个最优的超平面,使得所有的样本与超平面之间的距离达到最小。 pca是常用的一种降维的方法,其核心是对去中心化后的数据,求得协方差矩阵,再对协方差矩阵进行特征分解,将最大的几个特征值作为这个样本的的新特征,达到降低数据特征维度的效果 这里用sklearn的digits数据集作为演示数据集 import numpy as np import matplotlib.pyplot as plt from scipy import stats # ***use seaborn plotting style defaults import seaborn as sns; sns.set() from sklearn import decomposition from sklearn.decomposition import PCA from sklearn.datasets import load_digits #********************* KEY IMPORT OF THIS LECTURE******************************** from sklearn import svm # loading handwritten digits dig_data = load_digits() X = dig_data.data # y: the values of the digits, or "ground truth" y = dig_data.target dig_img = dig_data.images print(type(X), X.dtype, X.shape) print(type(dig_img), dig_img.dtype, dig_img.shape) print(type(y), y.dtype, y.shape) 先导入所需要的包,并下载所需要的数据集 这里主要用到digits数据集中的.data,.target,.images属性 .data 为数据集的图像数据,用有1797个数据以一维的形式呈现,每个数据集的长度为64 .target为数据集的标签数据 .image位数据以8x8的形式呈现 dig_data = load_digits() X = dig_data.data y = dig_data.target # This is basically each array in X # getting reshaped into (8, 8). dig_img = dig_data.images print(type(X), X.dtype, X.shape) print(type(y), y.dtype, y.shape) select_idx = 2 # select_idx = 5 # ********************************Separating training data from testing data**************** Xtrain = np.delete(X, select_idx, axis = 0) ytrain = np.delete(y, select_idx) # if you don't do .reshape(1, -1), you get a warning. # B/c the data argument for classifier has to be an array, # even if it's a one-element array. Xtest = X[select_idx].reshape(1, -1) test_img = dig_img[select_idx] ytest = y[select_idx] print('Xtrain.shape, ytrain.shape', Xtrain.shape, ytrain.shape) print('Xtest.shape, ytest.shape', Xtest.shape, ytest.shape) plt.figure(figsize = (4, 4)) plt.imshow(test_img, cmap = 'binary') plt.grid('off') plt.axis('off') # ************************************* The PCA Section ******************************** n_comp = 10 pca = PCA(n_comp) # finding pca axes pca.fit(Xtrain) # projecting training data onto pca axes Xtrain_proj = pca.transform(Xtrain) # projecting test data onto pca axes Xtest_proj = pca.transform(Xtest) print(Xtrain_proj.shape) print(Xtest_proj.shape) # ************************************* The SVM Section ******************************** # instantiating an SVM classifier clf = svm.SVC(gamma=0.001, C=100.) # apply SVM to training data and draw boundaries. clf.fit(Xtrain_proj, ytrain) # Use SVM-determined boundaries to make # a prediction for the test data point. clf.predict(Xtest_proj) 将数据集分成训练集和测试集,将索引为2的数据从整个数据集中剔除作为测试数据集,剩下的数据作为训练数据集, n_comp为PCA降维后取得维数, 用训练集来训练PCA,再用训练集的模型来对训练集和测试集进行降维, 接着用训练集来训练SVM,并对测试集进行预测 def classify_dig_svm(X, y, dig_img, select_idx, n_comp, plot_test_img = False): dig_data = load_digits() X = dig_data.data y = dig_data.target dig_img = dig_data.images Xtrain = np.delete(X, select_idx, axis = 0) ytrain = np.delete(y, select_idx) Xtest = X[select_idx].reshape(1, -1) test_img = dig_img[select_idx] ytest = y[select_idx] if plot_test_img == True: plt.figure(figsize = (4, 4)) plt.imshow(test_img, cmap = 'binary') plt.grid('off') plt.axis('off') n_comp = 10 pca = PCA(n_comp) pca.fit(Xtrain) Xtrain_proj = pca.transform(Xtrain) # projecting test data onto pca axes Xtest_proj = pca.transform(Xtest) # print(Xtrain_proj.shape) # print(Xtest_proj.shape) # ************************************* The SVM Section ******************************** # instantiating an SVM classifier clf = svm.SVC(gamma=0.001, C=100.) # apply SVM to training data and draw boundaries. clf.fit(Xtrain_proj, ytrain) clf.predict(Xtest_proj) return clf.predict(Xtest_proj) X = dig_data.data y = dig_data.target n_comp = 30 # select_idx = # classify_dig_svm(X, y, dig_img, select_idx, n_comp, plot_test_img = False) counter = 0 tot = 1797 for i in range(tot): if classify_dig_svm(X, y, dig_img, i, n_comp, plot_test_img = False) == y[i]: counter += 1 rate = counter/tot print(rate) classify_dig_svm的方法是对每个数据进行测试看一下训练出来的pca模型和svm模型的准确性 其实效果还好

优秀的个人博客,低调大师

Docker技术实践——初级篇

这是一篇关于Docker技术的初级文档,主要针对Docker的babies。当然,如果是老鸟也欢迎温故知新。 2. Docker组件(C/S) Docker组件分为客户端和服务端。 Docker Client:Docker的客户端 Docker Server: Docker daemon的主要组成部分,接收用户通过Docker Client发送的请求,按照相应的路由规则实现路由分发。 Docker Registry:是Docker镜像的中央存储仓库 Docker镜像运行之后变成容器。 3. 关于Docker实战 Docker需要使用Linux内核中的CGroups和Namespace功能,必须包含这两项功能,内核版本必须高于3.10. 3.1 安装docker 安装docker,安装docker和docker.io,使用命令 apt-get install docer apt-get install docker.io 启动docker Daemon命令为: #service docker start或者systemctl start docker 查看Docker版本 #docker version 运行测试(因为需要下载hello-world镜像,会自动去外网下载): #docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ 或者使用网上的镜像进行测试 我们使用码云上的一个开源项目 先克隆项目命令如下: # git clone 然后编译镜像: # docker build -t cyphere/centos:7.1 . Sending build context to Docker daemon 8.704 kB Step 1 : FROM centos:centos7.1.1503 ---> c288e5945774 Step 2 : MAINTAINER Carson,C.J.Zeong <zcy@nicescale.com> ---> Using cache ---> ec1a67832870 Step 3 : ENV TZ "Asia/Shanghai" ---> Using cache ---> 577afeadeac1 Step 4 : ENV TERM xterm ---> Using cache ---> c6cb24e09d77 Step 5 : ADD aliyun-mirror.repo /etc/yum.repos.d/CentOS-Base.repo ---> Using cache ---> 25fef5ca6f0b Step 6 : ADD aliyun-epel.repo /etc/yum.repos.d/epel.repo ---> Using cache ---> 983dd35ebe92 Step 7 : RUN yum install -y curl wget tar bzip2 unzip vim-enhanced passwdsudo yum-utils hostname net-tools rsync man && yum install -y gcc gcc-c++ git make automakecmake patch logrotate python-devel libpng-devel libjpeg-devel && yum install -y --enablerepo=epel pwgenpython-pip && yum clean all ---> Using cache ---> 8d4ad2dbd92f Step 8 : RUN pip install supervisor ---> Using cache ---> a112b76647f4 Step 9 : ADD supervisord.conf /etc/supervisord.conf ---> Using cache ---> 0fd05419af62 Step 10 : RUN mkdir -p /etc/supervisor.conf.d && mkdir -p /var/log/supervisor ---> Using cache ---> 14d11d019067 Step 11 : EXPOSE 22 ---> Using cache ---> 464f20e0f9b8 Step 12 : ENTRYPOINT /usr/bin/supervisord -n -c /etc/supervisord.conf ---> Using cache ---> d31702307c6b Successfully built d31702307c6b 3.2 Docker常用命令 查看镜像命令使用: docker images 查看docker进程: docker ps 查看容器日志 docker logs -f <容器名orID> 删除所有容器,不可以删除一个运行中的容器,此时必须先用docker stop或docker kill命令停止它才能删除。 docker rm $(docker ps -a -q) 删除之后去查看docker ps –a发现都不存在了。 删除单个容器 docker rm <容器名orID> 停止、启动、杀死一个容器 docker stop <容器名orID> docker start <容器名orID> (如果全部删掉后,那先如要执行docker run <images id>来启动) docker kill <容器名orID> 拉取镜像 docker pull <镜像名:tag> 删除所有镜像(慎重不要被好不容易下载的给删除了) docker rmi $(docker images | grep none | awk '{print $3}' | sort -r) 构建自己的镜像 docker build -t <镜像名> <Dockerfile路径> 如Dockerfile在当前路径: docker build -t xx/gitlab . 保存镜像: 当需要把一台机器上的镜像迁移到另一台机器的时候,需要保存镜像与加载镜像。 docker save busybox-1 > /home/save.tar 使用scp将save.tar拷到其他机器上,然后: docker load < /home/save.tar 从容器中拷贝文件出来 docker cp 7bb0e258aefe:/etc/debian_version . 把容器转换成镜像 docker commit 调查容器详细信息,诊断问题信息常用 docker inspect 1.1.1 容器内执行命令 #docker exec -it <container id> /bin/bash 进入交互模式 1.1.2ÂÂÂ Docker run参数 上面中的docker命令包括了三部分:docker,run,hello-world。 其中docker表示客户端程序, run表示子命令。 hello-world表示镜像名称。 说白了,docker run 组合在一起代表运行一个新docker容器。 我们继续运行一个ubuntu镜像: #docker pull Ubuntu 然后运行一个含shell终端的容器: #docker run -i -t ubuntu /bin/bash 直接进入到docker容器镜像了。 复杂一点的例如如下 运行一个新容器,同时为它命名、端口映射、文件夹映射。 docker run --name redmine -p 9003:80 -p 9023:22 -d -v /var/redmine/files:/redmine/files -v /var/redmine/mysql:/var/lib/mysql sameersbn/redmine 一个容器连接到另一个容器 docker run -i -t --name sonar -d -link mmysql:db tpires/sonar-server sonar 此外还可有有其他参数,例如-v参数。 在Docker run中-v参数表示映射本地文件到容器中。在数据库相关的容器中很有用,其他需要保存数据文件的场景也可以使用。 语法如下: -vhost_dir:container_dir --rm参数表示容器 --entrypoint可以覆盖掉原先的ENTRYPOINT参数,--entrypoint=/bin/bash 1.1.3 Docker create命令 通过create命令将镜像生成容器,但是不运行。 4. Docker的镜像和容器 容器和镜像是Docker的核心部分,Docker实际就是在容器里面运行一个镜像。 一个Docker镜像可以构建于另一个Docker镜像之上,这种层叠关系可以是多层的。第1层的镜像层我们称之为基础镜像(Base Image),其他层的镜像(除了最顶层)称之为父层镜像(Parent Image)。这些镜像继承了他们的父层镜像的所有属性和设置,并在Dockerfile中添加了自己的配置。 Docker镜像通过镜像ID进行识别。镜像ID是一个64字符的十六进制的字符串。但是当我们运行镜像时,通常我们不会使用镜像ID来引用镜像,而是使用镜像名来引用。 镜像可以发布为不同的版本,这种机制我们称之为标签(Tag)。 Docker容器可以使用命令创建: # docker run imagename 会在所有的镜像层之上增加一个可写层。这个可写层运行在CPU上的进程,有两个不同的状态:运行态(Running)和退出态(Exited)。这就是Docker容器。 当我们使用docker run启动容器,Docker容器就进入运行态,当我们停止Docker容器时,它就进入退出态。 可以用同一个镜像启动多个Docker容器,这些容器启动后都是活动的,彼此相互隔离的。对其中一个容器所做的变更只会局限于那个容器本身。 如果对容器的底层镜像进行修改,当前正在运行的容器是不受影响的,不会发生自动更新现象。 如果想更新容器到其镜像的新版本,那么必须当心,确保我们是以正确的方式构建了数据结构,否则可能会导致损失容器中所有数据的后果。 64字符的十六进制的字符串来定义容器ID,是容器的唯一标识符。容器之间的交互是依靠容器ID识别的,由于容器ID的字符太长,我们通常只需键入容器ID的前4个字符即可。当然,我们还可以使用容器名,但显然用4字符的容器ID更为简便。 4.1 Dockfile dockerfile由4部分信息组成:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。 Dockfile是创建Docker的文件,可以理解成makefile。 VOLUME 映射本地文件给虚拟机, CMD参数: container启动时执行的命令,一个Dockerfile中只能有一条CMD命令,多条则只执行最后一条CMD.CMD主要用于container时启动指定的服务,当docker run command的命令匹配到CMD command时,会替换CMD执行的命令。 ENTRYPOINT 容器入口进程,最后一个生效。container启动时执行的命令,但是一个Dockerfile中只能有一条ENTRYPOINT命令,如果多条,则只执行最后一条,ENTRYPOINT没有CMD的可替换特性。 ADD,将文件<src>拷贝到container的文件系统对应的路径<dest> 所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0,如果文件是可识别的压缩格式,则docker会帮忙解压缩。如果要ADD本地文件,则本地文件必须在 docker build <PATH>,指定的<PATH>目录下。 和Dockerfile同目录的.dockerignore文件可以记录文件名字用于忽略,即忽略文件中哪个文件。 ONBUILD命令在未做其他基线的时候引用触发,ONBUILD指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。 编译生成镜像,命令如下: docker build -t csphere/centos:7.1 . 其中-t参数指定镜像名称和tag 不过如果依赖基础镜像的话,下载速度很可能超时。 4.2 语法 FROM是基础镜像 MAINTAINER 作者 ENV 环境变量 RUN 是安装哪些服务 ADD EXPOSE ONBUILD ADD ONBUILD RUN 4.3 第三方镜像 可以到docker镜像市场 此处下载一个tomcat镜像。 拉取镜像,命令如下: docker pull daocloud.io/library/tomcat:7.0-jre7-alpine 当然可以拉最新的可以使用: docker pull daocloud.io/library/tomcat:latest 拉取完毕后可以使用 docker images来查看。 启动镜像容器: # docker run -it -p 8080:8080 daocloud.io/library/tomcat 也可以使用其他国内的镜像市场。 其中-p是指定主机和容器的端口映射。 4.1 容器的网络 可以使用如下命令进行查看: #docker network ls 查看网络详情 #docker network inspect bridge 创建新的桥接网络 #docker network create –driver bridge mynet 4.2 容器的数据 容器的文件系统由分层文件系统提供,包含只读层(镜像)和可读写层(容器运行时)。如果要将主机上文件系统共享给容器使用,可以使用数据卷或者数据容器。 数据卷是将主机的卷mount进入到容器,数据容器是将外部容器分享给容器。使用参数-v。例如: #docker run -d -v /webapp xxx #docker run -d -v /root:/hostroot xxx 第二个命令是将/root目录映射到了容器中的/hostroot中。第一个命令创建一个数据卷。 因为容器本身可以包含文件系统,可以把容器的卷分享给另一个容器。可以先创建一个包含外部卷的容器,然后使用--volumes-from来指定该数据容器。 需要注意的是,数据卷在容器创建时进行初始化,数据卷可以共享也可以容器间重用,其读写是直接下发的。 5. 关于Docker 仓库 镜像的公共仓库是Docker Hub,在海外,国内的需要墙出去才可以。当然可以在公司内部建立私有仓库,或者在网上建立公共的私有仓库。主要命令就是:search,pull,login,push。 例如查找mysql镜像,执行: #docker search mysql 6. 参考 Docker教程官方

优秀的个人博客,低调大师

Docker技术实践——高级篇

1.1 搭建私有仓库 我们需要看下如何搭建容器的私有仓库: Mavan的管理一样,Dockers不仅提供了一个中央仓库,同时也允许我们使用registry搭建本地私有仓库。 私有仓库有许多优点: 1.节省网络带宽,不用每个人都去中央仓库上面去下载,只需要从私有仓库中下载即可; 2.提供镜像资源利用,针对于公司内部使用的镜像,推送到本地的私有仓库中,以供公司内部相关人员使用。 #docker pull registry #dockerrun -d -p 5000:5000 --name registry-srv registry 默认仓库存放于容器内的/tmp/registry目录下 镜像需要通过docker tag进行修改,符合仓库需要。 #docker push 192.168.1.104:5000/hello-world 如果出现如下错误: http: server gave HTTP response to HTTPS client 这是因为docker registry交互默认使用的是https,然而此处搭建的私有仓库只提供http服务,所以当与私有仓库交互时就会报上面的错误。 MAC机器中修改: 在Docker的preference中,点击Daemon,Basic页签中,在Insecureregistries中增加一行: http://192.168.1.104:5000 点击apply and restart重启docker即可。 Ubuntu机器中修改: (Ubuntu的地址为/etc/init/docker.conf),在其中增加 --insecure-registry 192.168.1.104:5000 exec"$DOCKERD"$DOCKER_OPTS--raw-logs --insecure-registry 192.168.1.104:5000 然后重启 docker; #service docker restart; 如果上述方法不行,那么如下: 在”/etc/docker/“目录下,创建”daemon.json“文件。在文件中写入: { "insecure-registries":["192.168.1.104:5000"]} 然后重启 docker; #service docker restart; 1.2 上传镜像 # docker push registry:5000/image_name 1.3 查看镜像 # curl -XGET http://registry:5000/v2/_catalog # curl -XGEThttp://registry:5000/v2/image_name/tags/list 例如: #curl -XGEThttp://192.168.1.104:5000/v2/_catalog 输出如下: {"repositories":["centos","hello-world"]} # curl -XGEThttp://192.168.1.104:5000/v2/centos/tags/list 输出如下: {"name":"centos","tags":["7.1"]} 1.4 Docker-compose Docker-compose需要docker-compose.yml文件,依赖yml文件,没有yml文件就没有勇武之地了。 Docker Compose是一个用来定义和运行复杂应用的Docker工具。使用Compose,你可以在一个文件中定义一个多容器应用,然后使用一条命令来启动你的应用,完成一切准备工作。 编辑docker-compose.yml内容如下: mysql: image: csphere/mysql:5.5 ports: - "3306:3306" wordpress: image: csphere/wordpress:10 ports: -"80:80" 启动容器如下: docker-composeup-d 关闭容器: docker-compose stop 2. Q&A 2.1 编译错误 Rpmdb checksum is invalid: dCDPT(pkgchecksums): elfutils-libs.x86_64 0:0.168-8.el7 - u 答:在 Docker 文件中第一个 yum 之前加入如下命令对rpmdb 进行构筑. RUN rpm --rebuilddb&& \

优秀的个人博客,低调大师

Docker技术实践——中级篇

1.1 存储机制 每个镜像由多个镜像层组成,镜像层都是只读的,从下往上,以栈方式组合在一起,组成容器的根文件系统。镜像文件默认保存在主机的/var/lib/docker/volumes中。 容器层是可读写层。每个容器运行时都有自己的容器层,保存容器运行相关的数据,容器层之下的所有镜像都是只读的,多个容器可以共享一个镜像。容器层是保存在/var/lib/docker/containers路径。每次新建容器时,只需要为每个容器新建一个可写的数据层,而不用复制所有的镜像层。 容器层和镜像层都保存在宿主机的文件系统中,通过Docker存储驱动来管理。 1.2 数据卷和存储驱动 容器使用数据卷保证数据持久性,删除容器时候,所有不在数据卷中的数据都会被删除。因为数据卷是主机上的一个文件或者目录,不受存储驱动程序管理。 Docker设计了一套存储驱动插件框架,开发者可以基于此套标准,设计开发自己的存储驱动。 可以使用docker info查看当前存储驱动。 使用哪种存储驱动取决于用户在宿主机上使用何种文件系统。有些存储驱动可以工作在不同的后端文件系统上。 可以在启动Docker使用使用--storage-driver来指定。 Docker中每种存储驱动都是基于Linux文件系统或卷管理工具的。 1.3 定制Docker Daemon 因为Docker Daemon有七八十个启动选项,根据应用场景定制Docker运行环境就显得非常有必要。 在命令行中输入dockerd即可启动,就是默认的方式启动Daemon了。 如果开启debug模式,可以执行 #dockerd -D 仓库相关配置: --disable-legacy-registry选项,可以选择不从旧版本的镜像仓库中下载镜像。因为Docker从1.6版本后,支持从V2版本的镜像仓库下载镜像。 使用镜像仓库,使用参数—registry-mirror选项。 此外,还有何网络配置相关的等等。 因为,旧版本docker的配置文件默认的在 /etc/default/docker ,现在已不推荐。 变量的使用查看/lib/systemd/system/docker.service 可以参考官方指南:

优秀的个人博客,低调大师

Laravel实践---middleware生效机制

以前的是5.1版本写的。 现在改成5.6版本。 其中遇到的问题,我会在这个laravel专题中一一指出。 第一个问题是路由时 Route::controller不再支持。 于是,我只好弄成Route:get之类的语法来解决。 第二个问题是中间件如何生效。 写middleware时,不能直接返回view了。。要用response. return response()->view('user'); 然后,将这个中间件,弄进kernel.php里面。 protected $routeMiddleware = [ 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'middleware.xxx' => \App\Http\Middleware\XXXMiddleware::class, ]; 最后,不管是在controller的__construct里,还是在routers/web.php里,加入中间件缩写。 Route::get('/xxx','xxxController@getIndex')->middleware('middleware.xxx')->name('user.xxx'); public function __construct(){ $this->middleware('middleware.xxx'); }

优秀的个人博客,低调大师

Android Flutter实践--安装(Windows)

Flutter官网 Flutter中文网 Flutter社区中文资源 1. 下载源码 git clone -b beta https://github.com/flutter/flutter.git 图1.png 2. 配置环境变量 I. 命令配置 export PUB_HOSTED_URL=https://pub.flutter-io.cn //国内用户需要设置 export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //国内用户需要设置 // 配置环境变量 export PATH=`pwd`/flutter/bin:$PATH II. 右键我的电脑->属性->高级系统设置->环境变量->用户变量 在“用户变量”下检查是否有名为“Path”的条目: 如果该条目存在, 追加 D:\Program\flutter\bin(此处路径为自己本地存储地址+\flutter\bin)的全路径,使用 ; 作为分隔符. 如果条目不存在, 创建一个新用户变量 Path ,然后将 flutter\bin的全路径作为它的值. 在“用户变量”下检查是否有名为”PUB_HOSTED_URL”和”FLUTTER_STORAGE_BASE_URL”的条目,如果没有,也添加它们。 图2.png 图3.png 3. 运行flutter doctor 打开命令提示符,运行命令: flutter doctor 用于下载Dart SDK和更新Flutter Tool. 图4.png 4. 打开 Android Studio 安装插件: Flutter插件: 支持Flutter开发工作流 (运行、调试、热重载等). Dart插件: 提供代码分析 (输入代码时进行验证、代码补全等). File->Settings->Plugins->Browse Repositories, 输入Flutter,点击Install(安装).由于Flutter插件依赖于Dart插件,因此在下载Flutter时会同时下载Dart插件 图6.png 3). 重启. 5. 创建项目 1). New Flutter Project 图7.png 2). 选择 Flutter application 作为 project 类型, 然后点击 Next 图8.png 3). 配置工程名 图9.png 图10.png 4). 工程目录 图11.png android: Android 工程 ios: ios工程 lib: dart文件所在文件夹 test: 测试文件 5). 运行 图12.png 6). 热重载 在lib/main.dart文件中修改文字: 将You have pushed the button this many times修改You have clicked the button this many times,并点击保存。(调用 Save All (cmd-s / ctrl-s), 或点击 热重载按钮 (带有闪电️图标的按钮).)

优秀的个人博客,低调大师

CUDA实践指南(三十四)

可修改的状态:ECC模式启用和禁用ECC报告。ECC重置清除单位和双位ECC错误计数。 计算模式指示计算进程是否可以在GPU上运行,以及它们是否运行完全或同时与其他计算过程。持久性模式指示当没有应用程序连接到GPU时,NVIDIA驱动程序是否保持加载状态。 在大多数情况下最好启用此选项。GPU重置通过辅助总线重置重新初始化GPU硬件和软件状态。 NVML:NVIDIA管理库(NVML)是一个基于C的界面,可以直接访问通过nvidia-smi公开的查询和命令,作为构建第三方系统管理应用程序的平台。 NVML API可通过NVIDIA开发人员网站作为Tesla Deployment Kit的一部分通过单个头文件提供,并附有PDF文档,存根库和示例应用程序; 请参阅http://developer.nvidia.com/tesla-deployment-kit。 每个新版本的NVML都是向后兼容的。为NVML API提供了一组额外的Perl和Python绑定。 这些绑定公开了与基于C的接口相同的功能,并提供向后兼容性。 Perl绑定通过CPAN提供,并通过PyPI提供Python绑定。所有这些产品(nvidia-smi,NVML和NVML语言绑定)都随每个新的CUDA版本而更新,并提供大致相同的功能。 有关更多信息,请参见http://developer.nvidia.com/nvidia-management-library-nvml。群集管理工具:管理您的GPU集群将有助于实现最大的GPU利用率,并帮助您和您的用户获得最佳性能。 许多业界最受欢迎的集群管理工具现在都通过NVML支持CUDA GPU。 有关这些工具的列表,请参阅http://developer.nvidia.com/cluster-management。编译器JIT高速缓存管理工具:应用程序在运行时加载的任何PTX设备代码都将由设备驱动程序进一步编译为二进制代码。 这就是所谓的即时编译(JIT)。 即时编译增加了应用程序加载时间,但允许应用程序从最新的编译器改进中受益。 它也是应用程序在编译应用程序时不存在的设备上运行的唯一方式。当使用PTX设备代码的JIT编译时,NVIDIA驱动程序将产生的二进制代码缓存在磁盘上。 此行为的某些方面(如缓存位置和最大缓存大小)可以通过使用环境变量进行控制; 请参阅CUDA C编程指南的即时编译。CUDA_VISIBLE_DEVICES:通过CUDA_VISIBLE_DEVICES环境变量,可以重新排列安装的CUDA设备的集合,这些设备将在CUDA应用程序启动之前被CUDA应用程序显示并枚举。对于应用程序可见的设备应该按照可枚举设备的系统范围列表包含在逗号分隔列表中。 例如,要仅使用来自系统范围设备列表的设备0和2,请在启动应用程序之前设置CUDA_VISIBLE_DEVICES = 0,2。 然后,应用程序将分别将这些设备列为设备0和设备1

优秀的个人博客,低调大师

jackson-databind最佳实践

给出一个简单的POJO 使用databind,我们需要一个最基础的对象com.fasterxml.jackson.databind.ObjectMapper这里我们构造一个: 注意:这个objectMapper是可以复用的 ObjectMapper 该映射器(或数据绑定器或编解码器)为Java对象之间和匹配的JSON结构的转换提供功能 属性(为序列化过程定义基本的全局设置的配置对象) _serializationConfig _deserializationConfig image.png Inclusion 需要的传参 用于定义Java Bean的哪些属性将被包含在序列化中的枚举 ALWAYS 指示属性始终被包含 独立于值 NON_NULL 该值指示仅包含具有非空值的属性 NON_DEFAULT 只包含没有默认值的属性(意味着当它使用无参数构造函数构造Bean时的值) Map通常无用,因为它们没有默认值,如果使用,则与ALWAYS NON_EMPTY 属性值为null或被认为是空的属性不包括在内 Feature 定义了可引导序列化功能的可触发功能的枚举 WRITE_DATES_AS_TIMESTAMPS(true) 确定Date以及基于日期的东西如Calendar是否要序列化为时间戳 FAIL_ON_EMPTY_BEANS(true) 确定在找到某个类型没有访问者时会发生什么的功能 如果启用(默认),则抛出异常以将它们指示为不可序列化的类型 如果禁用,则它们被序列化为空的对象,即没有任何属性。 简单的把JSON反序列化成Object的用法如下: 简单的把Object序列化成JSON的用法如下: 其实到这一步,对于很多读者来说已经足够了。因为大部分时候我们要的就是这些。但是不妨继续看下去,还有一些你可能会用到的。 集合 如果你使用的不是简单的POJO,而是List,Map: 思考:为什么需要指定类型?(类型擦除) 注意:序列化的时候不需要指定,只有反序列化的时候需要。

优秀的个人博客,低调大师

redis从入门到实践

一. Redis安装使用 1.介绍 redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多, 包括string(字符串)、list(链表)、set(集合)、zset(sorted set--有序集合)和hash(哈希类型)。 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且 这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样, 为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘 或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。 2.安装redis 1.下载官网最新redis安装包 http://download.redis.io/releases/redis-4.0.0.tar.gz 2.在/usr/local下创建文件redis cd /usr/local mkdir redis 3.将下载的redis-4.0.2.tar.gz安装包解压到redis文件夹中 cd ~ tar -zxvf redis-4.0.2.tar.gz -C /usr/local/redis 4.进入解压后的目录进行编译 cd /usr/local/redis/redis-4.0.2 make 5.安装到指定目录,如 /usr/local/redis cd /usr/local/redis/redis-4.0.2 make PREFIX=/usr/local/redis install 6.拷贝配置文件redis.conf到安装目录下 cp /usr/local/redis/redis-4.0.2/redis.conf /usr/local/redis/bin 7.修改redis.conf配置文件,这里使用默认端口6379,有需要的可以更改。 把daemonize改为yes(这里推荐以后端模式启动) vi /usr/local/redis/bin/redis.conf ----------------------------------- 以后端模式启动redis cd /usr/local/redis ./bin/redis-server ./bin/redis.conf 8.测试redis cd /usr/local/redis ./bin/redis-cli set name zhangsan get name 9.Linux开启关闭redis 1.启动:./redis-server(redis-server redis.conf) 2.登陆:./redis-cli(redis-cli -p 6379) 3.关闭:./redis-cli shutdown 10.Linux 为redis配置密码 1.第一种方式(临时密码,Linux重启后会消失) (1) [root@localhost bin]# redis-cli -p 6379 127.0.0.1:6379> (2)查看当前redis有没有设置密码: 127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "" (3)为以上显示说明没有密码,那么现在来设置密码: 127.0.0.1:6379> config set requirepass abcdefg OK 127.0.0.1:6379> (4)再次查看当前redis就提示需要密码: 127.0.0.1:6379> config get requirepass (error) NOAUTH Authentication required. 127.0.0.1:6379> 2.第二种方式 (永久方式) 需要永久配置密码的话就去redis.conf的配置文件中找到requirepass这个参数,如下配置: 修改redis.conf配置文件 # requirepass foobared requirepass 123 指定密码123 保存后重启redis就可以了 11.Jedis连接redis java 代码方式 //连接redis服务器,192.168.0.100:6379 jedis = new Jedis("ip", 6379); //权限认证 jedis.auth("password"); 配置文件方式 <bean id=”jedisConnectionFactory” class=”org.springframework.data.redis.connection.jedis.JedisConnectionFactory”> <property name=”hostName” value=”${redis.host}” /> <property name=”port” value=”${redis.port}” /> <property name=”password” value=”${redis.pass}” /> </bean> redis的其他命令 如果需要关闭redis: [root@localhost bin]# pkill redis 如果需要开启redis: [root@localhost bin]# redis-server & 加&符号的作用是为了让此进程转换为后台进程,不占用shell的服务。 注意事项 1.提示time out错误 需要在iptables防火墙上添加6379端口并重启防火墙服务 2.提示connection refuse错误 需要注释掉redis.conf 文件中的bind 127.0.0.1 3.提示J edisDataException错误 需要将redis.conf文件中的protect-mode 置为no最后重启redis 应用场景 1.缓存 2.聊天室,秒杀,任务队列(list结构,pop(弹出),push(插入)) 3.数据存储(add,del,update,select)定期持久化到硬盘中 4.网站统计 5.数据过期处理 6.分布式集群架构中的session分离 主要内容 NoSQL(非关系型数据库) redis:key/value键值dui存储数据库 mongodb:文档型数据库 hbase:列式数据库 neo4j:图式数据库,存储的是图关系而非行或列。主要用于社交网络的存储 redis数据结构:String Hash Set SortedSet List redis事务:multi exec discard redis持久化:rbd内存快照,aof命令日志 二.Redis快速入门 1.redis 配置说明 1\. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 2\. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定 pidfile /var/run/redis.pid 3\. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字 port 6379 4\. 绑定的主机地址 bind 127.0.0.1 5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能 timeout 300 6\. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose loglevel verbose 7\. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null logfile stdout 8\. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id databases 16 9\. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 save <seconds> <changes> Redis默认配置文件中提供了三个条件: save 900 1 save 300 10 save 60 10000 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。 10\. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大 rdbcompression yes 11\. 指定本地数据库文件名,默认值为dump.rdb dbfilename dump.rdb 12\. 指定本地数据库存放目录 dir ./ 13\. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步 slaveof <masterip> <masterport> 14\. 当master服务设置了密码保护时,slav服务连接master的密码 masterauth <master-password> 15\. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭 requirepass foobared 16\. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息 maxclients 128 17\. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区 maxmemory <bytes> 18\. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no appendonly no 19\. 指定更新日志文件名,默认为appendonly.aof appendfilename appendonly.aof 20\. 指定更新日志条件,共有3个可选值: no:表示等操作系统进行数据缓存同步到磁盘(快) always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) everysec:表示每秒同步一次(折衷,默认值) appendfsync everysec 21\. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制) vm-enabled no 22\. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享 vm-swap-file /tmp/redis.swap 23\. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0 vm-max-memory 0 24\. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值 vm-page-size 32 25\. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。 vm-pages 134217728 26\. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4 vm-max-threads 4 27\. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 glueoutputbuf yes 28\. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 hash-max-zipmap-entries 64 hash-max-zipmap-value 512 29\. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍) activerehashing yes 30\. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 include /path/to/local.conf Redis 键(key) Redis 键命令用于管理 redis 的键。 语法 Redis 键命令的基本语法如下: redis 127.0.0.1:6379> COMMAND KEY_NAME 实例 redis 127.0.0.1:6379> SET runoobkey redis OK redis 127.0.0.1:6379> DEL runoobkey (integer) 1 在以上实例中 DEL 是一个命令, runoobkey 是一个键。 如果键被删除成功,命令执行后输出 (integer) 1,否则将输出 (integer) 0 Redis keys 命令 下表给出了与 Redis 键相关的基本命令: 1 DEL key 该命令用于在 key 存在时删除 key。 2 DUMP key 序列化给定 key ,并返回被序列化的值。 3 EXISTS key 检查给定 key 是否存在。 4 EXPIRE key seconds 为给定 key 设置过期时间。 5 EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 6 PEXPIRE key milliseconds 设置 key 的过期时间以毫秒计。 7 PEXPIREAT key milliseconds-timestamp 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计 8 KEYS pattern 查找所有符合给定模式( pattern)的 key 。 9 MOVE key db 将当前数据库的 key 移动到给定的数据库 db 当中。 10 PERSIST key 移除 key 的过期时间,key 将持久保持。 11 PTTL key 以毫秒为单位返回 key 的剩余的过期时间。 12 TTL key 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 13 RANDOMKEY 从当前数据库中随机返回一个 key 。 14 RENAME key newkey 修改 key 的名称 15 RENAMENX key newkey 仅当 newkey 不存在时,将 key 改名为 newkey 。 16 TYPE key 返回 key 所储存的值的类型 Redis 数据类型 Redis支持五种数据类型: string(字符串), hash(哈希), list(列表), set(集合) zset(sorted set:有序集合)。 String(字符串) string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。 string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。 string类型是Redis最基本的数据类型,一个键最大能存储512MB。 实例 redis 127.0.0.1:6379> SET name "runoob" OK redis 127.0.0.1:6379> GET name "runoob" 在以上实例中我们使用了 Redis 的 SET 和 GET 命令。键为 name,对应的值为 runoob。 注意:一个键最大能存储512MB。 Redis 字符串命令 1 SET key value 设置指定 key 的值 2 GET key 获取指定 key 的值。 3 GETRANGE key start end 返回 key 中字符串值的子字符 4 GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 5 GETBIT key offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。 6 MGET key1 [key2..] 获取所有(一个或多个)给定 key 的值。 7 SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 8 SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。 9 SETNX key value 只有在 key 不存在时设置 key 的值。 10 SETRANGE key offset value 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。 11 STRLEN key 返回 key 所储存的字符串值的长度。 12 MSET key value [key value ...] 同时设置一个或多个 key-value 对。 13 MSETNX key value [key value ...] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。 14 PSETEX key milliseconds value 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。 15 INCR key 将 key 中储存的数字值增一。 16 INCRBY key increment 将 key 所储存的值加上给定的增量值(increment) 。 17 INCRBYFLOAT key increment 将 key 所储存的值加上给定的浮点增量值(increment) 。 18 DECR key 将 key 中储存的数字值减一。 19 DECRBY key decrement key 所储存的值减去给定的减量值(decrement) 。 20 APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。 Hash(哈希) Redis hash 是一个键值(key=>value)对集合。 Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 实例 redis> HMSET myhash field1 "Hello" field2 "World" "OK" redis> HGET myhash field1 "Hello" redis> HGET myhash field2 "World" 以上实例中 hash 数据类型存储了包含用户脚本信息的用户对象。 实例中我们使用了 Redis HMSET, HGETALL 命令,user:1 为键值。 每个 hash 可以存储 232 -1 键值对(40多亿)。 Redis hash 命令 1 HDEL key field1 [field2] 删除一个或多个哈希表字段 2 HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。 3 HGET key field 获取存储在哈希表中指定字段的值。 4 HGETALL key 获取在哈希表中指定 key 的所有字段和值 5 HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。 6 HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。 7 HKEYS key 获取所有哈希表中的字段 8 HLEN key 获取哈希表中字段的数量 9 HMGET key field1 [field2] 获取所有给定字段的值 10 HMSET key field1 value1 [field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。 11 HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。 12 HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。 13 HVALS key 获取哈希表中所有值 14 HSCAN key cursor [MATCH pattern] [COUNT count] 迭代哈希表中的键值对。 List(列表) Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 实例 redis 127.0.0.1:6379> lpush runoob redis (integer) 1 redis 127.0.0.1:6379> lpush runoob mongodb (integer) 2 redis 127.0.0.1:6379> lpush runoob rabitmq (integer) 3 redis 127.0.0.1:6379> lrange runoob 0 10 1) "rabitmq" 2) "mongodb" 3) "redis" redis 127.0.0.1:6379> 列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。 Redis 列表命令 1 BLPOP key1 [key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 2 BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 3 BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 4 LINDEX key index 通过索引获取列表中的元素 5 LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者后插入元素 6 LLEN key 获取列表长度 7 LPOP key 移出并获取列表的第一个元素 8 LPUSH key value1 [value2] 将一个或多个值插入到列表头部 9 LPUSHX key value 将一个值插入到已存在的列表头部 10 LRANGE key start stop 获取列表指定范围内的元素 11 LREM key count value 移除列表元素 12 LSET key index value 通过索引设置列表元素的值 13 LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 14 RPOP key 移除并获取列表最后一个元素 15 RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 16 RPUSH key value1 [value2] 在列表中添加一个或多个值 17 RPUSHX key value 为已存在的列表添加值 Set(集合) Redis的Set是string类型的无序集合。 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 sadd 命令 添加一个string元素到,key对应的set集合中,成功返回1,如果元素已经在集合中返回0,key对应的set不存在返回错误。 sadd key member 实例 redis 127.0.0.1:6379> sadd runoob redis (integer) 1 redis 127.0.0.1:6379> sadd runoob mongodb (integer) 1 redis 127.0.0.1:6379> sadd runoob rabitmq (integer) 1 redis 127.0.0.1:6379> sadd runoob rabitmq (integer) 0 redis 127.0.0.1:6379> smembers runoob 1) "rabitmq" 2) "mongodb" 3) "redis" 注意:以上实例中 rabitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。 集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。 Redis 集合命令 1 SADD key member1 [member2] 向集合添加一个或多个成员 2 SCARD key 获取集合的成员数 3 SDIFF key1 [key2] 返回给定所有集合的差集 4 SDIFFSTORE destination key1 [key2] 返回给定所有集合的差集并存储在 destination 中 5 SINTER key1 [key2] 返回给定所有集合的交集 6 SINTERSTORE destination key1 [key2] 返回给定所有集合的交集并存储在 destination 中 7 SISMEMBER key member 判断 member 元素是否是集合 key 的成员 8 SMEMBERS key 返回集合中的所有成员 9 SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合 10 SPOP key 移除并返回集合中的一个随机元素 11 SRANDMEMBER key [count] 返回集合中一个或多个随机数 12 SREM key member1 [member2] 移除集合中一个或多个成员 13 SUNION key1 [key2] 返回所有给定集合的并集 14 SUNIONSTORE destination key1 [key2] 所有给定集合的并集存储在 destination 集合中 15 SSCAN key cursor [MATCH pattern] [COUNT count] 迭代集合中的元素 zset(sorted set:有序集合) Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。 zset的成员是唯一的,但分数(score)却可以重复。 zadd 命令 添加元素到集合,元素在集合中存在则更新对应score zadd key score member 实例 redis 127.0.0.1:6379> zadd runoob 0 redis (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 mongodb (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 rabitmq (integer) 1 redis 127.0.0.1:6379> zadd runoob 0 rabitmq (integer) 0 redis 127.0.0.1:6379> ZRANGEBYSCORE runoob 0 1000 1) "redis" 2) "mongodb" 3) "rabitmq" Redis 有序集合命令 1 ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数 2 ZCARD key 获取有序集合的成员数 3 ZCOUNT key min max 计算在有序集合中指定区间分数的成员数 4 ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment 5 ZINTERSTORE destination numkeys key [key ...] 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中 6 ZLEXCOUNT key min max 在有序集合中计算指定字典区间内成员数量 7 ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合成指定区间内的成员 8 ZRANGEBYLEX key min max [LIMIT offset count] 通过字典区间返回有序集合的成员 9 ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 通过分数返回有序集合指定区间内的成员 10 ZRANK key member 返回有序集合中指定成员的索引 11 ZREM key member [member ...] 移除有序集合中的一个或多个成员 12 ZREMRANGEBYLEX key min max 移除有序集合中给定的字典区间的所有成员 13 ZREMRANGEBYRANK key start stop 移除有序集合中给定的排名区间的所有成员 14 ZREMRANGEBYSCORE key min max 移除有序集合中给定的分数区间的所有成员 15 ZREVRANGE key start stop [WITHSCORES] 返回有序集中指定区间内的成员,通过索引,分数从高到底 16 ZREVRANGEBYSCORE key max min [WITHSCORES] 返回有序集中指定分数区间内的成员,分数从高到低排序 17 ZREVRANK key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 18 ZSCORE key member 返回有序集中,成员的分数值 19 ZUNIONSTORE destination numkeys key [key ...] 计算给定的一个或多个有序集的并集,并存储在新的 key 中 20 ZSCAN key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成员和元素分值) HyperLogLog Redis 在 2.8.9 版本添加了 HyperLogLog 结构。 Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。 在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。 但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。 什么是基数? 比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。 实例 redis 127.0.0.1:6379> PFADD runoobkey "redis" 1) (integer) 1 redis 127.0.0.1:6379> PFADD runoobkey "mongodb" 1) (integer) 1 redis 127.0.0.1:6379> PFADD runoobkey "mysql" 1) (integer) 1 redis 127.0.0.1:6379> PFCOUNT runoobkey (integer) 3 Redis HyperLogLog 命令 1 PFADD key element [element ...] 添加指定元素到 HyperLogLog 中。 2 PFCOUNT key [key ...] 返回给定 HyperLogLog 的基数估算值。 3 PFMERGE destkey sourcekey [sourcekey ...] 将多个 HyperLogLog 合并为一个 HyperLogLog 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。 Redis 客户端可以订阅任意数量的频道。 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系: image 当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端: image 实例 redis 127.0.0.1:6379> SUBSCRIBE redisChat Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "redisChat" 3) (integer) 1 现在,我们先重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。 redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique" (integer) 1 redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com" (integer) 1 # 订阅者的客户端会显示如下消息 1) "message" 2) "redisChat" 3) "Redis is a great caching technique" 1) "message" 2) "redisChat" 3) "Learn redis by runoob.com" Redis 发布订阅命令 1 PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道。 2 PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态。 3 PUBLISH channel message 将信息发送到指定的频道。 4 PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道。 5 SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。 6 UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道。 Redis 事务 Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证: 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。 一个事务从开始到执行会经历以下三个阶段: 开始事务。 命令入队。 执行事务。 实例 `` txt 以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令: redis 127.0.0.1:6379> MULTI OK redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days" QUEUED redis 127.0.0.1:6379> GET book-name QUEUED redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series" QUEUED redis 127.0.0.1:6379> SMEMBERS tag QUEUED redis 127.0.0.1:6379> EXEC OK "Mastering C++ in 21 days" (integer) 3 "Mastering Series" "C++" "Programming" ##### Redis 事务命令 ``` txt 1 DISCARD 取消事务,放弃执行事务块内的所有命令。 2 EXEC 执行所有事务块内的命令。 3 MULTI 标记一个事务块的开始。 4 UNWATCH 取消 WATCH 命令对所有 key 的监视。 5 WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 Redis 连接 Redis 连接命令主要是用于连接 redis 服务。 实例 以下实例演示了客户端如何通过密码验证连接到 redis 服务,并检测服务是否在运行: redis 127.0.0.1:6379> AUTH "password" OK redis 127.0.0.1:6379> PING PONG Redis 连接命令 1 AUTH password 验证密码是否正确 2 ECHO message 打印字符串 3 PING 查看服务是否运行 4 QUIT 关闭当前连接 5 SELECT index 切换到指定的数据库 Redis 服务器 Redis 服务器命令主要是用于管理 redis 服务。 实例 以下实例演示了如何获取 redis 服务器的统计信息: redis 127.0.0.1:6379> INFO Redis 服务器命令 1 BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作 2 BGSAVE 在后台异步保存当前数据库的数据到磁盘 3 CLIENT KILL [ip:port] [ID client-id] 关闭客户端连接 4 CLIENT LIST 获取连接到服务器的客户端连接列表 5 CLIENT GETNAME 获取连接的名称 6 CLIENT PAUSE timeout 在指定时间内终止运行来自客户端的命令 7 CLIENT SETNAME connection-name 设置当前连接的名称 8 CLUSTER SLOTS 获取集群节点的映射数组 9 COMMAND 获取 Redis 命令详情数组 10 COMMAND COUNT 获取 Redis 命令总数 11 COMMAND GETKEYS 获取给定命令的所有键 12 TIME 返回当前服务器时间 13 COMMAND INFO command-name [command-name ...] 获取指定 Redis 命令描述的数组 14 CONFIG GET parameter 获取指定配置参数的值 15 CONFIG REWRITE 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 16 CONFIG SET parameter value 修改 redis 配置参数,无需重启 17 CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据 18 DBSIZE 返回当前数据库的 key 的数量 19 DEBUG OBJECT key 获取 key 的调试信息 20 DEBUG SEGFAULT 让 Redis 服务崩溃 21 FLUSHALL 删除所有数据库的所有key 22 FLUSHDB 删除当前数据库的所有key 23 INFO [section] 获取 Redis 服务器的各种信息和统计数值 24 LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示 25 MONITOR 实时打印出 Redis 服务器接收到的命令,调试用 26 ROLE 返回主从实例所属的角色 27 SAVE 异步保存数据到硬盘 28 SHUTDOWN [NOSAVE] [SAVE] 异步保存数据到硬盘,并关闭服务器 29 SLAVEOF host port 将当前服务器转变为指定服务器的从属服务器(slave server) 30 SLOWLOG subcommand [argument] 管理 redis 的慢日志 31 SYNC 用于复制功能(replication)的内部命令 Redis 数据备份与恢复 Redis SAVE 命令用于创建当前数据库的备份。 语法 redis Save 命令基本语法如下: redis 127.0.0.1:6379> SAVE 实例 redis 127.0.0.1:6379> SAVE OK 该命令将在 redis 安装目录中创建dump.rdb文件。 恢复数据 如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令,如下所示: redis 127.0.0.1:6379> CONFIG GET dir 1) "dir" 2) "/usr/local/redis/bin" 以上命令 CONFIG GET dir 输出的 redis 安装目录为 /usr/local/redis/bin。 Bgsave 创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行。 实例 127.0.0.1:6379> BGSAVE Background saving started Redis 客户端连接 Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自客户端的连接,当一个连接建立后,Redis 内部会进行以下一些操作: 首先,客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。 然后为这个 socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法 然后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送 最大连接数 在 Redis2.4 中,最大连接数是被直接硬编码在代码里面的,而在2.6版本中这个值变成可配置的。 maxclients 的默认值是 10000,你也可以在 redis.conf 中对这个值进行修改。 config get maxclients 1) "maxclients" 2) "10000" 实例 以下实例我们在服务启动时设置最大连接数为 100000: redis-server --maxclients 100000 客户端命令 1 CLIENT LIST 返回连接到 redis 服务的客户端列表 2 CLIENT SETNAME 设置当前连接的名称 3 CLIENT GETNAME 获取通过 CLIENT SETNAME 命令设置的服务名称 4 CLIENT PAUSE 挂起客户端连接,指定挂起的时间以毫秒计 5 CLIENT KILL 关闭客户端连接 三.Java 使用 Redis 下载jedis.jar 连接到 redis 服务 import redis.clients.jedis.Jedis; public class RedisJava { public static void main(String[] args) { //连接本地的 Redis 服务 Jedis jedis = new Jedis("localhost"); System.out.println("连接成功"); //查看服务是否运行 System.out.println("服务正在运行: "+jedis.ping()); } } 编译以上 Java 程序,确保驱动包的路径是正确的。 连接成功 服务正在运行: PONG Redis Java String(字符串) 实例 import redis.clients.jedis.Jedis; public class RedisStringJava { public static void main(String[] args) { //连接本地的 Redis 服务 Jedis jedis = new Jedis("localhost"); System.out.println("连接成功"); //设置 redis 字符串数据 jedis.set("runoobkey", "www.runoob.com"); // 获取存储的数据并输出 System.out.println("redis 存储的字符串为: "+ jedis.get("runoobkey")); } } 编译以上程序。 连接成功 redis 存储的字符串为: www.runoob.com Redis Java List(列表) 实例 import java.util.List; import redis.clients.jedis.Jedis; public class RedisListJava { public static void main(String[] args) { //连接本地的 Redis 服务 Jedis jedis = new Jedis("localhost"); System.out.println("连接成功"); //存储数据到列表中 jedis.lpush("site-list", "Runoob"); jedis.lpush("site-list", "Google"); jedis.lpush("site-list", "Taobao"); // 获取存储的数据并输出 List<String> list = jedis.lrange("site-list", 0 ,2); for(int i=0; i<list.size(); i++) { System.out.println("列表项为: "+list.get(i)); } } } 编译以上程序。 连接成功 列表项为: Taobao 列表项为: Google 列表项为: Runoob Redis Java Keys 实例 import java.util.Iterator; import java.util.Set; import redis.clients.jedis.Jedis; public class RedisKeyJava { public static void main(String[] args) { //连接本地的 Redis 服务 Jedis jedis = new Jedis("localhost"); System.out.println("连接成功"); // 获取数据并输出 Set<String> keys = jedis.keys("*"); Iterator<String> it=keys.iterator() ; while(it.hasNext()){ String key = it.next(); System.out.println(key); } } } 编译以上程序。 连接成功 runoobkey site-list Maven依赖 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.1.0</version> </dependency> java 代码 package com.shier.common.test; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class RedisTest { private Jedis jedis; @Before public void setup() { //连接redis服务器,192.168.0.100:6379 jedis = new Jedis("172.16.57.150", 6379); //权限认证 jedis.auth("shier@ixiye.com"); jedis.select(1); } /** * redis存储字符串 */ @Test public void testString() { //-----添加数据---------- jedis.set("name", "xinxin");//向key-->name中放入了value-->xinxin System.out.println(jedis.get("name"));//执行结果:xinxin jedis.append("name", " is my lover"); //拼接 System.out.println(jedis.get("name")); //jedis.del("name"); //删除某个键 System.out.println(jedis.get("name")); //设置多个键值对 //jedis.mset("name", "liuling", "age", "23", "qq", "476777XXX"); //jedis.incr("age"); //进行加1操作 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq")); } /** * redis操作Map */ @Test public void testMap() { //-----添加数据---------- Map<String, String> map = new HashMap<String, String>(); map.put("name", "xinxin"); map.put("age", "22"); map.put("qq", "123456"); jedis.hmset("user", map); //取出user中的name,执行结果:[minxr]-->注意结果是一个泛型的List //第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变参数 List<String> rsmap = jedis.hmget("user", "name", "age", "qq"); System.out.println(rsmap); //删除map中的某个键值 jedis.hdel("user", "age"); System.out.println(jedis.hmget("user", "age")); //因为删除了,所以返回的是null System.out.println(jedis.hlen("user")); //返回key为user的键中存放的值的个数2 System.out.println(jedis.exists("user"));//是否存在key为user的记录 返回true System.out.println(jedis.hkeys("user"));//返回map对象中的所有key System.out.println(jedis.hvals("user"));//返回map对象中的所有value Iterator<String> iter = jedis.hkeys("user").iterator(); while (iter.hasNext()) { String key = iter.next(); System.out.println(key + ":" + jedis.hmget("user", key)); } } /** * jedis操作List */ @Test public void testList() { //开始前,先移除所有的内容 jedis.del("java framework"); System.out.println(jedis.lrange("java framework", 0, -1)); //先向key java framework中存放三条数据 jedis.lpush("java framework", "spring"); jedis.lpush("java framework", "struts"); jedis.lpush("java framework", "hibernate"); //再取出所有数据jedis.lrange是按范围取出, // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有 System.out.println(jedis.lrange("java framework", 0, -1)); jedis.del("java framework"); jedis.rpush("java framework", "spring"); jedis.rpush("java framework", "struts"); jedis.rpush("java framework", "hibernate"); System.out.println(jedis.lrange("java framework", 0, -1)); } /** * jedis操作Set */ @Test public void testSet() { //添加 jedis.sadd("user", "liuling"); jedis.sadd("user", "xinxin"); jedis.sadd("user", "ling"); jedis.sadd("user", "zhangxinxin"); jedis.sadd("user", "who"); //移除noname jedis.srem("user", "who"); System.out.println(jedis.smembers("user"));//获取所有加入的value System.out.println(jedis.sismember("user", "who"));//判断 who 是否是user集合的元素 System.out.println(jedis.srandmember("user")); System.out.println(jedis.scard("user"));//返回集合的元素个数 } @Test public void test() throws InterruptedException { //jedis 排序 //注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的) jedis.del("a");//先清除数据,再加入数据进行测试 jedis.rpush("a", "1"); jedis.lpush("a", "6"); jedis.lpush("a", "3"); jedis.lpush("a", "9"); System.out.println(jedis.lrange("a", 0, -1));// [9, 3, 6, 1] System.out.println(jedis.sort("a")); //[1, 3, 6, 9] //输入排序后结果 System.out.println(jedis.lrange("a", 0, -1)); } } RedisUtil package com.shier.common.util; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public final class RedisUtil { //Redis服务器IP private static String ADDR = "172.16.57.150"; //Redis的端口号 private static int PORT = 6379; //访问密码 private static String AUTH = "shier@ixiye.com"; //可用连接实例的最大数目,默认值为8; //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。 private static int MAX_ACTIVE = 1024; //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。 private static int MAX_IDLE = 200; //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException; private static int MAX_WAIT = 10000; private static int TIMEOUT = 10000; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; private static boolean TEST_ON_BORROW = true; private static JedisPool jedisPool = null; /** * 初始化Redis连接池 */ static { try { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxActive(MAX_ACTIVE); config.setMaxIdle(MAX_IDLE); config.setMaxWait(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH); } catch (Exception e) { e.printStackTrace(); } } /** * 获取Jedis实例 * * @return */ public synchronized static Jedis getJedis() { try { if (jedisPool != null) { Jedis resource = jedisPool.getResource(); return resource; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } } /** * 释放jedis资源 * * @param jedis */ public static void returnResource(final Jedis jedis) { if (jedis != null) { jedisPool.returnResource(jedis); } } } ----------------------------------------------------------------- package com.shier.common.test; import com.shier.common.util.RedisUtil; import org.junit.Test; import redis.clients.jedis.Jedis; public class RedisTest { @Test public void testRedisPool() { RedisUtil.getJedis().set("newname", "中文测试"); System.out.println(RedisUtil.getJedis().get("newname")); } } 四.Spring整合Redis 添加Redis Maven依赖 <span style="white-space:pre;"> </span><!-- redis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.1.RELEASE</version> </dependency> config.properties redis.host=192.168.0.254 redis.port=6379 redis.password=jedis21tb redis.maxIdle=300 redis.maxWait=1000 redis.testOnBorrow=true redis.timeout=3000 spring配置文件(applicationContext.xml) <!--引入配置属性文件 --> <context:property-placeholder location="classpath:config.properties" /> <!-- redis --> <!-- jedis 配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" > <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean > <!-- redis服务器中心 --> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <property name="poolConfig" ref="poolConfig" /> <property name="port" value="${redis.port}" /> <property name="hostName" value="${redis.host}" /> <property name="password" value="${redis.password}" /> <property name="timeout" value="${redis.timeout}" ></property> </bean > <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" > <property name="connectionFactory" ref="connectionFactory" /> <property name="keySerializer" > <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <!-- <property name="valueSerializer" > <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> --> </bean > <bean id="redisUtil" class="com.kttx.common.RedisUtil" > <property name="redisTemplate" ref="redisTemplate" /> </bean > java代码 package com.kttx.common; import java.io.Serializable; import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; /** * redis * @author txs * */ public class RedisUtil { private static Logger logger = Logger.getLogger(RedisUtil.class); private static RedisTemplate<Serializable, Object> redisTemplate; /** * 写入或更新缓存 * @param key * @param value * @return */ public static boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { logger.error("write redis is faill"); e.printStackTrace(); } return result; } /** * 写入缓存 * 设置失效时间 * @param key * @param value * @return */ public static boolean set(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 读取缓存 * @param key * @return */ public static Object get(final String key) { Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue(); result = operations.get(key); return result; } /** * 删除对应的value * @param key */ public static void remove(final String key) { if (exists(key)) { redisTemplate.delete(key); } } /** * 批量删除对应的value * * @param keys */ public static void remove(final String... keys) { for (String key : keys) { remove(key); } } /** * 批量删除key * * @param pattern 正则表达式 */ public static void removePattern(final String pattern) { Set<Serializable> keys = redisTemplate.keys(pattern); if (keys.size() > 0) redisTemplate.delete(keys); } /** * 判断缓存中是否有对应的value * * @param key * @return */ public static boolean exists(final String key) { return redisTemplate.hasKey(key); } public void setRedisTemplate( RedisTemplate<Serializable, Object> redisTemplate) { this.redisTemplate = redisTemplate; } } 五.Spring boot整合Redis 添加maveny依赖 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.1.RELEASE</version> </dependency> 配置属性: # database name spring.redis.database=0 # server host spring.redis.host=127.0.0.1 # server password spring.redis.password=123456 #connection port spring.redis.port=6379 # pool settings ... spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0 spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 redis配置 package com.ming.config; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration @EnableCaching // 启用缓存,这个注解很重要; public class RedisCacheConfig extends CachingConfigurerSupport { /** * 生成key的策略 * * @return */ @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } /** * 管理缓存 * * @param redisTemplate * @return */ @SuppressWarnings("rawtypes") @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); //设置缓存过期时间 // rcm.setDefaultExpiration(60);//秒 //设置value的过期时间 Map<String,Long> map=new HashMap<String, Long>(); map.put("test",60L); rcm.setExpires(map); return rcm; } /** * RedisTemplate配置 * @param factory * @return */ @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer);//如果key是String 需要配置一下StringSerializer,不然key会乱码 /XX/XX template.afterPropertiesSet(); return template; } } package com.ming.config; import java.io.Serializable; import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; /** * redicache 工具类 * */ @SuppressWarnings("unchecked") @Component public class RedisUtils { @SuppressWarnings("rawtypes") @Autowired private RedisTemplate redisTemplate; /** * 批量删除对应的value * * @param keys */ public void remove(final String... keys) { for (String key : keys) { remove(key); } } /** * 批量删除key * * @param pattern */ public void removePattern(final String pattern) { Set<Serializable> keys = redisTemplate.keys(pattern); if (keys.size() > 0) redisTemplate.delete(keys); } /** * 删除对应的value * * @param key */ public void remove(final String key) { if (exists(key)) { redisTemplate.delete(key); } } /** * 判断缓存中是否有对应的value * * @param key * @return */ public boolean exists(final String key) { return redisTemplate.hasKey(key); } /** * 读取缓存 * * @param key * @return */ public Object get(final String key) { Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key); return result; } /** * 写入缓存 * * @param key * @param value * @return */ public boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 写入缓存 * * @param key * @param value * @return */ public boolean set(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } } 测试 package com.ming.web.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ming.config.RedisUtils; @RestController @RequestMapping("/caches") public class CacheController { @Autowired private RedisUtils redisUtils; @RequestMapping("/test") public String test(){ redisUtils.set("123", "hello world"); System.out.println("进入了方法"); String string= redisUtils.get("123").toString(); return string; } }

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册