首页
壁纸
留言板
友链
更多
统计归档
Search
1
TensorBoard:训练日志及网络结构可视化工具
12,544 阅读
2
主板开机跳线接线图【F_PANEL接线图】
5,800 阅读
3
Linux使用V2Ray 原生客户端
5,091 阅读
4
NVIDIA 显卡限制功率
2,780 阅读
5
帧差法+三帧差法原理与实现
2,452 阅读
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
登录
/
注册
Search
标签搜索
好物分享
学习笔记
linux
MySQL
nvidia
typero
内网穿透
webdav
vps
java
cudann
gcc
cuda
树莓派
CNN
图像去雾
ssh安全
nps
暗通道先验
阿里云
jupiter
累计撰写
346
篇文章
累计收到
68
条评论
首页
栏目
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
页面
壁纸
留言板
友链
统计归档
搜索到
76
篇与
的结果
2024-07-12
CenterOS7安装Maven
1.安装java环境参考:CenterOS7安装java环境 - jupiter's blog (inat.top)2.下载maven并解压下载地址:https://maven.apache.org/download.cgiwget https://dlcdn.apache.org/maven/maven-3/3.9.8/binaries/apache-maven-3.9.8-bin.tar.gztar xzvf apache-maven-3.9.8-bin.tar.gz创建本地仓库文件夹cd apache-maven-3.9.8 mkdir repository3.配置环境变量vim ~/.bashrc# 配置maven_home和Path环境变量 export MAVEN_HOME=/software/apache-maven-3.9.8 export PATH=$PATH:$MAVEN_HOME/bin # 配置本地仓库地址环境变量 export M2_HOME=/software/apache-maven-3.9.8/repositorysource ~/.bashrc4.配置镜像源vim conf/settings.xml# 在<mirrors></mirrors>标签中添加 mirror 子节点 <!-- 阿里云仓库 --> <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror>5.检查是否安装成功[root@localhost apache-maven-3.9.8]# mvn --version Apache Maven 3.9.8 (36645f6c9b5079805ea5009217e36f2cffd34256) Maven home: /software/apache-maven-3.9.8 Java version: 17.0.11, vendor: Eclipse Adoptium, runtime: /software/jdk17 Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "3.10.0-1160.119.1.el7.x86_64", arch: "amd64", family: "unix"参考资料CenterOS7安装java环境 - jupiter's blog (inat.top)Maven超细致史上最全Maven下载安装配置教学(2023更新...全版本)建议收藏...赠送IDEA配置Maven教程-CSDN博客
2024年07月12日
2 阅读
0 评论
0 点赞
2024-07-10
CenterOS7手动安装gitlab
1.准备工作gitlab的安装,需要依赖相关组件,主要有policycoreutils-pythonopensshpostfix实测默认的centerOS7上都已经安装了1.1 检查policycoreutils-python是否安装[root@localhost .jenkins]# rpm -qa|grep policycoreutils-python policycoreutils-python-2.5-34.el7.x86_641.2 检查openssh是否安装[root@localhost .jenkins]# rpm -qa|grep openssh openssh-clients-7.4p1-23.el7_9.x86_64 openssh-7.4p1-23.el7_9.x86_64 openssh-server-7.4p1-23.el7_9.x86_641.3 检查postfix是否安装[root@localhost .jenkins]# rpm -qa|grep postfix postfix-2.10.1-9.el7.x86_642.下载gitlab安装包从gitlab官网地址中下载:https://packages.gitlab.com/gitlab/gitlab-ce,选择适用于CentOS7的el/7版本进行下载。wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/7/gitlab-ce-16.6.8-ce.0.el7.x86_64.rpm/download.rpm镜像站下载地址:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-17.1.1-ce.0.el7.x86_64.rpm3.安装gitlabrpm -i gitlab-ce-17.1.1-ce.0.el7.x86_64.rpm当出现以下内容提示,说明gitlab安装成功;warning: gitlab-ce-17.1.1-ce.0.el7.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID f27eab47: NOKEY It looks like GitLab has not been configured yet; skipping the upgrade script. *. *. *** *** ***** ***** .****** ******* ******** ******** ,,,,,,,,,***********,,,,,,,,, ,,,,,,,,,,,*********,,,,,,,,,,, .,,,,,,,,,,,*******,,,,,,,,,,,, ,,,,,,,,,*****,,,,,,,,,. ,,,,,,,****,,,,,, .,,,***,,,, ,*,. _______ __ __ __ / ____(_) /_/ / ____ _/ /_ / / __/ / __/ / / __ `/ __ \ / /_/ / / /_/ /___/ /_/ / /_/ / \____/_/\__/_____/\__,_/_.___/ Thank you for installing GitLab! GitLab was unable to detect a valid hostname for your instance. Please configure a URL for your GitLab instance by setting `external_url` configuration in /etc/gitlab/gitlab.rb file. Then, you can start your GitLab instance by running the following command: sudo gitlab-ctl reconfigure For a comprehensive list of configuration options please see the Omnibus GitLab readme https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md Help us improve the installation experience, let us know how we did with a 1 minute survey: https://gitlab.fra1.qualtrics.com/jfe/form/SV_6kVqZANThUQ1bZb?installation=omnibus&release=17-14.修改对外暴露的IP及端口修改/etc/gitlab/gitlab.rb文件中的external_url,设置gitlab的登录地址;vim /etc/gitlab/gitlab.rb## GitLab URL ##! URL on which GitLab will be reachable. ##! For more details on configuring external_url see: ##! https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab ##! ##! Note: During installation/upgrades, the value of the environment variable ##! EXTERNAL_URL will be used to populate/replace this value. ##! On AWS EC2 instances, we also attempt to fetch the public hostname/IP ##! address from AWS. For more details, see: ##! https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html external_url 'http://192.168.124.17:8080'重新加载配置gitlab-ctl reconfigure #重新生成相关配置文件,执行此命令时间比较长5.启动GitLab# 关闭防火墙 也可以自行开放端口 systemctl stop firewalld # 开放端口号 firewall-cmd --zone=public --add-port=8080/tcp --permanent # 重启防火墙 systemctl restart firewalld# 重启gitlab gitlab-ctl restart启动日志ok: run: alertmanager: (pid 6113) 1s ok: run: gitaly: (pid 6122) 1s ok: run: gitlab-exporter: (pid 6137) 0s ok: run: gitlab-kas: (pid 6148) 1s ok: run: gitlab-workhorse: (pid 6156) 0s ok: run: logrotate: (pid 6166) 0s ok: run: nginx: (pid 6172) 1s ok: run: node-exporter: (pid 6178) 0s ok: run: postgres-exporter: (pid 6183) 1s ok: run: postgresql: (pid 6193) 0s ok: run: prometheus: (pid 6202) 0s ok: run: puma: (pid 6212) 0s ok: run: redis: (pid 6217) 0s ok: run: redis-exporter: (pid 6224) 0s ok: run: sidekiq: (pid 6235) 0s访问测试:http://192.168.124.17:8080502问题定位:端口冲突导致的vim /etc/gitlab/gitlab.rb找到如下内容### Advanced settings # puma['listen'] = '127.0.0.1' # puma['port'] = 8080 # puma['socket'] = '/var/opt/gitlab/gitlab-rails/sockets/gitlab.socket' # puma['somaxconn'] = 2048修改为### Advanced settings puma['listen'] = '127.0.0.1' puma['port'] = 8008 # puma['socket'] = '/var/opt/gitlab/gitlab-rails/sockets/gitlab.socket' # puma['somaxconn'] = 2048重新配置启动#重新生成相关配置文件,执行此命令时间比较长 gitlab-ctl reconfigure # 重启gitlab gitlab-ctl restart再次访问测试:http://192.168.124.17:8080/6. 配置gitlab开机自动启动systemctl enable gitlab-runsvdir.service systemctl start gitlab-runsvdir.service # 关闭gitlab的自动启动命令: systemctl disable gitlab-runsvdir.service参考资料Index of /gitlab-ce/yum/el7/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirrorcentos 7离线安装中文版GitLab - 小破孩楼主 - 博客园 (cnblogs.com)CentOS7离线搭建GitLab_在centos7上离线安装gitlab-CSDN博客linux中安装Gitlab服务器后登录报错502解决办法(图文结合)_linux安装gitlab后502-CSDN博客
2024年07月10日
6 阅读
0 评论
0 点赞
2024-07-09
CenterOS7安装jenkins
1.准备工作1.1 安装java环境参考:CenterOS7安装java环境 - jupiter's blog (inat.top)1.2 安装git如果你的系统没有自带git,那么也需要安装一个yum install git2.通过下载war包安装2.1 war包下载官网下载地址:https://www.jenkins.io/zh/download/阿里云镜像站下载地址:https://mirrors.aliyun.com/jenkins/war/latest/清华大学开源软件镜像站 (☆☆☆推荐):https://mirrors.tuna.tsinghua.edu.cn/jenkins/war/latest/wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war/latest/jenkins.war2.2 启动jenkins(报错) java -jar jenkins.war访问测试:http://192.168.124.18:8080/报错:AWT is not properly configured on this server. Perhaps you need to run your container with "-Djava.awt.headless=true"? See also: https://www.jenkins.io/redirect/troubleshooting/java.awt.headless错误原因,因为安装的是openjdk2.3 错误修复#CentOS 7 yum install fontconfig java -jar jenkins.war启动日志2024-07-09 15:09:23.538+0000 [id=31] INFO jenkins.install.SetupWizard#init: ************************************************************* ************************************************************* ************************************************************* Jenkins initial setup is required. An admin user has been created and a password generated. Please use the following password to proceed to installation: 9bd6e45ed26c47fd83903af49ef79997 This may also be found at: /root/.jenkins/secrets/initialAdminPassword ************************************************************* ************************************************************* ************************************************************* 访问测试:http://192.168.124.18:8080/等待初始化完成输入启动日志中的密码即可顺利进入,选择安装默认插件部署jenkins一直显示Please wait while Jenkins is getting ready to work …vim ~/.jenkins/hudson.model.UpdateCenter.xml将https://updates.jenkins.io/update-center.json更换为更改为https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json<?xml version='1.1' encoding='UTF-8'?> <sites> <site> <id>default</id> <url>https://updates.jenkins.io/update-center.json</url> </site> </sites>2.4 创建用户使用参考资料CenterOS7安装java环境 - jupiter's blog (inat.top)解决jenkins报错:AWT is not properly configured on this server-CSDN博客部署jenkins一直显示Please wait while Jenkins is getting ready to work-CSDN博客
2024年07月09日
4 阅读
0 评论
0 点赞
2024-07-09
CenterOS7安装java环境
1.下载安装包wget https://mirrors.tuna.tsinghua.edu.cn/Adoptium/17/jdk/x64/linux/OpenJDK17U-jdk_x64_linux_hotspot_17.0.11_9.tar.gz2.解压并移动到目标路径tar xzvf OpenJDK17U-jdk_x64_linux_hotspot_17.0.11_9.tar.gz mv jdk-17.0.11+9 jdk17 mv jdk17 /software/3.配置环境变量 vim ~/.bashrcexport JAVA_HOME=/software/jdk17 export PATH=$PATH:$JAVA_HOME/bin source ~/.bashrc4.验证[root@localhost ~]# java -version openjdk version "17.0.11" 2024-04-16 OpenJDK Runtime Environment Temurin-17.0.11+9 (build 17.0.11+9) OpenJDK 64-Bit Server VM Temurin-17.0.11+9 (build 17.0.11+9, mixed mode, sharing)参考资料Index of /Adoptium/17/jdk/x64/linux/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
2024年07月09日
8 阅读
0 评论
0 点赞
2024-06-22
SpringBoot启动后执行方法
0.主启动类public class HikariDataSourceApplication { public static void main(String[] args) { SpringApplication.run(HikariDataSourceApplication.class, args); System.out.println("项目启动成功====================================="); } }1.@PostConstruct 注解在项目初始化过程中,就会调用此方法。如果业务逻辑执行很耗时,可能会导致项目启动失败。import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Component; @Component public class StartInit1 { @PostConstruct public void init() { System.out.println("@PostConstruct==============================="); } }2024-06-22T22:51:22.978+08:00 INFO 18120 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2024-06-22T22:51:22.990+08:00 INFO 18120 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-06-22T22:51:22.990+08:00 INFO 18120 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24] 2024-06-22T22:51:23.023+08:00 INFO 18120 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-06-22T22:51:23.024+08:00 INFO 18120 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 668 ms @PostConstruct=============================== 2024-06-22T22:51:23.303+08:00 WARN 18120 --- [ main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - idleTimeout is close to or more than maxLifetime, disabling it. 2024-06-22T22:51:23.304+08:00 INFO 18120 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-06-22T22:51:23.391+08:00 INFO 18120 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@46468f0 2024-06-22T22:51:23.393+08:00 INFO 18120 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-06-22T22:51:23.503+08:00 INFO 18120 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2024-06-22T22:51:23.509+08:00 INFO 18120 --- [ main] c.e.h.HikariDataSourceApplication : Started HikariDataSourceApplication in 1.415 seconds (process running for 1.729) 项目启动成功=====================================2.实现 CommandLineRunner 接口项目初始化完毕后,才会调用方法,提供服务import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class StartInit2 implements CommandLineRunner { @Override public void run(String... args) { System.out.println("CommandLineRunner===================="); } }2024-06-22T22:54:34.798+08:00 INFO 14312 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2024-06-22T22:54:34.806+08:00 INFO 14312 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-06-22T22:54:34.806+08:00 INFO 14312 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24] 2024-06-22T22:54:34.845+08:00 INFO 14312 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-06-22T22:54:34.845+08:00 INFO 14312 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 660 ms 2024-06-22T22:54:35.128+08:00 WARN 14312 --- [ main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - idleTimeout is close to or more than maxLifetime, disabling it. 2024-06-22T22:54:35.128+08:00 INFO 14312 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-06-22T22:54:35.214+08:00 INFO 14312 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3a0b6a 2024-06-22T22:54:35.215+08:00 INFO 14312 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-06-22T22:54:35.324+08:00 INFO 14312 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2024-06-22T22:54:35.328+08:00 INFO 14312 --- [ main] c.e.h.HikariDataSourceApplication : Started HikariDataSourceApplication in 1.408 seconds (process running for 1.722) CommandLineRunner==================== 项目启动成功===================================== 3.实现 ApplicationRunner 接口同 CommandLineRunner。只是传参格式不一样。CommandLineRunner:没有任何限制;ApplicationRunner:key-valueimport org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class StartInit3 implements ApplicationRunner { @Override public void run(ApplicationArguments args) { System.out.println("ApplicationRunner================="); } }2024-06-22T22:57:50.064+08:00 INFO 19228 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2024-06-22T22:57:50.071+08:00 INFO 19228 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-06-22T22:57:50.071+08:00 INFO 19228 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24] 2024-06-22T22:57:50.105+08:00 INFO 19228 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-06-22T22:57:50.105+08:00 INFO 19228 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 670 ms 2024-06-22T22:57:50.386+08:00 WARN 19228 --- [ main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - idleTimeout is close to or more than maxLifetime, disabling it. 2024-06-22T22:57:50.387+08:00 INFO 19228 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-06-22T22:57:50.481+08:00 INFO 19228 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@539c4830 2024-06-22T22:57:50.483+08:00 INFO 19228 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-06-22T22:57:50.601+08:00 INFO 19228 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2024-06-22T22:57:50.606+08:00 INFO 19228 --- [ main] c.e.h.HikariDataSourceApplication : Started HikariDataSourceApplication in 1.439 seconds (process running for 1.755) ApplicationRunner================= 项目启动成功=====================================4.实现 ApplicationListener 接口项目初始化完毕后,才会调用方法,提供服务。注意监听的事件,通常是 ApplicationStartedEvent 或者 ApplicationReadyEvent,其他的事件可能无法注入 bean。如果监听的是 ApplicationStartedEvent 事件,则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之前执行;如果监听的是 ApplicationReadyEvent 事件,则 ApplicationListener 一定会在 CommandLineRunner 和import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class StartInit4 implements ApplicationListener<ApplicationStartedEvent> { @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("ApplicationListener================ApplicationStartedEvent"); } }2024-06-22T23:01:14.615+08:00 INFO 21164 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2024-06-22T23:01:14.627+08:00 INFO 21164 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-06-22T23:01:14.628+08:00 INFO 21164 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24] 2024-06-22T23:01:14.661+08:00 INFO 21164 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-06-22T23:01:14.661+08:00 INFO 21164 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 683 ms 2024-06-22T23:01:14.942+08:00 WARN 21164 --- [ main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - idleTimeout is close to or more than maxLifetime, disabling it. 2024-06-22T23:01:14.942+08:00 INFO 21164 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-06-22T23:01:15.027+08:00 INFO 21164 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@6486fe7b 2024-06-22T23:01:15.028+08:00 INFO 21164 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-06-22T23:01:15.133+08:00 INFO 21164 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2024-06-22T23:01:15.138+08:00 INFO 21164 --- [ main] c.e.h.HikariDataSourceApplication : Started HikariDataSourceApplication in 1.429 seconds (process running for 1.752) ApplicationListener================ApplicationStartedEvent 项目启动成功=====================================5.执行顺序2024-06-22T23:03:22.206+08:00 INFO 19432 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-06-22T23:03:22.207+08:00 INFO 19432 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24] 2024-06-22T23:03:22.244+08:00 INFO 19432 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-06-22T23:03:22.244+08:00 INFO 19432 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 613 ms @PostConstruct=============================== 2024-06-22T23:03:22.519+08:00 WARN 19432 --- [ main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - idleTimeout is close to or more than maxLifetime, disabling it. 2024-06-22T23:03:22.519+08:00 INFO 19432 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-06-22T23:03:22.604+08:00 INFO 19432 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3e14d390 2024-06-22T23:03:22.605+08:00 INFO 19432 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-06-22T23:03:22.708+08:00 INFO 19432 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2024-06-22T23:03:22.716+08:00 INFO 19432 --- [ main] c.e.h.HikariDataSourceApplication : Started HikariDataSourceApplication in 1.317 seconds (process running for 1.573) ApplicationListener================ApplicationReadyEvent ApplicationRunner================= CommandLineRunner==================== ApplicationListener================ApplicationReadyEvent 项目启动成功=====================================参考资料【SpringBoot】 启动后执行方法的五种方式_springboot启动后执行某个方法-CSDN博客Springboot启动后执行方法的四种方式_springboot 启动执行方法-CSDN博客
2024年06月22日
14 阅读
0 评论
0 点赞
2024-06-22
MyBatis的工作原理和SpringBoot快速集成Mybatis(极简)
1.MyBatis的工作原理1.1、传统的JDBC编程JAVA程序通过JDBC链接数据库,这样我们就可以通过SQL对数据库进行编程。JAVA链接数据库大致分为五步,如下所示:1、使用JDBC编程需要链接数据库,注册驱动和数据库信息。2、操作Connection,打开Statement对象。3、通过Statement执行SQL语句,返回结果放到ResultSet对象。4、使用ResultSet读取数据。5、关闭数据库相关的资源。JDBC 代码示例:import java.sql.*; public class JdbcDemo { public static void main(String[] args) throws SQLException, ClassNotFoundException { String username = "db1"; String password = "db1"; String url = "jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"; // 使用JDBC编程需要链接数据库,注册驱动和数据库信息。 Connection conn = DriverManager.getConnection(url,username,password); // 编写待执行sql String sql = "select * from user1"; // 通过Statement执行SQL语句,返回结果放到ResultSet对象。 PreparedStatement preparedStatement = conn.prepareStatement(sql); ResultSet rs = preparedStatement.executeQuery(); //使用ResultSet读取数据。 // 获取 ResultSetMetadata 对象,它包含了 ResultSet 的结构信息 ResultSetMetaData metaData = rs.getMetaData(); // 打印列名 for (int i = 1; i <= metaData.getColumnCount(); i++) { System.out.print(metaData.getColumnName(i) + "\t"); } System.out.println(); // 换行 // 遍历 ResultSet 并打印数据 while (rs.next()) { for (int i = 1; i <= metaData.getColumnCount(); i++) { System.out.print(rs.getString(i) + "\t"); } System.out.println(); // 每行数据后换行 } // 关闭数据库相关的资源。 preparedStatement.close(); conn.close(); } }传统的JDBC方式存在一些弊端:(1)工作量比较大。我们需要先建立链接,然后处理JDBC底层业务,处理数据类型。我们还需要处理Connection对象,Statement对象和Result对象去拿数据,并关闭它们。(2)我们对JDBC编程处理的异常进行捕获处理并正确的关闭资源。1.2、MyBatis工作原理:对JDBC进行了封装MyBatis的四大核心组件:1、SQLSessionFactoryBuilder(构造器):它会根据配置信息或者代码生成SqlSessionFactory。2、SqlSessionFactory(工厂接口):依靠工厂生成SqlSession。3、SqlSession(会话):是一个既可以发送SQL去执行并且返回结果,也可以获取Mapper接口。4、SQL Mapper:是由一个JAVA接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。SQL是由Mapper发送出去,并且返回结果。MyBatis工作原理示意图:从上面的流程图可以看出MyBatis和JDBC的执行时相似的。MyBatis的底层操作封装了JDBC的API,MyBatis的工作原理以及核心流程与JDBC的使用步骤一脉相承,MyBatis的核心对象(SqlSession,Executor)与JDBC的核心对象(Connection,Statement)相互对应。1.3 @Mapper执行sql原理Mapper 接口与 @Mapper 注解:Mapper 接口是用户定义的,其中包含了与数据库表交互的方法。@Mapper 注解是 MyBatis-Spring 集成库中的一个注解,用于标识一个接口作为 MyBatis 的 Mapper 接口。当接口被 @Mapper 注解标记后,MyBatis 会自动为这个接口创建一个代理实现类。MyBatis 映射器(Mapper)的代理实现:MyBatis 使用 Java 动态代理技术为 Mapper 接口创建代理实现类。代理实现类会拦截对 Mapper 接口方法的调用,并根据方法的定义(包括方法名、参数等)来查找并执行相应的 SQL 语句。SQL 语句的查找与执行:MyBatis 会在配置的 SQL 映射文件(通常是 XML 文件)中查找与 Mapper 接口方法对应的 SQL 语句。SQL 映射文件定义了 Mapper 接口中每个方法对应的 SQL 语句,包括查询、插入、更新、删除等操作。MyBatis 会根据 Mapper 接口方法的定义和 SQL 映射文件中的配置,生成具体的 SQL 语句并执行。@Param 注解与参数绑定:如果 Mapper 接口方法中有参数,可以使用 @Param 注解来指定参数名。MyBatis 会根据 @Param 注解指定的参数名,在 SQL 语句中进行参数绑定。参数绑定是将 Java 对象的属性值或方法参数值设置到 SQL 语句的占位符中的过程。结果映射与返回类型:MyBatis 会根据 Mapper 接口方法的返回类型,将 SQL 语句执行的结果映射为相应的 Java 对象或集合。结果映射可以在 XML 映射文件中进行配置,包括结果集的列名与 Java 对象属性的对应关系等。Spring 集成与 SqlSessionTemplate:在 Spring 与 MyBatis 的集成中,SqlSessionTemplate 是一个关键的组件。SqlSessionTemplate 封装了 SqlSession 的使用,并提供了线程安全的 SQL 执行环境。当通过 Spring 容器注入 Mapper 接口时,实际上注入的是 SqlSessionTemplate 创建的 Mapper 代理实现类的实例。总结:@Mapper 注解使得 MyBatis 能够自动为 Mapper 接口创建代理实现类。MyBatis 通过动态代理和 SQL 映射文件来执行 Mapper 接口中定义的 SQL 语句。Spring 集成通过 SqlSessionTemplate 提供了线程安全的 SQL 执行环境,并简化了 Mapper 接口的注入和使用。2.MyBatis的优点MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。MyBatis是对JDBC的封装。相对于JDBC,MyBatis有以下优点:SQL映射:MyBatis 支持定制化 SQL、存储过程以及高级映射。它允许你直接在 XML 映射文件中编写 SQL 语句,或者使用注解的方式将 SQL 语句直接写在 Mapper 接口的方法上。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的麻烦,极大地简化了数据库操作。对象关系映射(ORM):MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。提供了映射标签,支持对象与数据库的 ORM 字段关系映射,降低了耦合度,提高了代码的复用性和可维护性。动态SQL:MyBatis 提供了 XML 标签,支持编写动态 SQL 语句。你可以根据传入参数的不同,动态地生成不同的 SQL 语句,实现更复杂的数据库操作。事务管理:MyBatis 通过与 Spring 等框架的集成,提供了完整的事务管理功能。它支持编程式事务和声明式事务,可以确保数据的一致性。插件机制:MyBatis 提供了插件机制,允许你通过编写插件来扩展 MyBatis 的功能。例如,你可以编写一个插件来拦截 SQL 语句的执行,进行日志记录、性能监控等操作。缓存机制:MyBatis 提供了一级缓存(SqlSession 级别的缓存)和二级缓存(Mapper 级别的缓存)来提高查询性能。一级缓存默认是开启的,而二级缓存需要手动开启并进行配置。3.快速集成步骤3.1 引入mybatis-starter依赖<!-- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency>其他必备依赖<!-- springboot基础依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.3.0</version> </dependency> <!-- mysql数据库连接驱动--> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> </dependency> <!-- 引入Spring封装的jdbc,内部默认依赖了 HikariDataSource 数据源--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> </dependency>测试辅助依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>3.3.0</version> </dependency>3.2 配置数据源在 application.properties 或 application.yml 文件中配置你的数据源(如MySQL)。spring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: db1 password: db1 type: com.zaxxer.hikari.HikariDataSource hikari: # 连接池最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size minimum-idle: 10 # 连接池最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值。 maximum-pool-size: 20 # 连接最大存活时间,不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短 max-lifetime: 600000 # 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。 idle-timeout: 600000 # 连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒,如果在这个时间内无法建立连接,将会抛出异常。 connection-timeout: 30000 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.hikaridatasource.domain.entity3.3 创建数据源和Mybatis必备bean的Config文件@Configuration public class Db1DataSourceConfig { // jdbc连接信息 @Value(value = "${spring.datasource.url:}") private String url; @Value(value = "${spring.datasource.username:}") private String username; @Value(value = "${spring.datasource.password:}") private String password; @Value(value = "${spring.datasource.driver-class-name:}") private String driveClassName; // HikariDataSource配置参数 // 连接池最小空闲连接,默认值10 @Value(value = "${spring.datasource.hikari.minimum-idle:10}") private int minimumIdle; // 连接池最大连接数,默认值10 @Value(value = "${spring.datasource.hikari.maximum-pool-size:10}") private int maximumPoolSize; // 连接最大存活时间,默认值30分钟.设置应该比mysql设置的超时时间短,配置单位毫秒 @Value(value = "${spring.datasource.hikari.max-lifetime:600000}") private long maxLifetime; // 空闲连接超时时间,默认值600000(10分钟)配置单位毫秒 @Value(value = "${spring.datasource.hikari.idle-timeout:600000}") private long idleTimeout; // 连接超时时间,配置单位毫秒 @Value(value = "${spring.datasource.hikari.connection-timeout:60000}") private long connectionTimeout; // mybatis配置 // mapperXml文件地址 @Value(value = "${spring.datasource.hikari.mapper-locations:}") private String mapperLocations; /** * 配置db1 数据源 */ @Bean(name = "db1DataSource") public DataSource db1DataSource(){ HikariDataSource dataSource = new HikariDataSource(); // 设置jdbc连接信息 dataSource.setJdbcUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setDriverClassName(driveClassName); // 设置HikariDataSource配置参数 dataSource.setMinimumIdle(minimumIdle); dataSource.setMaximumPoolSize(maximumPoolSize); dataSource.setMaxLifetime(maxLifetime); dataSource.setIdleTimeout(idleTimeout); dataSource.setConnectionTimeout(connectionTimeout); return dataSource; } /** * 配置db1 SqlSessionFactory mybatis必备(实现数据库连接会话管理) */ @Bean(name = "db1SqlSessionFactory") public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); // 设置mapperXml文件地址 //factory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(mapperLocations)); return factory.getObject(); } /** * 配置db1 SqlSessionTemplate mybatis必备(实现数据库连接sql执行和结果映射) */ @Bean(name = "db1SqlSessionTemplate") public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory){ return new SqlSessionTemplate(sqlSessionFactory); } /** * 配置db1 DataSourceTransactionManager 事务管理器(Spring的JDBC事务增强) */ @Bean(name = "db1DataSourceTransactionManager") public DataSourceTransactionManager db1DataSourceTransactionManager(@Qualifier("db1DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }3.4 创建实体类(Entity)import lombok.Data; import lombok.experimental.Accessors; @Data @Accessors(chain = true) public class User1Entity { private Integer id; private String username; private String password; }3.5 创建 Mapper 接口Mapper 接口用于定义 SQL 语句和数据库交互。import com.example.hikaridatasource.domain.entity.User1Entity; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface User1Mapper { @Select("SELECT * FROM user1") List<User1Entity> selectAllUsers(); }3.6 使用 Mapper测试自动注入Mapper代理对象的方式@SpringBootTest @Slf4j class HikariDataSourceApplicationTests { @Resource User1Mapper user1Mapper1; @Test void contextLoads() throws SQLException { List<User1Entity> user1List1Entity = user1Mapper1.selectAllUsers(); log.info("user1List1={}", user1List1Entity); } }2024-06-22T17:19:15.053+08:00 INFO 15316 --- [ main] c.e.h.HikariDataSourceApplicationTests : user1List1=[User1Entity(id=1, username=username1, password=password1), User1Entity(id=2, username=username1, password=password1), User1Entity(id=3, username=username1, password=password1), User1Entity(id=4, username=username1, password=password1), User1Entity(id=5, username=username1, password=password1)]通过SqlSessionTemplate手动获取Mapper代理对象的方式@SpringBootTest @Slf4j class HikariDataSourceApplicationTests { @Resource SqlSessionTemplate sqlSessionTemplate; @Test void contextLoads() throws SQLException { User1Mapper user1Mapper2 = sqlSessionTemplate.getMapper(User1Mapper.class); List<User1Entity> user1EntityList2 = user1Mapper2.selectAllUsers(); log.info("user1List2={}", user1EntityList2); } }2024-06-22T17:21:11.392+08:00 INFO 8368 --- [ main] c.e.h.HikariDataSourceApplicationTests : user1List2=[User1Entity(id=1, username=username1, password=password1), User1Entity(id=2, username=username1, password=password1), User1Entity(id=3, username=username1, password=password1), User1Entity(id=4, username=username1, password=password1), User1Entity(id=5, username=username1, password=password1)]参考资料MyBatis 入门介绍
2024年06月22日
11 阅读
0 评论
0 点赞
2024-06-16
SpringBoot默认数据源 HikariDataSource使用和配置及DataSource自动装配、手动装配
1.pom依赖 <!-- springboot基础依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>3.3.0</version> </dependency> <!-- mysql数据库连接驱动--> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> </dependency> <!-- 引入Spring封装的jdbc,内部默认依赖了 HikariDataSource 数据源--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>2.application.yml基本配置spring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: db1 password: db13.连接测试@SpringBootTest class HikariDataSourceApplicationTests { @Resource DataSource dataSource; @Test void contextLoads() throws SQLException { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); System.out.println("数据源>>>>>>" + dataSource.getClass()); System.out.println("连接>>>>>>>>" + connection); System.out.println("连接地址>>>>" + connection.getMetaData().getURL()); System.out.println("驱动名称>>>>" + metaData.getDriverName()); System.out.println("驱动版本>>>>" + metaData.getDriverVersion()); System.out.println("数据库名称>>" + metaData.getDatabaseProductName()); System.out.println("数据库版本>>" + metaData.getDatabaseProductVersion()); System.out.println("连接用户名称>" + metaData.getUserName()); connection.close(); } }数据源>>>>>>class com.zaxxer.hikari.HikariDataSource 连接>>>>>>>>HikariProxyConnection@902348321 wrapping com.mysql.cj.jdbc.ConnectionImpl@14998e21 连接地址>>>>jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai 驱动名称>>>>MySQL Connector/J 驱动版本>>>>mysql-connector-j-8.3.0 (Revision: 805f872a57875f311cb82487efcfb070411a3fa0) 数据库名称>>MySQL 数据库版本>>5.7.44-log 连接用户名称>db1@192.168.124.84.操作数据库测试数据库内容@SpringBootTest class HikariDataSourceApplicationTests { @Resource JdbcTemplate jdbcTemplate; @Test void contextLoads() throws SQLException { String sql = "select * from user1"; List<Map<String, Object>> selectRes = jdbcTemplate.queryForList(sql); System.out.println("selectRes="+selectRes); } } 5.数据源自动配置原理引入spring-boot-starter-data-jdbc后org.springframework.boot.autoconfigure.jdbc下定义的AutoConfiguration相关的类会触发DataSource、JdbcTemplate等的默认装配行为,会读取spring.datasource下的配置执行相关bean的装配引入spring-boot-starter-data-jdbc后不配置spring.datasource相关内容会导致如下异常*************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active). Process finished with exit code 1也可以通过在启动类来解除自动配置行为@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class HikariDataSourceApplication { public static void main(String[] args) { SpringApplication.run(HikariDataSourceApplication.class, args); } }org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration 数据源配置类作用是根据逻辑判断之后,添加数据源,内部配置了默认使用的数据源是类型是com.zaxxer.hikari.HikariDataSource可以通过 spring.datasource.type 指定自定义的数据源类型,如DruidDataSource对应的配置文件为spring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: db1 password: db1 type: com.alibaba.druid.pool.DruidDataSource使用该数据源需要引入相关依赖<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.22</version> </dependency>6.HikariDataSource数据源配置参数6.1 常用配置及含义Hikari的配置参数配置为spring.datasource.hikari.*形式。最常用的配置及其参数说明如下spring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: db1 password: db1 type: com.zaxxer.hikari.HikariDataSource hikari: # 连接池最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size minimum-idle: 10 # 连接池最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值。 maximum-pool-size: 20 # 连接最大存活时间,不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短 max-lifetime: 600000 # 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。 idle-timeout: 600000 # 连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒,如果在这个时间内无法建立连接,将会抛出异常。 connection-timeout: 300006.2 完整配置参数说明name描述构造器默认值默认配置validate之后的值validate重置autoCommit自动提交从池中返回的连接TRUETRUE–connectionTimeout等待来自池的连接的最大毫秒数SECONDS.toMillis(30) = 3000030000如果小于250毫秒,则被重置回30秒idleTimeout连接允许在池中闲置的最长时间MINUTES.toMillis(10) = 600000600000如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,则会被重置为0(代表永远不会退出);如果idleTimeout!=0且小于10秒,则会被重置为10秒maxLifetime池中连接最长生命周期MINUTES.toMillis(30) = 18000001800000如果不等于0且小于30秒则会被重置回30分钟connectionTestQuery如果您的驱动程序支持JDBC4,我们强烈建议您不要设置此属性nullnull–minimumIdle池中维护的最小空闲连接数-110minIdle<0或者minIdle>maxPoolSize,则被重置为maxPoolSizemaximumPoolSize池中最大连接数,包括闲置和使用中的连接-110如果maxPoolSize小于1,则会被重置。当minIdle<=0被重置为DEFAULT\_POOL\_SIZE则为10;如果minIdle>0则重置为minIdle的值metricRegistry该属性允许您指定一个 Codahale / Dropwizard MetricRegistry 的实例,供池使用以记录各种指标nullnull–healthCheckRegistry该属性允许您指定池使用的Codahale / Dropwizard HealthCheckRegistry的实例来报告当前健康信息nullnull–poolName连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置nullHikariPool-1–initializationFailTimeout如果池无法成功初始化连接,则此属性控制池是否将 fail fast11–isolateInternalQueries是否在其自己的事务中隔离内部池查询,例如连接活动测试FALSEFALSE–allowPoolSuspension控制池是否可以通过JMX暂停和恢复FALSEFALSE–readOnly从池中获取的连接是否默认处于只读模式FALSEFALSE–registerMbeans是否注册JMX管理Bean(MBeans)FALSEFALSE–catalog为支持 catalog 概念的数据库设置默认 catalogdriver defaultnull–connectionInitSql该属性设置一个SQL语句,在将每个新连接创建后,将其添加到池中之前执行该语句。nullnull–driverClassNameHikariCP将尝试通过仅基于jdbcUrl的DriverManager解析驱动程序,但对于一些较旧的驱动程序,还必须指定driverClassNamenullnull–transactionIsolation控制从池返回的连接的默认事务隔离级别nullnull–validationTimeout连接将被测试活动的最大时间量SECONDS.toMillis(5) = 50005000如果小于250毫秒,则会被重置回5秒leakDetectionThreshold记录消息之前连接可能离开池的时间量,表示可能的连接泄漏00如果大于0且不是单元测试,则进一步判断:(leakDetectionThreshold < SECONDS.toMillis(2) or (leakDetectionThreshold > maxLifetime && maxLifetime > 0),会被重置为0 . 即如果要生效则必须>0,而且不能小于2秒,而且当maxLifetime > 0时不能大于maxLifetimedataSource这个属性允许你直接设置数据源的实例被池包装,而不是让HikariCP通过反射来构造它nullnull–schema该属性为支持模式概念的数据库设置默认模式driver defaultnull–threadFactory此属性允许您设置将用于创建池使用的所有线程的java.util.concurrent.ThreadFactory的实例。nullnull–scheduledExecutor此属性允许您设置将用于各种内部计划任务的java.util.concurrent.ScheduledExecutorService实例nullnull–7.通过Config文件手动创建数据源配置取消自动配置行为@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class HikariDataSourceApplication { public static void main(String[] args) { SpringApplication.run(HikariDataSourceApplication.class, args); } }手动创建配置文件package com.example.hikaridatasource.config; import com.zaxxer.hikari.HikariDataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; @Configuration public class Db1DataSourceConfig { // jdbc连接信息 @Value(value = "${spring.datasource.url:}") private String url; @Value(value = "${spring.datasource.username:}") private String username; @Value(value = "${spring.datasource.password:}") private String password; @Value(value = "${spring.datasource.driver-class-name:}") private String driveClassName; // HikariDataSource配置参数 // 连接池最小空闲连接,默认值10 @Value(value = "${spring.datasource.hikari.minimum-idle:10}") private int minimumIdle; // 连接池最大连接数,默认值10 @Value(value = "${spring.datasource.hikari.maximum-pool-size:10}") private int maximumPoolSize; // 连接最大存活时间,默认值30分钟.设置应该比mysql设置的超时时间短,配置单位毫秒 @Value(value = "${spring.datasource.hikari.max-lifetime:600000}") private long maxLifetime; // 空闲连接超时时间,默认值600000(10分钟)配置单位毫秒 @Value(value = "${spring.datasource.hikari.idle-timeout:600000}") private long idleTimeout; // 连接超时时间,配置单位毫秒 @Value(value = "${spring.datasource.hikari.connection-timeout:60000}") private long connectionTimeout; @Bean(name = "db1DataSource") @Primary public DataSource db1DataSource(){ HikariDataSource dataSource = new HikariDataSource(); // 设置jdbc连接信息 dataSource.setJdbcUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setDriverClassName(driveClassName); // 设置HikariDataSource配置参数 dataSource.setMinimumIdle(minimumIdle); dataSource.setMaximumPoolSize(maximumPoolSize); dataSource.setMaxLifetime(maxLifetime); dataSource.setIdleTimeout(idleTimeout); dataSource.setConnectionTimeout(connectionTimeout); return dataSource; } @Bean(name = "db1JdbcTemplate") @Primary public JdbcTemplate db1JdbcTemplate(@Qualifier("db1DataSource") DataSource dataSource){ return new JdbcTemplate(dataSource); } }application.ymlspring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: db1 password: db1 type: com.zaxxer.hikari.HikariDataSource hikari: # 连接池最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size minimum-idle: 10 # 连接池最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值。 maximum-pool-size: 20 # 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。 idle-timeout: 600000 # 连接最大存活时间,不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短 max-lifetime: 600000 # 连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒,如果在这个时间内无法建立连接,将会抛出异常。 connection-timeout: 60000连接测试测试数据源@SpringBootTest class HikariDataSourceApplicationTests { @Resource DataSource dataSource; @Test void contextLoads() throws SQLException { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); System.out.println("数据源>>>>>>" + dataSource.getClass()); System.out.println("连接>>>>>>>>" + connection); System.out.println("连接地址>>>>" + connection.getMetaData().getURL()); System.out.println("驱动名称>>>>" + metaData.getDriverName()); System.out.println("驱动版本>>>>" + metaData.getDriverVersion()); System.out.println("数据库名称>>" + metaData.getDatabaseProductName()); System.out.println("数据库版本>>" + metaData.getDatabaseProductVersion()); System.out.println("连接用户名称>" + metaData.getUserName()); System.out.println("连接超时时间>" + dataSource.getLoginTimeout() + "s"); connection.close(); } }数据源>>>>>>class com.zaxxer.hikari.HikariDataSource 连接>>>>>>>>HikariProxyConnection@42898626 wrapping com.mysql.cj.jdbc.ConnectionImpl@62b790a5 连接地址>>>>jdbc:mysql://192.168.124.10:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai 驱动名称>>>>MySQL Connector/J 驱动版本>>>>mysql-connector-j-8.3.0 (Revision: 805f872a57875f311cb82487efcfb070411a3fa0) 数据库名称>>MySQL 数据库版本>>5.7.44-log 连接用户名称>db1@192.168.124.8 连接超时时间>60s操作数据源测试@SpringBootTest class HikariDataSourceApplicationTests { @Resource JdbcTemplate jdbcTemplate; @Test void contextLoads() throws SQLException { String sql = "select * from user1"; List<Map<String, Object>> selectRes = jdbcTemplate.queryForList(sql); System.out.println("selectRes="+selectRes); } }selectRes=[{username=username1, password=password1, id=1}, {username=username1, password=password1, id=2}, {username=username1, password=password1, id=3}, {username=username1, password=password1, id=4}, {username=username1, password=password1, id=5}]参考资料Spring Boot 如何通过jdbc+HikariDataSource 完成对Mysql 操作_hikaridatasource mysql-CSDN博客Spring Boot 默认数据源 HikariDataSource 与 JdbcTemplate 初遇-CSDN博客SpringBoot - 数据源注入 及其 自动配置原理_springboot 注入datasource-CSDN博客Spring Boot 2.x基础教程:默认数据源Hikari的配置详解 - 程序猿DD - 博客园 (cnblogs.com)Spring Boot 如何通过jdbc+HikariDataSource 完成对Mysql 操作_hikaridatasource mysql-CSDN博客
2024年06月16日
15 阅读
0 评论
0 点赞
2024-06-02
SpringBoot集成Nacos作为配置中心
1.Nacos安装参考:docker快速部署nacos - jupiter's blog (inat.top)2.SpringBoot集成Nacos作为配置中心2.1 引入依赖必要依赖 <!--nacos配置中心--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2023.0.1.0</version> </dependency> <!-- spring-cloud-starter-bootstrap --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> <version>4.1.2</version> </dependency>JSON转换依赖(测试用,可选)<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.28</version> </dependency>2.2 nacos新建命名空间和配置文件配置文件内容# 注入字符串 stringConfig: nacosStringConfig # 注入数组 arrayConfig: aaa,bbb,ccc # 注入list listConfig: aaa,bbb,ccc2.3 bootstrap.yml增加配置spring: cloud: nacos: username: nacos password: nacos123 config: namespace: 4ee219bc-2c01-4598-9719-bec80a57ce2f server-addr: 192.168.124.10:8848 extension-configs: - {data-id: "project-basic.yaml", group: "dev", refresh: "true"}2.4 配置映射类import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; import java.util.List; @Component @RefreshScope @Data public class ProjectBasicConfig { @Value("${stringConfig:}") private String stringConfig; @Value("${arrayConfig:}") private String[] arrayConfig; @Value("#{'${listConfig:}'.empty ? null : '${listConfig:}'.split(',')}") private List<String> listConfig; }2.5 配置映射使用测试@RestController public class TestController { @Resource private ProjectBasicConfig projectBasicConfig; @GetMapping("/") public String testNacosConfig() { return "stringConfig=" + projectBasicConfig.getStringConfig() + ",arrayConfig=" + JSONUtil.toJsonStr(projectBasicConfig.getArrayConfig()) + ",listConfig=" +JSONUtil.toJsonStr(projectBasicConfig.getListConfig()); } }2.6 启动访问测试参考资料Nacos 融合 Spring Boot,成为注册配置中心 | NacosSpringBoot整合nacos实现配置中心(配置动态更新) - yvioo - 博客园 (cnblogs.com)SpringCloudAlibaba:Nacos配置的多文件加载与共享配置_nacos多文件配置-CSDN博客
2024年06月02日
28 阅读
0 评论
0 点赞
2024-05-19
nginx配置详解和示例
1.nginx默认配置文件Nginx默认的配置文件是在安装目录下的 conf目录下,后续对 Nginx的使用基本上都是对此配置文件进行相应的修改,修改过nginx.conf配置文件,记得要重启Nginx服务(☆☆☆☆☆)默认的配置文件内容(其中#开头的都是被注释了的内容):#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }2.nginx配置文件配置详解nginx配置文件主要分为如下三部分2.1 全局块全局块是默认配置文件从开始到events块之间的内容。主要设置nginx整体运行的配置指令,这些指令的作用域是全局,配置案例解析#定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数。 worker_processes 8; #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ] error_log /usr/local/nginx/logs/error.log info; #进程pid文件 pid /usr/local/nginx/logs/nginx.pid; #指定进程可以打开的最大描述符:数目 #工作模式与连接数上限 #这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致。 #现在在linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535。 #这是因为nginx调度时分配请求到进程并不是那么的均衡,所以假如填写10240,总并发量达到3-4万时就有进程可能超过10240了,这时会返回502错误。 worker_rlimit_nofile 65535;2.2 events块events块的指令主要影响nginx服务器和用户的网络连接,对性能影响较大。配置案例:events { #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型 #是Linux 2.6以上版本内核中的高性能网络I/O模型,linux建议epoll,如果跑在FreeBSD上面,就用kqueue模型。 #补充说明: #与apache相类,nginx针对不同的操作系统,有不同的事件模型 #A)标准事件模型 #Select、poll属于标准事件模型,如果当前系统不存在更有效的方法,nginx会选择select或poll #B)高效事件模型 #Kqueue:使用于FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X.使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。 #Epoll:使用于Linux内核2.6版本及以后的系统。 #/dev/poll:使用于Solaris 7 11/99+,HP/UX 11.22+ (eventport),IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+。 #Eventport:使用于Solaris 10。 为了防止出现内核崩溃的问题, 有必要安装安全补丁。 use epoll; #单个进程最大连接数(最大连接数=连接数*进程数) #根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。每个进程允许的最多连接数,理论上每台nginx服务器的最大连接数为。 worker_connections 65535; #keepalive超时时间。 keepalive_timeout 60; #客户端请求头部的缓冲区大小。这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。 #分页大小可以用命令getconf PAGESIZE 取得。 #[root@web001 ~]# getconf PAGESIZE #4096 #但也有client_header_buffer_size超过4k的情况,但是client_header_buffer_size该值必须设置为“系统分页大小”的整倍数。 client_header_buffer_size 4k; #这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。 open_file_cache max=65535 inactive=60s; #这个是指多长时间检查一次缓存的有效信息。 #语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了何时需要检查open_file_cache中缓存项目的有效信息. open_file_cache_valid 80s; #open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive时间内一次没被使用,它将被移除。 #语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1 使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如果使用更大的值,文件描述符在cache中总是打开状态. open_file_cache_min_uses 1; #语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件时记录cache错误. open_file_cache_errors on; }常用到的配置案例:events { # events块开始 worker_connections 1024; #每个工作进程的最大连接数量(根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。) use epoll; # 使用epoll的I/O 模型。linux建议epoll,FreeBSD建议采用kqueue,window下不指定。 accept_mutex on; #开启网络连接的序列化(防止多个进程对连接的争抢) multi_accept on; #允许同时接收多个网络连接(默认关闭),工作进程都有能力同时接收多个新到达的网络连接 } 2.3 http块这部分是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。需要注意的是:http 块也可以包括 http 全局块、server 块。下面的反向代理、动静分离、负载均衡都是在这部分中配置http 全局块:http 全局块配置的指令包括:文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。server 块:这块和虚拟主机有密切关系,从用户角度看,虚拟主机和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本。每个http块可以包括多个server块,而每个server块就相当于一个虚拟主机。每个server块也分为全局server块,以及可以同时包含多个locaton块。2.3.1 http块全局配置配置案例:#文件扩展名与文件类型映射表 include mime.types; #默认文件类型 default_type application/octet-stream; #默认编码 #charset utf-8; #设定通过nginx上传文件的大小 client_max_body_size 8m; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。 #sendfile指令指定 nginx 是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度,降低系统uptime。 sendfile on; #开启目录列表访问,合适下载服务器,默认关闭。 autoindex on; # 负载均衡服务器组配置 upstream backend { server 127.0.0.1:8081 max_fails=2 fail_timeout=10s; server 127.0.0.1:8082 max_fails=2 fail_timeout=10s; # 可选的其他参数 # least_conn; # 使用最少连接的服务器 # ip_hash; # 根据客户端IP进行哈希,确保来自同一IP的请求总是发送到同一台服务器 # keepalive 32; # 每个worker进程保持的最大空闲连接数 }2.3.2 http块下的server块server块 必须包含在http之下。server是一切的开始,代表一个代理的出现,里边两大配置项:listen监听接口和server_name监听的地址,里边还包括了location和其它配置项,当存在server的时候,nginx获取到的请求都会去匹配这些server(匹配其中的listen和server_name)。server也可单独拆分为一个文件 在nginx下http块下引用即可location是nginx的精华,nginx就是通过拦截到的请求去对配置好的location块进行请求代理的。alias&root:将请求代理到本地的指令,也就是如果可以把请求发送到你的 硬盘里去获取资源,这个指令可以代理前端的静态资源proxy_pass:对请求进行转发重定向的rewrite:用来重写请求路径配置案例:server { listen 80; server_name localhost; location / { root html/dist; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # 反向代理+负载均衡配置 location /api/ { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_http_version 1.1; } location /upload/ { proxy_pass http://backend; } # 请求日志按天/按小时/按分钟/按秒分割 if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") { set $year $1; set $month $2; set $day $3; set $hour $4; set $minutes $5; set $seconds $6; } access_log ./logs/nginx-access_$year-$month-$day.log; # 错误日志配置 error_log ./logs/nginx-access-error.log; }3.nginx 反向代理配置通过server>location>proxy_pass属性生效:server { listen 80; server_name localhost; location / { proxy_pass http://127.0.0.1:8080 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_http_version 1.1; } }还可以针对单个子路径进行反向代理配置server { listen 9001; server_name localhost; location ~ /edu/ { proxy_pass http://127.0.0.1:8080 } location ~ /vod/ { proxy_pass http://127.0.0.1:8081 } }4.nginx负责均衡配置通过http块下的upstream属性进行配置实现http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream backend { server 127.0.0.1:8081 max_fails=2 fail_timeout=10s; server 127.0.0.1:8082 max_fails=2 fail_timeout=10s; # 可选的其他参数 # least_conn; # 使用最少连接的服务器 # ip_hash; # 根据客户端IP进行哈希,确保来自同一IP的请求总是发送到同一台服务器 # keepalive 32; # 每个worker进程保持的最大空闲连接数 } server { listen 80; server_name localhost; location / { root html/dist; index index.html index.htm; } location /api/ { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_http_version 1.1; } location /upload/ { proxy_pass http://backend; } } } 5.nginx 负载均衡分配服务器策略5.1 轮询(默认)每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。upstream myserver { server 127.0.0.1:8081; server 127.0.0.1:8082; } server { listen 80; server_name 127.0.0.1; location / { root html; proxy_pass http://myserver; index index.html index.htm; } }5.2 weightweight 代表权重, 默认为 1,权重越高被分配的客户端越多upstream myserver { server 127.0.0.1:8081 weight=10; server 127.0.0.1:8082 weight=10; } server { listen 80; server_name 127.0.0.1; location / { root html; proxy_pass http://myserver; index index.html index.htm; } }5.3 ip_haship_hash 每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器upstream myserver { server 127.0.0.1:8081; server 127.0.0.1:8082; ip_hash; } server { listen 80; server_name 127.0.0.1; location / { root html; proxy_pass http://myserver; index index.html index.htm; } }5.4 fair(第三方)fair(第三方),按后端服务器的响应时间来分配请求,响应时间短的优先分配。upstream myserver { server 127.0.0.1:8081; server 127.0.0.1:8082; fair; } server { listen 80; server_name 127.0.0.1; location / { root html; proxy_pass http://myserver; index index.html index.htm; } }6.nginx日志分割配置server { listen 80; server_name 127.0.0.1; location / { root html; index index.html index.htm; } # 请求日志按天/按小时/按分钟/按秒分割 if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") { set $year $1; set $month $2; set $day $3; set $hour $4; set $minutes $5; set $seconds $6; } access_log ./logs/nginx-access_$year-$month-$day.log; # 错误日志配置 error_log ./logs/nginx-access-error.log; }参考资料Nginx反向代理配置去除前缀-百度开发者中心 (baidu.com)Nginx 负载均衡演示之 upstream 参数 & location 参数 - 知乎 (zhihu.com)Nginx--upstream健康检查 - 心恩惠动 - 博客园 (cnblogs.com)nginx日志切割/分割,按天生成&定期删除日志_nginx 日志按天切割-CSDN博客nginx学习,看这一篇就够了:下载、安装。使用:正向代理、反向代理、负载均衡。常用命令和配置文件,很全-CSDN博客Nginx——访问日志、错误日志、日志文件切割_nginx错误日志文件太大了怎么办-CSDN博客一文理清nginx中的location配置(系列一) - 知乎 (zhihu.com)全网最全最完整Nginx 配置文件nginx.conf中文详解-CSDN博客nginx 配置相关详解_nginx 配置详解-CSDN博客Nginx配置——反向代理_nginx反向代理-CSDN博客
2024年05月19日
43 阅读
0 评论
0 点赞
2024-05-16
docker快速部署Redis
下载镜像docker pull redis创建配置文件mkdir -p /data/redis/data ## 创建文件 vim /data/redis/redis.conf# 配置文件内容 appendonly yes protected-mode no bind 0.0.0.0 requirepass 密码命令功能appendonly yes启动Redis持久化功能 (默认 no , 所有信息都存储在内存 [重启丢失] 。 设置为 yes , 将存储在硬盘 [重启还在])protected-mode no关闭protected-mode模式,此时外部网络可以直接访问 (docker貌似自动开启了)bind 0.0.0.0设置所有IP都可以访问 (docker貌似自动开启了)requirepass 密码设置密码创建Redis容器并启动docker run \ --name redis \ -p 6379:6379 \ --restart unless-stopped \ -v /data/redis/data:/data \ -v /data/redis/redis.conf:/etc/redis/redis.conf \ -d redis \ redis-server /etc/redis/redis.conf进入Redis容器测试[root@centeros7 redis]# docker exec -it redis /bin/bash root@8b4424c8a4e8:/data# redis-cli 127.0.0.1:6379> auth redis OK 127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379>参考资料Docker 安装 Redis 容器 (完整详细版)_docker redis-CSDN博客Docker 安装 Redis - 犬小哈教程 (quanxiaoha.com)
2024年05月16日
11 阅读
0 评论
0 点赞
2024-05-15
SpringBoot RabbitMQ配置多vhost/多RabbitMQ实例+解决Exchange/Queue在vhost之间扩散造成交换机队列重复
1.添加maven依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>2.配置文件配置RabbitMQ连接信息:server: port: 8201 spring: application: name: RabbitMQ rabbitmq: vhost1: host: 192.168.124.10 port: 5672 username: user1 password: user1 virtual-host: /vhost1 vhost2: host: 192.168.124.10 port: 5672 username: user2 password: user2 virtual-host: /vhost23.RabbitMQConfig配置3.1 RabbitConstantpackage com.example.rabbitmq.config; public class RabbitConstant { // region vhost1 ConnectionFactory.RabbitTemplate.RabbitAdmin配置 public static final String VHOST_1_CONNECTION_FACTORY = "vhost1ConnectionFactory"; public static final String VHOST_1_RABBIT_LISTENER_CONTAINER_FACTORY = "vhost1RabbitListenerContainerFactory"; public static final String VHOST_1_RABBIT_TEMPLATE = "vhost1RabbitTemplate"; public static final String VHOST_1_RABBIT_ADMIN = "vhost1RabbitAdmin"; // endregion // region vhost2 ConnectionFactory.RabbitTemplate.RabbitAdmin配置 public static final String VHOST_2_CONNECTION_FACTORY = "vhost2ConnectionFactory"; public static final String VHOST_2_RABBIT_LISTENER_CONTAINER_FACTORY = "vhost2RabbitListenerContainerFactory"; public static final String VHOST_2_RABBIT_TEMPLATE = "vhost2RabbitTemplate"; public static final String VHOST_2_RABBIT_ADMIN = "vhost2RabbitAdmin"; // endregion // region vhost1 测试交换机.队列.路由配置 public static final String VHOST_1_TEST_EXCHANGE_1 = "vhost1TestExchange1"; public static final String VHOST_1_TEST_EXCHANGE_2 = "vhost1TestExchange2"; public static final String VHOST_1_TEST_EXCHANGE_1_QUEUE_1 = "vhost1TestExchange1Queue1"; public static final String VHOST_1_TEST_EXCHANGE_1_ROUTING_KEY_1 = "vhost1TestExchange1RoutingKey1"; public static final String VHOST_1_TEST_EXCHANGE_2_QUEUE_1 = "vhost1TestExchange2Queue1"; public static final String VHOST_1_TEST_EXCHANGE_2_ROUTING_KEY_1 = "vhost1TestExchange2RoutingKey1"; // endregion // region vhost2 测试交换机.队列.路由配置 public static final String VHOST_2_TEST_EXCHANGE_1 = "vhost2TestExchange1"; public static final String VHOST_2_TEST_EXCHANGE_2 = "vhost2TestExchange2"; public static final String VHOST_2_TEST_EXCHANGE_1_QUEUE_1 = "vhost2TestExchange1Queue1"; public static final String VHOST_2_TEST_EXCHANGE_1_ROUTING_KEY_1 = "vhost2TestExchange1RoutingKey1"; public static final String VHOST_2_TEST_EXCHANGE_2_QUEUE_1 = "vhost2TestExchange2Queue1"; public static final String VHOST_2_TEST_EXCHANGE_2_ROUTING_KEY_1 = "vhost2TestExchange2RoutingKey1"; // endregion }3.2 Vhost1RabbitMQConfigpackage com.example.rabbitmq.config; import org.springframework.amqp.core.AcknowledgeMode; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class Vhost1RabbitMQConfig { @Value("${spring.rabbitmq.vhost1.host}") private String host; @Value("${spring.rabbitmq.vhost1.port}") private int port; @Value("${spring.rabbitmq.vhost1.username}") private String username; @Value("${spring.rabbitmq.vhost1.password}") private String password; @Value("${spring.rabbitmq.vhost1.virtual-host}") private String vhost; // 为vhost1配置ConnectionFactory @Bean(name = RabbitConstant.VHOST_1_CONNECTION_FACTORY) @Primary public ConnectionFactory vhost1ConnectionFactory() { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port); connectionFactory.setUsername(username); connectionFactory.setPassword(password); connectionFactory.setVirtualHost(vhost); return connectionFactory; } // 为vhost1配置SimpleRabbitListenerContainerFactory @Bean(name = RabbitConstant.VHOST_1_RABBIT_LISTENER_CONTAINER_FACTORY) @Primary public SimpleRabbitListenerContainerFactory vhost1RabbitListenerContainerFactory( @Qualifier(RabbitConstant.VHOST_1_CONNECTION_FACTORY)ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); return factory; } // 为vhost1配置RabbitTemplate @Bean(name = RabbitConstant.VHOST_1_RABBIT_TEMPLATE) @Primary public RabbitTemplate vhost1RabbitTemplate( @Qualifier(RabbitConstant.VHOST_1_CONNECTION_FACTORY) ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); // 可以设置其他属性,如消息转换器 return rabbitTemplate; } // 为vhost1配置RabbitAdmin @Bean(name = RabbitConstant.VHOST_1_RABBIT_ADMIN) @Primary public RabbitAdmin vhost1RabbitAdmin( @Qualifier(RabbitConstant.VHOST_1_CONNECTION_FACTORY) ConnectionFactory connectionFactory) { RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); rabbitAdmin.setAutoStartup(true); return rabbitAdmin; } }3.3 Vhost2RabbitMQConfigpackage com.example.rabbitmq.config; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class Vhost2RabbitMQConfig { @Value("${spring.rabbitmq.vhost2.host}") private String host; @Value("${spring.rabbitmq.vhost2.port}") private int port; @Value("${spring.rabbitmq.vhost2.username}") private String username; @Value("${spring.rabbitmq.vhost2.password}") private String password; @Value("${spring.rabbitmq.vhost2.virtual-host}") private String vhost; // 为vhost2配置ConnectionFactory @Bean(name = RabbitConstant.VHOST_2_CONNECTION_FACTORY) public ConnectionFactory vhost2ConnectionFactory() { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port); connectionFactory.setUsername(username); connectionFactory.setPassword(password); connectionFactory.setVirtualHost(vhost); return connectionFactory; } // 为vhost2配置SimpleRabbitListenerContainerFactory @Bean(name = RabbitConstant.VHOST_2_RABBIT_LISTENER_CONTAINER_FACTORY) public SimpleRabbitListenerContainerFactory vhost2RabbitListenerContainerFactory( @Qualifier(RabbitConstant.VHOST_2_CONNECTION_FACTORY)ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); return factory; } // 为vhost2配置RabbitTemplate @Bean(name = RabbitConstant.VHOST_2_RABBIT_TEMPLATE) public RabbitTemplate vhost2RabbitTemplate( @Qualifier(RabbitConstant.VHOST_2_CONNECTION_FACTORY) ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); // 可以设置其他属性,如消息转换器 return rabbitTemplate; } // 为vhost2配置RabbitAdmin @Bean(name = RabbitConstant.VHOST_2_RABBIT_ADMIN) public RabbitAdmin vhost2RabbitAdmin( @Qualifier(RabbitConstant.VHOST_2_CONNECTION_FACTORY) ConnectionFactory connectionFactory) { RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); rabbitAdmin.setAutoStartup(true); return rabbitAdmin; } }4.消费者其中 @QueueBinding下的admins=的配置是交换机和队列数据不会在vhost之间扩散的必要条件4.1 Vhost1Consumerpackage com.example.rabbitmq.consumer; import com.example.rabbitmq.config.RabbitConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.ExchangeTypes; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component @Slf4j public class Vhost1Consumer { @RabbitListener( containerFactory = RabbitConstant.VHOST_1_RABBIT_LISTENER_CONTAINER_FACTORY, bindings = @QueueBinding( value = @Queue(value = RabbitConstant.VHOST_1_TEST_EXCHANGE_1_QUEUE_1, admins = RabbitConstant.VHOST_1_RABBIT_ADMIN), exchange = @Exchange(value = RabbitConstant.VHOST_1_TEST_EXCHANGE_1, type = ExchangeTypes.TOPIC, admins = RabbitConstant.VHOST_1_RABBIT_ADMIN), key = RabbitConstant.VHOST_1_TEST_EXCHANGE_1_ROUTING_KEY_1, admins = RabbitConstant.VHOST_1_RABBIT_ADMIN) ) public void vhost1Exchang1Queue1Consumer(String message) { log.info("vhost1 exchange1 queue1 consumer meaasge: {}", message); } @RabbitListener( containerFactory = RabbitConstant.VHOST_1_RABBIT_LISTENER_CONTAINER_FACTORY, bindings = @QueueBinding( value = @Queue(value = RabbitConstant.VHOST_1_TEST_EXCHANGE_2_QUEUE_1, admins = RabbitConstant.VHOST_1_RABBIT_ADMIN), exchange = @Exchange(value = RabbitConstant.VHOST_1_TEST_EXCHANGE_2, type = ExchangeTypes.TOPIC, admins = RabbitConstant.VHOST_1_RABBIT_ADMIN), key = RabbitConstant.VHOST_1_TEST_EXCHANGE_2_ROUTING_KEY_1, admins = RabbitConstant.VHOST_1_RABBIT_ADMIN)) public void vhost1Exchang2Queue1Consumer(String message) { log.info("vhost1 exchange2 queue1 consumer meaasge: {}", message); } }4.2 Vhost2Consumerpackage com.example.rabbitmq.consumer; import com.example.rabbitmq.config.RabbitConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.ExchangeTypes; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component @Slf4j public class Vhost2Consumer { @RabbitListener( containerFactory = RabbitConstant.VHOST_2_RABBIT_LISTENER_CONTAINER_FACTORY, bindings = @QueueBinding( value = @Queue(value = RabbitConstant.VHOST_2_TEST_EXCHANGE_1_QUEUE_1, admins = RabbitConstant.VHOST_2_RABBIT_ADMIN), exchange = @Exchange(value = RabbitConstant.VHOST_2_TEST_EXCHANGE_1, type = ExchangeTypes.TOPIC, admins = RabbitConstant.VHOST_2_RABBIT_ADMIN), key = RabbitConstant.VHOST_2_TEST_EXCHANGE_1_ROUTING_KEY_1, admins = RabbitConstant.VHOST_2_RABBIT_ADMIN) ) public void vhost2Exchang1Queue1Consumer(String message) { log.info("vhost2 exchange1 queue1 consumer meaasge: {}", message); } @RabbitListener( containerFactory = RabbitConstant.VHOST_2_RABBIT_LISTENER_CONTAINER_FACTORY, bindings = @QueueBinding( value = @Queue(value = RabbitConstant.VHOST_2_TEST_EXCHANGE_2_QUEUE_1, admins = RabbitConstant.VHOST_2_RABBIT_ADMIN), exchange = @Exchange(value = RabbitConstant.VHOST_2_TEST_EXCHANGE_2, type = ExchangeTypes.TOPIC, admins = RabbitConstant.VHOST_2_RABBIT_ADMIN), key = RabbitConstant.VHOST_2_TEST_EXCHANGE_2_ROUTING_KEY_1, admins = RabbitConstant.VHOST_2_RABBIT_ADMIN)) public void vhost2Exchang2Queue1Consumer(String message) { log.info("vhost2 exchange2 queue1 consumer meaasge: {}", message); } }5.生产者ProducerControllerpackage com.example.rabbitmq.producer; import com.example.rabbitmq.config.RabbitConstant; import jakarta.annotation.Resource; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/") public class ProducerController { @Resource(name = RabbitConstant.VHOST_1_RABBIT_TEMPLATE) RabbitTemplate vhost1RabbitTemplate; @Resource(name = RabbitConstant.VHOST_2_RABBIT_TEMPLATE) RabbitTemplate vhost2RabbitTemplate; @GetMapping("/") public String index() { return "rabbitmq study index"; } @GetMapping("/produceVhost1Exchange1Message") public String produceVhost1Exchange1Message() { String content1 = "vhost1 exchange1 message " + System.currentTimeMillis(); vhost1RabbitTemplate.convertAndSend( RabbitConstant.VHOST_1_TEST_EXCHANGE_1, RabbitConstant.VHOST_1_TEST_EXCHANGE_1_ROUTING_KEY_1, content1); return content1 + " send success"; } @GetMapping("/produceVhost1Exchange2Message") public String produceVhost1Exchange2Message() { String content1 = "vhost1 exchange2 message " + System.currentTimeMillis(); vhost1RabbitTemplate.convertAndSend( RabbitConstant.VHOST_1_TEST_EXCHANGE_2, RabbitConstant.VHOST_1_TEST_EXCHANGE_2_ROUTING_KEY_1, content1); return content1 + " send success"; } @GetMapping("/produceVhost2Exchange1Message") public String produceVhost2Exchange1Message() { String content1 = "vhost2 exchange1 message " + System.currentTimeMillis(); vhost2RabbitTemplate.convertAndSend( RabbitConstant.VHOST_2_TEST_EXCHANGE_1, RabbitConstant.VHOST_2_TEST_EXCHANGE_1_ROUTING_KEY_1, content1); return content1 + "send success "; } @GetMapping("/produceVhost2Exchange2Message") public String produceVhost2Exchange2Message() { String content1 = "vhost2 exchange2 message " + System.currentTimeMillis(); vhost2RabbitTemplate.convertAndSend( RabbitConstant.VHOST_2_TEST_EXCHANGE_2, RabbitConstant.VHOST_2_TEST_EXCHANGE_2_ROUTING_KEY_1, content1); return content1 + "send success "; } }6.启动测试日志 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.2.5) 2024-05-15T23:12:32.832+08:00 INFO 20956 --- [RabbitMQ] [ main] c.example.rabbitmq.RabbitMqApplication : Starting RabbitMqApplication using Java 17.0.8 with PID 20956 (C:\Users\vin\Desktop\WorkSpace\StudyProject\RabbitMQ\target\classes started by vin in C:\Users\vin\Desktop\WorkSpace\StudyProject) 2024-05-15T23:12:32.834+08:00 INFO 20956 --- [RabbitMQ] [ main] c.example.rabbitmq.RabbitMqApplication : No active profile set, falling back to 1 default profile: "default" 2024-05-15T23:12:33.401+08:00 INFO 20956 --- [RabbitMQ] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8201 (http) 2024-05-15T23:12:33.408+08:00 INFO 20956 --- [RabbitMQ] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-05-15T23:12:33.408+08:00 INFO 20956 --- [RabbitMQ] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.20] 2024-05-15T23:12:33.438+08:00 INFO 20956 --- [RabbitMQ] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-05-15T23:12:33.439+08:00 INFO 20956 --- [RabbitMQ] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 577 ms 2024-05-15T23:12:33.738+08:00 INFO 20956 --- [RabbitMQ] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8201 (http) with context path '' 2024-05-15T23:12:33.740+08:00 INFO 20956 --- [RabbitMQ] [ main] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: 192.168.124.10:5672 2024-05-15T23:12:33.764+08:00 INFO 20956 --- [RabbitMQ] [ main] o.s.a.r.c.CachingConnectionFactory : Created new connection: vhost1ConnectionFactory#6af91cc8:0/SimpleConnection@7bee8621 [delegate=amqp://user1@192.168.124.10:5672//vhost1, localPort=3708] 2024-05-15T23:12:33.789+08:00 INFO 20956 --- [RabbitMQ] [ main] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: 192.168.124.10:5672 2024-05-15T23:12:33.791+08:00 INFO 20956 --- [RabbitMQ] [ main] o.s.a.r.c.CachingConnectionFactory : Created new connection: vhost2ConnectionFactory#43acd79e:0/SimpleConnection@385d819 [delegate=amqp://user2@192.168.124.10:5672//vhost2, localPort=3709] 2024-05-15T23:12:33.800+08:00 INFO 20956 --- [RabbitMQ] [ main] c.example.rabbitmq.RabbitMqApplication : Started RabbitMqApplication in 1.212 seconds (process running for 1.512) 2024-05-15T23:13:00.260+08:00 INFO 20956 --- [RabbitMQ] [nio-8201-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2024-05-15T23:13:00.261+08:00 INFO 20956 --- [RabbitMQ] [nio-8201-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2024-05-15T23:13:00.261+08:00 INFO 20956 --- [RabbitMQ] [nio-8201-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms 2024-05-15T23:13:00.315+08:00 INFO 20956 --- [RabbitMQ] [ntContainer#0-1] c.e.rabbitmq.consumer.Vhost1Consumer : vhost1 exchange1 queue1 consumer meaasge: vhost1 exchange1 message 1715785980295 2024-05-15T23:13:04.012+08:00 INFO 20956 --- [RabbitMQ] [ntContainer#1-1] c.e.rabbitmq.consumer.Vhost1Consumer : vhost1 exchange2 queue1 consumer meaasge: vhost1 exchange2 message 1715785984008 2024-05-15T23:13:09.439+08:00 INFO 20956 --- [RabbitMQ] [ntContainer#2-1] c.e.rabbitmq.consumer.Vhost2Consumer : vhost2 exchange1 queue1 consumer meaasge: vhost2 exchange1 message 1715785989435 2024-05-15T23:13:15.260+08:00 INFO 20956 --- [RabbitMQ] [ntContainer#3-1] c.e.rabbitmq.consumer.Vhost2Consumer : vhost2 exchange2 queue1 consumer meaasge: vhost2 exchange2 message 1715785995257参考资料SpringBoot RabbitMQ配置多vhost/多RabbitMQ实例方案_rabbitmq springboot消费多个vhost-CSDN博客SpringBoot连接多RabbitMQ源 - 知乎 (zhihu.com)@QueueBinding RabbitMQ 多数据源 队列重复-CSDN博客【MQ系列】RabbitListener消费基本使用姿势介绍 | 一灰灰Blog (hhui.top)
2024年05月15日
18 阅读
0 评论
0 点赞
2024-05-10
docker快速部署nacos
注意Nacos是一个内部微服务组件,需要在可信的内部网络中运行,不可暴露在公网环境,防止带来安全风险。Nacos提供简单的鉴权实现,为防止业务错用的弱鉴权体系,不是防止恶意攻击的强鉴权体系。如果运行在不可信的网络环境或者有强鉴权诉求,请参考官方简单实现做进行自定义插件开发。1.单机模式 DerbyDocker 拉取镜像docker pull nacos/nacos-server启动nacos# 不开启鉴权 docker run -d \ --name nacos \ -p 8848:8848 -p 9848:9848 \ -e MODE=standalone \ nacos/nacos-server访问页面:http://192.168.124.10:8848/nacos/2.单机模式mysql+宿主机配置文件映射启动Docker 拉取镜像docker pull nacos/nacos-servermysql中创建nacos所需的表mysql中新建一个库,名字可自定义,这里就用nacos从github中找到创建表的文件,在nacos-config库中执行,创建所需的表创建配置文件的保存目录mkdir -p /data/nacos/logs/ #新建logs目录 mkdir -p /data/nacos/conf/ #新建conf目录将nacos里面的文件拷贝出到挂载目录中# 启动容器 docker run -p 8848:8848 --name nacos -d nacos/nacos-server# 复制文件 docker cp nacos:/home/nacos/logs/ /data/nacos/ docker cp nacos:/home/nacos/conf/ /data/nacos/# 删除并关闭容器 docker rm -f nacos再次启动nacosdocker run -d \ --name nacos \ -p 8848:8848 -p 9848:9848 -p 9849:9849 \ --privileged=true \ -e MODE=standalone \ -v /data/nacos/logs/:/home/nacos/logs/ \ -v /data/nacos/conf/:/home/nacos/conf/ \ nacos/nacos-server修改配置文件-application.properties# 在宿主机中修改application.properties文件 vim /data/nacos/conf/application.propertiesspring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://192.168.124.10:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=30000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=nacos db.password=nacos访问页面:http://192.168.124.10:8848/nacos/3.开启登录验证修改配置文件-application.properties# 在宿主机中修改application.properties文件 vim /data/nacos/conf/application.properties# 开启登录验证 nacos.core.auth.enabled=true nacos.core.auth.server.identity.key=serverIdentity nacos.core.auth.server.identity.value=security # 自定义指定生成JWT的密钥,使用BASE64进行编码,编码前的key长度必须不小于32个字符 nacos.core.auth.plugin.nacos.token.secret.key=NzRmNzRiMGE3OTk5M2ZmOGQyOThhYzgwYWEyZjk4M2MxZTBlMjIyN2YyNGIwOWQzNGQwNGNiYjNiODRlYzQ4ZQ==nacos.core.auth.plugin.nacos.token.secret.key生成步骤:1、使用openssl rand -hex 32获取密钥值[root@centeros7 docker-test]# openssl rand -hex 32 74f74b0a79993ff8d298ac80aa2f983c1e0e2227f24b09d34d04cbb3b84ec48e2、将密钥值再进行base编码访问:https://base64.us/,输入密钥进行base64编码NzRmNzRiMGE3OTk5M2ZmOGQyOThhYzgwYWEyZjk4M2MxZTBlMjIyN2YyNGIwOWQzNGQwNGNiYjNiODRlYzQ4ZQ==参考资料Nacos部署(三)Docker部署Nacos2.3单机环境_nacos 2.3.2镜像-CSDN博客如何使用Docker部署Nacos服务?Nacos Docker 快速部署指南: 一站式部署与配置教程-腾讯云开发者社区-腾讯云 (tencent.com)
2024年05月10日
24 阅读
0 评论
0 点赞
2024-04-22
Java日志体系和springboot日志配置
1.日志框架的分类1.1 门面型日志框架日志门面定义了一组日志的接口规范,它并不提供底层具体的实现逻辑。JCL:Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons LoggingSLF4J:是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)1.2 记录型日志框架日志实现则是日志具体的实现,包括日志级别控制、日志打印格式、日志输出形式(输出到数据库、输出到文件、输出到控制台等)。Jul (Java Util Logging):JDK中的日志记录工具,也常称为JDKLog、jdk-logging,自Java1.4以来的官方日志实现。Log4j:Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。Log4j2:一个具体的日志实现框架,是Log4j 1的下一个版本,与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1。Logback:一个具体的日志实现框架,和Slf4j是同一个作者,但其性能更好(推荐使用)。将日志门面和日志实现分离其实是一种典型的门面模式,这种方式可以让具体业务在不同的日志实现框架之间自由切换,而不需要改动任何代码,开发者只需要掌握日志门面的 API 即可。日志门面是不能单独使用的,它必须和一种具体的日志实现框架相结合使用。2.Java日志的恩怨情仇1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j(由Ceki创建)。后来Log4j成为Apache基金会项目中的一员,Ceki也加入Apache组织。后来Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入Log4j到Java的标准库中,但Sun拒绝了。2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,Log4j就已经成为一项成熟的技术,使得Log4j在选择上占据了一定的优势。接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是Log4j,也可以是Java Util Logging。后来(2006年),Ceki不适应Apache的工作方式,离开了Apache。然后先后创建了Slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。Java日志领域被划分为两大阵营:Commons Logging阵营和Slf4j阵营。Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出Slf4j的发展趋势更好。Apache眼看有被Logback反超的势头,于2012-07重写了Log4j 1.x,成立了新的项目Log4j 2, Log4j 2具有Logback的所有特性。3.项目中选择日志框架选择如果是在一个新的项目中建议使用Slf4j与Logback组合,这样有如下的几个优点。Slf4j实现机制决定Slf4j限制较少,使用范围更广。由于Slf4j在编译期间,静态绑定本地的LOG库使得通用性要比Commons Logging要好。Logback拥有更好的性能。Logback声称:某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在Logback中需要3纳秒,而在Log4J中则需要30纳秒。LogBack创建记录器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它获取已存在的记录器只需94纳秒,而Log4J需要2234纳秒,时间减少到了1/23。跟JUL相比的性能提高也是显著的。Commons Logging开销更高Logback文档免费。Logback的所有文档是全面免费提供的,不象Log4J那样只提供部分免费文档而需要用户去购买付费文档。4.Spring Boot 默认日志4.1 默认日志pom依赖Spring Boot 的日志支持依赖是 spring-boot-starter-logging,默认使用slf4j+logback的方式来记录日志。<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>3.2.5</version> </dependency>备注:该依赖已经被spring-boot-starter所集成,无需重复引入4.2 默认日志级别配置Logback 支持 TRACE, DEBUG, INFO, WARN, ERROR 日志级别,优先级关系为 TRACE < DEBUG < INFO < WARN < ERROR , 可以在 application 配置文件中更改打印日志级别# Log level config logging.level.root=DEBUG4.3 默认日志打印测试手动创建logger@SpringBootTest class SpringBootLogStudyApplicationTests { private static final Logger logger = LoggerFactory.getLogger(SpringBootLogStudyApplicationTests.class); @Test void contextLoads() { logger.debug("debug日志"); logger.info("info日志"); logger.warn("warn日志"); logger.error("error日志"); } }使用@Slf4j注解需要实现引入lombok<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency>打印测试@Slf4j @SpringBootTest class SpringBootLogStudyApplicationTests { @Test void testPrintLog() { log.debug("debug日志"); log.info("info日志"); log.warn("warn日志"); log.error("error日志"); } }4.4 日志格式设置使用属性 logging.pattern.console 和 logging.pattern.file 可以分别自定义控制台日志和文件日志的格式#控制台显示日志的格式 logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{5}- %msg%n #文件显示日志的格式 logging.pattern.file=%d{yyyy-MM-dd HH:mm} [%thread] %-5level %logger- %msg%n上面用的一些标签含义如下:%d: 日期实践%thread: 线程名%-5level:级别从左显示5个字符宽度%logger{5}:表示logger名字最长5个字符,否则按照句点分割。%msg:日志消息%n:换行4. 使用application.yml 简单配置Logbacklogging: level: root: info # 根日志级别设置为info com.example: debug # 特定包的日志级别设置为debug pattern: console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n" file: name: application.log # 日志文件名称5. 使用自定义规则的xml配置Logback-配置详解(推荐使用)5.1 configuration节点相关属性属性名称默认值介绍debugfalse要不要打印 logback内部日志信息,true则表示要打印。scantrue配置发送改变时,要不要重新加载scanPeriod1 seconds检测配置发生变化的时间间隔。如果没给出时间单位,默认时间单位是毫秒5.2 configuration子节点介绍contextName节点用来设置上下文名称,每个logger都关联到logger上下文,默认上下文名称为default。但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改,后面输出格式中可以通过定义 %contextName 来打印日志上下文名称(一般可以无需配置)示例:<configuration scan="true" scanPeriod="60 seconds" debug="false"> <contextName>myAppName</contextName> <!--其他配置省略--> </configuration> property节点用来设置相关变量,通过key-value的方式配置,然后在后面的配置文件中通过 ${key}来访问示例:<configuration scan="true" scanPeriod="60 seconds" debug="false"> <property name="APP_Name" value="myAppName" /> <contextName>${APP_Name}</contextName> <!--其他配置省略--> </configuration>appender 节点负责写日志的组件,它有两个必要属性name和class。name指定appender名称,class指定appender的全限定名。属性名称默认值介绍name无默认值appender组件的名称,后面给logger指定appender使用class无默认值appender的具体实现类。常用的有 ConsoleAppender、FileAppender、RollingFileAppenderConsoleAppender:向控制台输出日志内容的组件,只要定义好encoder节点就可以使用。示例:把>=DEBUG级别的日志都输出到控制台<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration>FileAppender:向文件输出日志内容的组件,用法也很简单,不过由于没有日志滚动策略,一般很少使用:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。:对记录事件进行格式化。:如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。示例:把>=DEBUG级别的日志都输出到testFile.log<configuration> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>testFile.log</file> <append>true</append> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="FILE" /> </root> </configuration>RollingFileAppender(推荐):向文件输出日志内容的组件,同时可以配置日志文件滚动策略,在日志达到一定条件后生成一个新的日志文件。有以下子节点::被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 :如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。:当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类,最常用的是ch.qos.logback.core.rolling.TimeBasedRollingPolicy滚动测量配置详解: class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy": 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。有以下子节点::必要节点,包含文件名及“%d”转换符,“%d”可以包含一个java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}。如果直接使用 %d,默认格式是 yyyy-MM-dd。RollingFileAppender的file字节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置,当前日志总是记录到file指定的文件(活动文件),活动文件的名字不会改变;如果没设置file,活动文件的名字会根据fileNamePattern 的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。:可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,且是6,则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。 class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy": 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动。只有一个节点::这是活动文件的大小,默认值是10MB。:当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,1不支持也不允许文件压缩,2不能设置file属性,必须留空。: 告知 RollingFileAppender 合适激活滚动。 class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy" 根据固定窗口算法重命名文件的滚动策略。有以下子节点::窗口索引最小值:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12。:必须包含“%i”例如,假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如,mylog%i.log.gz 或者 没有log%i.log.zip示例:每天生成一个日志文件,保存30天的日志文件。<configuration> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="FILE" /> </root> </configuration>logger节点和root节点logger节点:用来设置某一个包或具体的某一个类的日志打印级别、以及指定<appender>,<logger>仅有一个name属性,一个可选的level和一个可选的addtivity属性。可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。name: 用来指定受此loger约束的某一个包或者具体的某一个类。level: 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。 如果未设置此属性,那么当前logger将会继承上级的级别。addtivity: 是否向上级logger传递打印信息。默认是true。可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。root节点:它也是<logger>元素,但是它是根logger,是所有<logger>的上级。只有一个level属性,因为name已经被命名为"root",且已经是最上级了。level: 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,不能设置为INHERITED或者同义词NULL。 默认是DEBUG。示例:常用logger配置<!-- show parameters for hibernate sql 专为 Hibernate 定制 --> <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" /> <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" /> <logger name="org.hibernate.SQL" level="DEBUG" /> <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" /> <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" /> <!--myibatis log configure--> <logger name="com.apache.ibatis" level="TRACE"/> <logger name="java.sql.Connection" level="DEBUG"/> <logger name="java.sql.Statement" level="DEBUG"/> <logger name="java.sql.PreparedStatement" level="DEBUG"/>4.2.2 配置实例可以实现每天生成一个日志文件,日志文件按等级分文件保存,保存日期等 复杂规则日志<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> <property name="LOG_HOME" value="C:/Users/vin/Desktop/log-test"/> <property name="appName" value="logbackStudy"/> <!--控制台日志, 控制台输出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> </appender> <!--文件日志, 按照每天生成日志文件 --> <!--RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件--> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true --> <append>true</append> <!--当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--定义文件滚动时的文件名的格式--> <fileNamePattern>${LOG_HOME}/${appName}.%d{yyyy-MM-dd}.log </fileNamePattern> <!--30天的时间周期,日志量最大1GB--> <maxHistory>30</maxHistory> <!-- 该属性在 1.1.6版本后 才开始支持--> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> <!--定义输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <!--每个日志文件最大10MB--> <MaxFileSize>10MB</MaxFileSize> </triggeringPolicy> </appender> <!-- 按日志级别打印 INFO --> <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 文件名称 --> <fileNamePattern>${LOG_HOME}/INFO.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 文件最大保存历史数量 --> <MaxHistory>30</MaxHistory> </rollingPolicy> <!--定义输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> <!--filter 过滤输出--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 按日志级别打印 WARN --> <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 文件名称 --> <fileNamePattern>${LOG_HOME}/WARN.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 文件最大保存历史数量 --> <MaxHistory>30</MaxHistory> </rollingPolicy> <!--定义输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> <!--filter 过滤输出--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>WARN</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 按日志级别打印 ERROR --> <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 文件名称 --> <fileNamePattern>${LOG_HOME}/ERROR.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 文件最大保存历史数量 --> <MaxHistory>30</MaxHistory> </rollingPolicy> <!--定义输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> <!--filter 过滤输出--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 日志输出级别设置,ref 属性为 appender 的name--> <root level="INFO"> <appender-ref ref="STDOUT"/> <appender-ref ref="FILE"/> <appender-ref ref="INFO"/> <appender-ref ref="WARN"/> <appender-ref ref="ERROR"/> </root> </configuration>参考资料面试官:SpringBoot中关于日志工具的使用,我想问你几个常见问题-腾讯云开发者社区-腾讯云 (tencent.com)深入掌握Java日志体系,再也不迷路了 - 掘金 (juejin.cn)Java日志体系详解_Jeremy_Lee123的博客-CSDN博客Spring Boot中集成Slf4j 与Logback-腾讯云开发者社区-腾讯云 (tencent.com)Spring Boot 默认日志使用_logging.level.springfox__星辰夜风的博客-CSDN博客logback配置文件---logback.xml详解 - 马非白即黑 - 博客园 (cnblogs.com)logback介绍和配置详解 - 简书 (jianshu.com)
2024年04月22日
126 阅读
0 评论
0 点赞
2023-12-30
Jmeter性能测试学习笔记
1.性能测试理论1.1 性能的概念1.1.1 什么是性能对于应用和软件来说,主要包括时间和资源两个维度时间:系统处理用户请求的响应时间资源:系统运行过程中,系统资源的消耗情况1.1.2 什么是性能测试?使用自动化工具,模拟不同的场景,对软件各项性能指标进行测试和评估的过程。1.1.3 性能测试的目的?评估当前系统能力寻找性能瓶颈,优化性能评估软件是否能够满足未来的需要1.2 性能测试和功能测试:1.2.1 功能测试和性能测试有什么不同?功能测试:验证系统的功能需求规格。焦点:功能(正向、逆向)性能测试:验证系统的业务需求场景。焦点:时间、资源1.2.2 功能测试和性能测试有什么关系?一般项目中,先功能测试通过后,后进行性能测试。2 性能测试分类:2.1 基准测试:(1)概念:狭义上讲:就是单用户测试。(单用户循环多次得到的数据)广义上讲:建立基准线,当系统的软硬件环境发生变化之后再进行一次基准测试以确定变化对性能的影响。(2)作用基准测试不会单独存在为多用户并发测试和综合场景测试等提供参考依据为系统/环境配置、系统优化前后的性能提升/下降提供参考指标2.2 负载测试(1)概念:通过逐步增加系统负载,确定在满足系统的性能指标(如响应时间等)情况下,找出系统所能够承受的最大负载量的测试。(2)作用系统最大负载量达到用户要求时,系统才能正式上线使用。案例:电梯行业规范:电梯从1楼到5楼(15m)的运行时间不超过24s进行负载测试:case1: 1人乘坐电梯,从1楼到5楼,运行时间为20scase2:7人乘坐电梯,从1楼到5楼,运行时间为20scase3: 13人乘坐电梯,从1楼到5楼,运行时间为20s--->[最大负载量]case4: 16人乘坐电梯,从1楼到5楼,运行时间为25sCase5: 19人乘坐电梯,从1楼到5楼,运行时间为28sCase6: 21人乘坐电梯,从1楼到5楼,运行过程中绳子断了。。。注意:通过负载测试,可以确定系统的最大负载量和极限负载量系统对外宣称的最大负载量负载测试的时间一般为1-2小时2.3 稳定性测试:(1)概念在服务器稳定运行(用户正常的业务负载下)的情况下进行长时间测试(1天-1周等),并最终保证服务器能满足线上业务需求。(2)作用系统在用户要求的业务负载下运行达到规定的时间时,系统才能正式上线使用。2.4 其它分类-压力测试背景:1、软件实际使用时,用户量超过预期(系统最大负载量),该如何反应?2、软件由于意外情况出现问题,多久能恢复?(1)概念:在强负载下的测试,查看系统在峰值情况下是否功能隐患、系统是否具有良好的容错能力和可恢复能力。(2)测试场景极限负载情况下的破坏性压力测试。高负载下的长时间的稳定性压力测试。2.5 其它分类-压力并发测试:(1)概念:并发测试(绝对并发):是指在极短的时间内,发送多个请求,来验证服务器对并发的处理能力。(2)应用场景特定活动场景,如:抢红包、秒杀、抢购等。生活中的案例:悬赏任务:做菜一西红柿炒鸡蛋(但是只有一个鸡蛋和一个西红柿)(3)与负载测试对比:负载测试:主要目的是测试高负载情况下,对系统资源的消耗,是否会耗尽的问题(双11活动)并发测试:主要目的是测试极短时间内,并发请求时,系统资源争抢的问题(抢红包、秒杀)3 性能测试的指标3.1 响应时间:指从客户端发起请求开始,到客户端接收到结果的总时间包括:服务器处理时间 + 网络传输时间3.2 并发用户数:某一时刻同时向服务器发送请求的用户数案例:淘宝系统案例—哪个是并发数?3.3 吞吐量:吞吐量(Throughput):指的是单位时间内处理的客户端请求数量,直接体现软件系统的性能承载能力。从业务角度来看单位:“业务数/小时”、“业务数/天”、“访问人数/天”、“页面访问量/天”从网络角度来看单位:“字节数/小时”、“字节数/天”从技术角度来看单位:每秒事务数(TPS)、每秒查询数(QPS)QPS:QPS(Query Per Second)每秒查询数:即控制服务器每秒处理的指定请求的数量TPS:TPS(Transactions Per Second)每秒事务数:即控制服务器每秒处理的事务请求的数量事务:即业务,页面上的一次操作,可能对应一个请求/多个请求。3.4 点击数:所有的页面元素(如:图片、链接、框架等)的请求总数量.注意:点击数是请求数,不是页面上的一次点击3.5 错误率:指系统在负载情况下,失败业务的概率注意:错误率是性能指标,是高负载下的失败业务的概率随机bug是功能bug,先解决随机bug才能进行性能测试3.6 资源利用率:(1)什么是资源利用率?系统各种资源的使用情况,“资源的使用量/总的资源可用量×100%”(2)常见资源指标有哪些?CPU使用率:不高于75%-85%内存(大小)使用率:不高于80%磁盘IO(速率):不高于90%网络(速率):不高于80%4.性能测试的流程性能测试的核心:需求分析、性能测试执行、性能分析调优4.1 需求分析4.2 性能测试计划和方案测什么项目背景测试目的测试范围谁来测进度与分工交付清单怎么测测试策略4.3 编写性能测试用例用例模板:4.4 性能测试执行4.5 性能分析和调优性能测试分析人员经过对结果的分析以后,如果不符合性能需求,则会提出性能bug,然后由开发人员进行后续的调优。提示:调优-开发人员为主导,数据库管理员、系统管理员、网络管理员、性能测试分析人员配合进行验证-性能测试人员继续进行第二轮、第三轮.的测试,与以前的测试结果进行对比,从而确定经过调整以后系统的性能是否有提升4.6 性能测试报告总结测试报告是对性能测试工作的总结,为软件后续验收和交付打下基础。测试报告的主要内容:测试工作的经过回顾缺陷分析和调优风险评估性能测试结果测试工作总结与改进5.性能测试工具介绍5.1 Loadrunner简介HP Loadrunner是一种工业级标准性能测试负载工具,可以模拟上万用户实施测试,并在测试时可实时检测应用服务器及服务器硬件各种数据,来确认和查找存在的瓶颈支持多协议:Web(HTTP/HTML)、Windows Sockets、FTP、ODBC、MS SQL Server等协议采用c语言编写优点1.多用户(支持用户以万为单位)2.详细的分析报表(以秒为单位)3.支持IP欺骗功能缺点:1.收费2.体积庞大(安装包单位GB)3.无法定制功能5.2 JMeterJMeter是Apache组织开发的基于Java的开源软件,用于对系统做功能测试和性能测试。它最初被设计用于web应用测试,但后来扩展到其他测试领域,例如静态文件、Java程序、shell脚本、数据库、FTP、 Mail等。优点:1.开源免费2.小巧(安装包50MB左右)3.丰富的学习资料和扩展组件缺点:1.不支持IP欺骗2.分析和报表能力相对于LR欠缺精度(以分钟为单位)5.3 对比相同点1.都能模拟大量用户2.都能支持多协议(常见的协议都支持,如:HTTP)3.都有监控及分析报表功能不同点结论:项目日常性能测试Jmeter足够用,出商业报告优先Loadrunner6.JMeter安装和基本使用6.1 JMeter安装安装JDK安装 JMeter下载JMeterjmeter是免安装的,下载解压配置环境变量即可使用。官网下载地址:http://jmeter.apache.org/download_jmeter.cgi环境配置(可不配)jdk1.8环境配置:Java -version 查看jdk版本。jmeter环境配置(不配置不影响)1)桌面上选择“我的电脑”(右键),高级, 环境变量, 在“系统变量”—>“新建”, 在变量名中输:JMETER_HOME,变量值中输入:D:\apache-jmeter-2.112)再修改CLASSPATH变量,变量值中添加%JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;% JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib\logkit-1.2.jar; 然后确定即可。Jmeter启动三种方式:进入JMeter安装目录下的bin目录1、双击 jmeter.bat2、双击ApacheJMeter.jar3、命令行输入:java-jar ApacheJMeter.jar启动效果6.2 JMeter常用目录介绍和汉化设置6.2.1 常用文件目录介绍Bin目录:存放可执行文件和配置文件docs目录:是JMeter的api文档,用于开发扩展组件printable_docs目录:用户帮助手册lib目录:存放JMeter依赖的jar包和用户扩展所依赖的jar包6.2.2 JMeter界面的汉化临时性:启动JMeter->选择菜单、Options'->Choose Language->Chinese(Simplified)永久性 — 修改配置文件:1.找到jMeter安装目录下的bin目录2.打开jmeter.properties文件,把第37行修改为"language=zh_CN"3.重启JMeter即可7.JMeter原件和组件介绍7.1 元件的基本介绍元件:多个类似功能组件的容器(类似于类)如上图所示,主要包括:1.取样器:发送请求2.逻辑控制器:控制语句的执行顺序3.前置处理器:对请求参数进行预处理4.后置处理器:对响应结果进行提取5.断言:检查接口的返回结果是否与预期结果一致6.定时器:设置等待7.测试片段:封装一段代码,供其他脚本调用8.配置元件:测试数据的初始化配置7.2 组件的基本介绍组件:实现独立的某个功能(类似于方法)例如:取样器的组件7.3 小结如下接口自动化脚本的实现过程对应着Jmeter哪个元件?元件与组件有什么关系?元件:多个类似功能组件的容器(类似于类)组件:容器中实现独立的某个功能(类似于方法)7.4 Jmeter元件作用域和执行顺序元件的作用域:是靠测试计划的树形结构中元件的父子关系来确定的。提示:所有的组件都是以取样器为核心来运行的。组件添加的位置不同,生效的取样器也不同作用域的原则:取样器:核心,不和其他元件相互作用,没有作用域。逻辑控制器:只对其子节点中的取样器和逻辑控制器起作用。其他元件:如果是某个取样器的子节点,则该元件只对其父节点起作用。如果其父节点不是取样器,则其作用域是该元件父节点下的其他所有后代节点(包括子节点,子节点的子节点等)。元件的执行顺序同一个作用域下不同类型元件:1.配置元件(config elements)2.前置处理程序(Per-processors)3.定时器(timers)4.取样器(Sampler)5.后置处理程序(Post-processors)6.断言(Assertions)7.监听器(Listeners)同一个作用域下多个相同类型元件:按照在测试计划中从上到下的顺序依次执行执行顺序样例正确:定时器1-请求1-定时器1-定时器2-请求2-定时器1-定时器3-请求38.Jmeter第一个案例需求:使用JMeter访问百度首页接口,并查看请求和响应信息步骤:1.启动JMeter2.在测试计划下添加线程组3.在线程组,下添加HTTP请求取样器4.填写HTTP请求的相关请求数据5·在线程组下添加查看结果树监听器6.点启动按钮运行,并查看结果9.Jmeter三个重要组件(重点)9.1 线程组作用:线程组就是控制Jmeter用于执行测试的一组用户位置:右键点击、测试计划'-->添加-->线程(用户)-->线程组特点:模拟多人操作线程组可以添加多个,多个线程组可以并行或串行取样器(请求)和逻辑控制器必须依赖线程组才能使用线程组下可以添加其他元件下组件线程组分类:普通线程组:普通的、常用的线程组,可以看做一个虚拟用户组,线程组中的每一个线程都可以理解为一个虚拟用户setUp线程组:一种特殊类型的线程组,可用于执行预测试操作tearDown线程组:一种特殊类型的线程组,可用于执行测试后工作线程组的属性:练习:如下场景如何设置线程组?模拟10个用户并行执行:----线程数模拟10个用户5s内启动完成:----线程数10,ramp-up时间:5s模拟2个用户各循环3次:----线程数:2,循环次数:3模拟2个用户运行30s:----线程数:2,循环:永远,持续时间:30s模拟2个用户等待10s后开始执行:----在上一个的基础上,增加延迟启动时间:10s9.2 HTTP请求作用:向服务器发送http及https请求位置:选中线程组->右键->添加->取样器->HTTP请求参数:案例:案例一:GET请求,URL为http://www.baidu.com/S?wd=test要求:使用HTTP请求-路径来传递get请求参数案例二:GET请求,URL为https://www.baidu.com/S?wd=test要求:使用HTTP请求-参数列表来传递get请求的参数案例三:PosT请求,URL为https://www.baidu.com/S,请求体为:wd=test(form表单)要求:使用HTTP请求-参数列表来传递POST请求的form格式参数案例四:POST请求,URL为http://www.baidu.com/s,请求体为:wd=test(form表单)要求:使用HTTP请求-消息体数据来传递POST请求的form格式参数9.3 查看结果树作用:查看HTTP请求的请求和响应结果位置:选中测试计划/线程组->右键->添加->监听器->察看结果树组成:取样结果:查看响应信息头信息、响应状态码请求:查看请求相关信息(url、方法、参数)响应:查看响应信息10.Jmeter参数化定义:使用不同的测试数据,调用相同的测试方法进行测试本质:实现测试数据与测试方法的分离。JMeter中常见的参数化方式用户定义的变量——全局变量用户参数——为每个用户分配不同的参数值CSV数据文件设置——文件方式参数化函数——随机数据数据库全局变量步骤:1.添加线程组2.添加用户定义的变量。格式:变量名-变量值3.添加HTTP请求,引用定义的变量名。格式: ${变量名}4.添加查看结果树用户参数-[在线程组配置]作用:针对同一组参数,当不同的用户来访问时,可以获取到不同的值步骤:添加线程组,设置线程数为n(表示模拟的用户数)添加用户参数第一列添加多个变量含后续每一列为一组用户的数据3.添加HTTP请求用定义的变量名。格式: ${变量名}4.添加查看结果树CSV数据文件设置作用:当不同的用户,或者同一个用户多次循环时,都可以获取到不同的值位置:测试计划-->线程组--> 配置元件--> CSV 数据文件设置步骤:1.定义csv数据文件user01,123456,0000 user02, 123456, 1111 user03, 123456, 22222.添加线程组3.添加csv数据文件设置4.添加HTTP请求,引用定义的变量名。格式: ${变量名}5.添加查看结果树函数(案例:_counter函数)为什么要使用函数参数化?性能测试时,如果模拟1000个用户,每个用户循环执行10万次添加商品操作,请求参数要求不同,该怎么做?作用:计数函数,一般做执行次数统计使用位置:在菜单中选择-->选项-->函数助手对话框设置:TRUE,每个用户有自己的计数器;FALSE,使用全局计数器Name of variable in which to store the result(optional):用于存储结果的变量名(可选)操作步骤:1.添加线程组,设置虚拟用户数和循环次数2.生成_counter函数3.添加HTTP请求,使__counter函数4添加查看结果树4种参数化方式有何不同?如何选择适当的方式?用户定义的变量:-作用:定义全局变量-局限性:每次取值(无论是否相同的用户)都是固定值用户参数:-作用:保证不同的用户针对同一组参数,可以取到不同的值-局限性:同一个用户在多次循环时,取到相同的值csv数据文件设置:-作用:保证不同的用户及同一用户多次循环时,都可以取到不同的值-局限性:需要手动进行测试数据的设置函数:-作用:保证不同的用户及多次循环时,都可以取到。的值,不需要提前设置-局限性:输入数据有特定的业务要求时无法使用(如:登录时的用户名密码)参考资料黑马程序员性能测试全套教程,4天快速入门性能测试+项目商城实战JMeter安装教程
2023年12月30日
68 阅读
0 评论
0 点赞
2023-12-30
牛客刷题笔记
mysql1.MySQL的NULL值处理方法在MySQL中不能使用 = NULL 或 != NULL 等比较运算符在列中查找 NULL 值 。要用IS NULL 或 IS NOT NULL才会进行NULL值或非NULL值得查找。2.从一张表中选取数据插入到另一张表中INSERT INTO 语句用于向一张表中插入新的行。SELECT INTO 语句从一张表中选取数据插入到另一张表中。常用于创建表的备份复件或者用于对记录进行存档。3.关系代数运算中的集合运算符和关系运算符4.having必须跟在group By后面having必须跟在group By后面,不然会报错In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'db_sql.course_sku_publish_record.id'; this is incompatible with sql_mode=only_full_group_by ... 展开5.关于mysql的insert语句insert字段名顺序与字段值顺序一致即可,可以给部分或所有字段名加``。Mysql中表student_info(id,name,birth,sex),字段类型都是varchar,插入:1018 , 赵六 , 2003-08-02 , 男;SQL正确的是()?A insert overwrite student_info values('1018' , '赵六' , '2003-08-02' , '男');B insert into student_info values(1018 , '赵六' , '2003-08-02' , '男');C insert into student_info(birth,id,name,sex) values('2003-08-02' ,'1018' , '赵六' , '男');D insert into student_info value('1018' , '赵六' , '2003-08-02' , '男');正确答案:C你的答案:D官方解析:A执行报错,插入时是insert into不是insert overwrite;B执行报错,id是varchar类型,插入的1018需要加上单引号;D执行报错,插入时是values不是value;所以C正确,字段名顺序与字段值顺序一致即可,可以给部分或所有字段名加``。知识点:数据库、SQL6.MySQL中ALTER TABLE命令的用法MySQL中ALTER TABLE命令可以修改数据表的表名或数据表的字段。但是接不同后缀意义不同,比如:要修改表名或索引名时,可以用RENAME函数;当然RENAME也可以更改列名,但是后面要加TO,且它只会更改列的名字,并不更改定义。要修改字段定义和名称,可以用MODIFY或CHANGE函数。但是MODIFY只改字段定义,不改名字;CHANGE是两个都可以修改。要修改字段默认值,可以用ALTER 字段名 SET DEFULT 更改值。1.要将employee 的表名更改为 employee_info,下面MySQL语句正确的是:A ALTER TABLE employee RENAME employee_info;B ALTER TABLE employee MODIFY employee_info;C ALTER TABLE employee ALTER employee_info;D ALTER TABLE employee CHANGE employee_info;正确答案:A你的答案:B官方解析:本题考察知识点:MySQL中ALTER TABLE命令的用法MySQL中ALTER TABLE命令可以修改数据表的表名或数据表的字段。但是接不同后缀意义不同,比如:要修改表名或索引名时,可以用RENAME函数;当然RENAME也可以更改列名,但是后面要加TO,且它只会更改列的名字,并不更改定义。要修改字段定义和名称,可以用MODIFY或CHANGE函数。但是MODIFY只改字段定义,不改名字;CHANGE是两个都可以修改。要修改字段默认值,可以用ALTER 字段名 SET DEFULT 更改值。所以根据题意,要修改表名,只能用RENAME函数,因此A正确;BCD则分别是修改字段的方法。知识点:数据库、SQL7.MySql修改表名的两种方法rename table 旧表名 to 新表名; alter table 旧表名 rename [as] 新表名8.MySQL中ALTER TABLE修改字段用法-- 新增字段 ALTER TABLE 表名 ADD COLUMN 字段名 字段类型; -- 在name字段后面新增一个age列 ALTER TABLE tuser ADD COLUMN age int(11) DEFAULT NULL COMMENT '年龄' AFTER name; # AFTER:在某字段后, BEFOR:在某字段之前 -- 在表后追加一列 ALTER TABLE tuser ADD COLUMN age int(11) DEFAULT NULL COMMENT '年龄'; -- 修改字段 ALTER TABLE tuser CHANGE name user_name varchar(32) DEFAULT NULL COMMENT '姓名'; # ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型; -- 修改字段类型 ALTER TABLE tuser MODIFY name varchar(32) DEFAULT NULL COMMENT '姓名'; # ALTER TABLE 表名 MODIFY 字段名 数据类型; -- 删除字段 ALTER TABLE tuser DROP name; # ALTER TABLE 表名 DROP 字段名;9.多表删除时,delete和from之间必须要写明想要删除记录的表名。Mysql中表student_table(id,name,birth,sex),删除name重复的id最大的记录,比如'张三'重复2次,id分别是1、2,则删除id=2的记录,保留id=1的记录。如下SQL正确的是()?A delete from student_table where id in (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) ;B delete from student_table t0inner join (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) t3on t0.id = t3.id ;C delete t0from student_table t0inner join (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) t3on t0.id = t3.id ;D delete student_tablefrom student_table t0inner join (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) t3on t0.id = t3.id ;10.COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入)而COUNT(*) 函数才返回表中的记录数11.MySQL添加用户、删除用户、授权及撤销权限创建用户 insert into mysql.user(Host,User,Password) values("localhost","test",password("1234"));这样就创建了一个名为:test 密码为:1234 的用户。注意:==此处的"localhost",是指该用户只能在本地登录,不能在另外一台机器上远程登录。如果想远程登录的话,将"localhost"改为"%",表示在任何一台电脑上都可以登录。也可以指定某台机器(例如192.168.1.10),或某个网段(例如192.168.1.%)可以远程登录。==为用户授权:授权格式:grant 权限 on 数据库.* to 用户名@登录主机 identified by "密码"; 首先为用户创建一个数据库(testDB):mysql>create database testDB;授权test用户拥有testDB数据库的所有权限(某个数据库的所有权限):mysql>grant all privileges on testDB.* to test@localhost identified by '1234'; mysql>flush privileges;//刷新系统权限表,即时生效如果想指定某库的部分权限给某用户本地操作,可以这样来写:mysql>grant select,update on testDB.* to test@localhost identified by '1234'; mysql>flush privileges; 常用的权限有select,insert,update,delete,alter,create,drop等。可以查看mysql可授予用户的执行权限了解更多内容。2.4 授权test用户拥有所有数据库的某些权限的远程操作: mysql>grant select,delete,update,create,drop on *.* to test@"%" identified by "1234"; #test用户对所有数据库都有select,delete,update,create,drop 权限。2.5 查看用户所授予的权限:mysql> show grants for test@localhost;撤销已经赋予用户的权限:revoke 跟 grant 的语法差不多,只需要把关键字 “to” 换成 “from” 即可:mysql>grant all on *.* to dba@localhost; mysql>revoke all on *.* from dba@localhost;12.drop、trustcate、delete1:处理效率:drop>trustcate>delete2:删除范围:drop删除整个表(结构和数据一起删除);trustcate删除全部记录,但不删除表结构;delete只删除数据3:高水位线:delete不影响自增ID值,高水线保持原位置不动;trustcate会将高水线复位,自增ID变为1。13.mysql select 字段重命名as可以做重命名,不过也可以省略as,空格隔开新名称即可。14.mysql设置外键todo2.java1.java中接口、接口属性、接口方法的修饰符合java接口的修饰符:abstract(默认不写。interface本身就是抽象的,加不加abstract都一样)接口中字段的修饰符:public static final(默认不写) 接口中方法的修饰符:public abstract(默认不写)2.java中的数组创建形式声明的二维数组中第一个中括号中必须要有值,它代表的是在该二维数组中有多少个一维数组。 下面哪个语句是创建数组的正确语句?( )A float f[][] = new float[6][6];B float []f[] = new float[6][6];C float f[][] = new float[][6];D float [][]f = new float[6][6];E float [][]f = new float[6][];正确答案:ABDE3.关于java继承在java中,下列对继承的说法,正确的是( )A 子类能继承父类的所有成员B 子类继承父类的非私有方法和状态C 子类只能继承父类的public方法和状态D 子类只能继承父类的方法正确答案:A官方解析:Constructors, static initializers, and instance initializers are not members andtherefore are not inherited.(构造器、静态初始化块、实例初始化块不继承)4.java线程的start()和run()的区别t.run直接执行代码,按顺序打印代码; t.start是另起线程,与当前线程同时竞争cpu资源,结果存在不确定性下面程序的运行结果是:( )public static void main(String args[]) { Thread t = new Thread() { public void run() { pong(); } }; t.run(); System.out.print("ping"); } static void pong() { System.out.print("pong"); }A pingpongB pongpingC pingpong和pongping都有可能D 都不输出E pongF ping5.java集合体系判断对错。List,Set,Map都继承自继承Collection接口。A 对B错正确答案:B你的答案:A参考答案:答案:B List,Set等集合对象都继承自Collection接口 Map是一个顶层结果,不继承自Collection接口6.this不能在static的方法中使用已知有下列Test类的说明,在该类的main方法的横线处,则下列哪个语句是正确的?()public class Test { private float f = 1.0f; int m = 12; static int n = 1; public static void main (String args[]) { Test t = new Test(); ———————— } }A t.f = 1;B this.n = 1;C Test.m = 1;D Test.f = 1;正确答案:A你的答案:BA的答案中变量虽然为private,但因为main函数在该类中,所以即使private也仍可使用,B的答案static变量不能使用this7.Java中的byte,short,char进行计算时都会提升为int类型。代码片段:byte b1=1,b2=2,b3,b6; final byte b4=4,b5=6; b6=b4+b5; b3=(b1+b2); System.out.println(b3+b6);关于上面代码片段叙述正确的是()A 输出结果:13B 语句:b6=b4+b5编译出错C 语句:b3=b1+b2编译出错D 运行期抛出异常正确答案:C你的答案:A参考答案:C. 被final修饰的变量是常量,这里的b6=b4+b5可以看成是b6=10;在编译时就已经变为b6=10了 而b1和b2是byte类型,java中进行计算时候将他们提升为int类型,再进行计算,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。 Java中的byte,short,char进行计算时都会提升为int类型。8.boolean 类型不能转换成任何其它数据类型。Java中可以将布尔值与整数进行比较吗 ?A 可以B 不可以正确答案:B你的答案:A官方解析:boolean 类型不能转换成任何其它数据类型。9.java中的char是两个字节执行如下程序代码char chr = 127; int sum = 200; chr += 1; sum += chr;后,sum的值是()备注:同时考虑c/c++和Java的情况的话A 72B 99C 328D 327正确答案:AC你的答案:Ajava中只有byte, boolean是一个字节, char是两个字节, 所以对于java来说127不会发生溢出, 输出328 但是对于c/c++语言来说, char是一个字节, 会发生溢出, 对127加一发生溢出, 0111 1111 --> 1000 0000, 1000 0000为补码-128, 所以结果为200-128=7210.java中Object类的方法有哪些?equals(Object obj): 该方法用于比较当前对象与参数对象是否相等。hashCode(): 该方法返回该对象的哈希码值。toString(): 该方法返回该对象的字符串表示。clone(): 该方法创建并返回该对象的副本。finalize(): 该方法是垃圾回收器在对该对象进行清理之前调用的方法。getClass(): 该方法返回表示此对象的运行时类(包含该对象的类的对象)的Class对象。wait(long timeout): 该方法使当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者经过指定的时间量。wait(long timeout, int nanos): 该方法使当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者经过指定的时间量和纳秒数。notify(): 该方法唤醒正在等待该对象监视器的单个线程(如果没有线程在等待,则抛出IllegalMonitorStateException异常)。notifyAll(): 该方法唤醒正在等待该对象监视器的所有线程。在JAVA中,下列哪些是Object类的方法()A synchronized()B wait()C notify()D notifyAll()E sleep()正确答案:BCD你的答案:BCDE参考答案:A synchronized Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。 B C D 都是Object类中的方法 notify(): 是唤醒一个正在等待该对象的线程。 notifyAll(): 唤醒所有正在等待该对象的线程。 E sleep 是Thread类中的方法 wait 和 sleep的区别: wait指线程处于进入等待状态,形象地说明为“等待使用CPU”,此时线程不占用任何资源,不增加时间限制。 sleep指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制。11.java中整数类型 默认为 int 带小数的默认为 double在基本JAVA类型中,如果不明确指定,整数型的默认是什么类型?带小数的默认是什么类型?A int floatB int doubleC long floatD long double正确答案:B你的答案:A参考答案:整数类型 默认为 int 带小数的默认为 double12.java访问控制修饰符default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)public : 对所有类可见。使用对象:类、接口、变量、方法protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。我们可以通过以下表来说明访问权限:修饰符当前类同一包内子孙类(同一包)子孙类(不同包)其他包publicYYYYYprotectedYYYY/N(说明)NdefaultYYYNNprivateYNNNN13.java中创建线程的方法实现Runnable接口:这是最常用的方法。创建一个实现了Runnable接口的类,然后实现run()方法。这个run()方法将包含线程应该运行的代码。然后,创建一个Thread对象,并将Runnable对象作为参数传递给Thread的构造函数。最后,调用Thread对象的start()方法来启动线程。继承Thread类:这是另一种创建线程的方法,但是通常不推荐使用,因为Java不支持多重继承。创建一个继承了Thread类的类,然后重写run()方法。然后,创建一个Thread对象,并调用start()方法来启动线程。使用Callable和Future:这是一种更现代的方法,主要用于并发编程。Callable接口与Runnable接口类似,但Callable可以返回结果并且可以抛出异常。Future接口代表异步计算的结果。通过使用ExecutorService,你可以执行Callable任务并获取Future对象,然后使用Future对象的get()方法获取结果。14.jvm内存:堆区栈区存储下列Java代码中的变量a、b、c分别在内存的____存储区存放。class A { private String a = “aa”; public boolean methodB() { String b = “bb”; final String c = “cc”; } }A 堆区、堆区、堆区B 堆区、栈区、堆区C 堆区、栈区、栈区D 堆区、堆区、栈区E 静态区、栈区、堆区F 静态区、栈区、栈区正确答案:C你的答案:F参考答案:答案是C a是类中的成员变量,存放在堆区 b、c都是方法中的局部变量,存放在栈区15.java流体系16.java异常体系17.java类加载过程Java类加载过程是Java虚拟机(JVM)运行时将类文件加载到内存中的过程。这个过程可以分为三个阶段:加载、链接(验证、准备、解析)和初始化。加载:这是类加载过程的第一个阶段,主要任务是加载类。JVM通过类的全限定名来获取定义此类的二进制字节流。这个过程主要通过以下几种方式完成:通过类路径(Classpath)查找类文件(.class文件)。从JAR或ZIP文件中读取,这些文件可能被放在类路径中。从网络或其他源动态加载。通过Java反射机制从已加载的类中生成。链接:这个阶段是验证、准备和解析阶段,主要任务是确保被加载的类文件的正确性,为类的静态变量分配内存并设置初始值,以及解析符号引用。验证:确保被加载的类文件的正确性,没有安全方面的隐患。准备:为类的静态变量分配内存,并设置默认的初始值。解析:将符号引用转换为直接引用。符号引用是在编译时生成的,包含了被引用的类的全限定名;而直接引用可以直接指向数据。初始化:这是类加载过程的最后一个阶段,主要任务是执行类构造器方法<clinit>()。这个方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块(但不执行其中的方法)组成的。JVM会创建Class对象,并执行<clinit>()方法。注意,类加载器在执行完这三个阶段后,会为这个类生成一个Class对象,这个Class对象在JVM中表示这个类的类型信息。每个Class对象都对应于Java虚拟机中的元空间的一个类或接口的符号引用。此外,Java类加载器有三种:启动类加载器(Bootstrap Class Loader):负责加载核心类库,如 rt.jar、resources.jar、charsets.jar等,它是其他所有类加载器的父类加载器。由于该类加载器负责加载的是核心类库,所以它是不负责扩展类的加载的。扩展类加载器(Extension Class Loader):该类加载器负责加载JRE的扩展目录(java.ext.dirs系统属性或者java.library.path)中的类库,它是ExtensionClassLoader的父类加载器。由于该类加载器是ClassLoader中的sun.misc.Launcher$ExtClassLoader的默认实现,所以一般情况下我们不需要直接使用扩展类加载器。系统类加载器(System Class Loader):也被称为应用程序类加载器(Application Class Loader),它负责在应用程序的classpath中查找并加载类。它是ClassLoader中的sun.misc.Launcher$AppClassLoader的默认实现,也是我们最常直接使用的类加载器。以下哪项不属于java类加载过程?A 生成java.lang.Class对象B nt类型对象成员变量赋予默认值C 执行static块代码D 类方法解析正确答案:B你的答案:D参考答案:不应该选D,而应该选B 类的加载包括:加载,验证,准备,解析,初始化。 选项A:生成java.lang.Class对象是在加载时进行的。生成Class对象作为方法区这个类的各种数据的访问入口。 选项B:既然是对象成员,那么肯定在实例化对象后才有。在类加载的时候会赋予初值的是类变量,而非对象成员。 选项C:这个会调用。可以用反射试验。 选项D:类方法解析发生在解析过程。18. sleep、wait、yield、join区别sleepsleep 方法是属于 Thread 类中的,sleep 过程中线程不会释放锁,只会阻塞线程,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断,sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会waitwait 方法是属于 Object 类中的,wait 过程中线程会释放对象锁,只有当其他线程调用 notify 才能唤醒此线程。wait 使用时必须先获取对象锁,即必须在 synchronized 修饰的代码块中使用,那么相应的 notify 方法同样必须在 synchronized 修饰的代码块中使用,如果没有在synchronized 修饰的代码块中使用时运行时会抛出IllegalMonitorStateException的异常yield和 sleep 一样都是 Thread 类的方法,都是暂停当前正在执行的线程对象,不会释放资源锁,和 sleep 不同的是 yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 方法只能使同优先级或更高优先级的线程有执行的机会join等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。例如:主线程创建并启动了子线程,如果子线程中药进行大量耗时运算计算某个数据值,而主线程要取得这个数据值才能运行,这时就要用到 join 方法了下列哪些操作会使线程释放锁资源?A sleep()B wait()C join()D yield()正确答案:BC你的答案:BD19.java ThreadLocalThreadLocal是Java中的一个类,它提供了线程局部变量(thread-local variables)的实现。线程局部变量允许程序员将与线程关联的特定值(通常是一个对象引用)存储在变量中。每个线程都可以拥有自己独立的变量副本,而不会与其他线程共享。ThreadLocal的主要用途是解决多线程中的数据同步问题,避免使用synchronized关键字来锁定整个方法或代码块,从而提高程序的性能。ThreadLocal的工作原理是:每个线程持有一个该变量的副本,当线程需要访问该变量时,它将获取自己的副本,而不是共享变量。因此,每个线程都可以独立地修改自己的变量副本,而不会影响其他线程的变量。ThreadLocal的使用方法如下:创建一个ThreadLocal对象:ThreadLocal<Integer> threadLocal = new ThreadLocal<>();将值设置为每个线程的变量副本:threadLocal.set(42); // 设置当前线程的变量副本为42从每个线程获取自己的变量副本:int value = threadLocal.get(); // 获取当前线程的变量副本的值在不再需要时清除当前线程的变量副本:threadLocal.remove(); // 清除当前线程的变量副本ThreadLocal在Web开发中经常被用于存储每个请求的上下文信息,例如用户信息、会话信息等。这样,每个请求都可以有自己的独立上下文,而不会与其他请求共享。20.关于HashMap的知识点a) HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap的底层结构是一个数组,数组中的每一项是一条链表。 b) HashMap的实例有俩个参数影响其性能: “初始容量” 和 装填因子。 c) HashMap实现不同步,线程不安全。 HashTable线程安全 d) HashMap中的key-value都是存储在Entry中的。 e) HashMap可以存null键和null值,不保证元素的顺序恒久不变,它的底层使用的是数组和链表,通过hashCode()方法和equals方法保证键的唯一性 f) 解决冲突主要有三种方法:定址法,拉链法,再散列法。HashMap是采用拉链法解决哈希冲突的。21.关于java的内存区域以下描述错误的一项是( )?A 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行 到了第几行,是线程隔离的B 原则上讲,所有的对象都是在堆区上分配内存,是线程之间共享的C 方法区用于存储JVM加载的类信息、常量、静态变量,即使编译器编译后的代码等数据,是线程隔离的D Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的22.三元操作符如果遇到可以转换为数字的类型,会做自动类型提升。以下JAVA程序的运行结果是什么( )public static void main(String[] args) { Object o1 = true ? new Integer(1) : new Double(2.0); Object o2; if (true) { o2 = new Integer(1); } else { o2 = new Double(2.0); } System.out.print(o1); System.out.print(" "); System.out.print(o2); }A 1 1B 1.0 1.0C 1 1.0D 1.0 1正确答案:D你的答案:A23.类实现多个接口的时候,只需要一个implements,多个接口通过逗号进行隔开,先继承类再实现接口在java中,已定义两个接口B和C,要定义一个实现这两个接口的类,以下语句正确的是()A interface A extends B,CB interface A eimplements B,CC class A implements B,CD class A implements B,implements C正确答案:C你的答案:D24.类中实例变量可以不用初始化,使用相应类型的默认值即可;方法中的定义的局部变量必须初始化,否则编译不通过。下面代码的运行结果是()public static void main(String[] args){ String s; System.out.println("s="+s); }A 代码编程成功,并输出”s=”B 代码编译成功,并输出”s=null”C 由于String s没有初始化,代码不能编译通过。D 代码编译成功,但捕获到NullPointException异常正确答案:C你的答案:A参考答案:局部变量没有默认值25.switch支持 int及以下(char, short, byte),String, Enum 。不支持long类型在java7中,下列不能做switch()的参数类型是?A int型B 枚举类型C 字符串D 浮点型正确答案:D你的答案:B参考答案:Dswitch语句后的控制表达式只能是short、char、int整数类型和枚举类型,不能是float,double和boolean类型。String类型是java7开始支持。下面的switch语句中,x可以是哪些类型的数据:()switch(x) { default: System.out.println("Hello"); }A longB charC floatD byteE doubleF String正确答案:BDF你的答案:ABDF26.java是面向对象的,但是不是所有的都是对象,基本数据类型就不是对象,所以才会有封装类的;27.java多线程生命周期及对应的方法调用以下哪个事件会导致线程销毁?()A 调用方法sleep()B 调用方法wait()C start()方法的执行结束D run()方法的执行结束正确答案:D你的答案:C28.抛InterruptedException的代表方法有:java.lang.Object 类的 wait 方法java.lang.Thread 类的 sleep 方法java.lang.Thread 类的 join 方法29.线程安全的集合有Vector、Stack、Hashtable30. 数组无论是在定义为实例变量还是局部变量,若没有初始化,都会被自动初始化31. 发生继承关系时父子类代码执行顺序1.父类静态代码块:如果有多个静态代码块,按顺序执行,仅执行一遍2.子类静态代码块:同上3.父类非静态代码块: 有多个非静态代码块,按顺序执行,且每次new,每次执行4.父类构造函数5.子类非静态代码块: 有多个非静态代码块,按顺序执行,且每次new,每次执行6.子类构造函数32.序列化的是对象,不是类,类变量不会被序列化有以下一个对象:public class DataObject implements Serializable{ private static int i=0; private String word=" "; public void setWord(String word){ this.word=word; } public void setI(int i){ Data0bject.i=i; } }创建一个如下方式的DataObject:DataObject object=new Data0bject ( ); object.setWord("123"); object.setI(2);将此对象序列化为文件,并在另外一个JVM中读取文件,进行反序列化,请问此时读出的Data0bject对象中的word和i的值分别为:A "", 0B "", 2C "123", 2D "123", 0正确答案:D你的答案:C参考答案:这道题的答案应该是: D,序列化保存的是对象的状态,静态变量属于类的状态,因此,序列化并不保存静态变量。所以i是没有改变的33.java数组的复制效率:System.arraycopy>使用clone方法>Array.copyOf>for 循环逐一复制34.HashTable和HashMap的区别(7点):1.继承的父类不同:HashTable继承Dictory类,HashMap继承AbstractMap.但都实现了Map接口; 2.线程安全性不同:HashTable是线程安全的,适用于多线程;HashMap是非线程安全,更适合于单线程; 3.是否提供contains方法:HashTable中保留了contains方法,与constainsValue功能相同;HashMap中去掉了contains方法; 4.key和value是否可为null值:HashTable的key、value都不允许null值;HashMap,null可以作为key; 5.遍历方式的内部实现不同:HashTable、HashMap都使用了Iterator,HashTable还使用过Enumeration方式;6.hash值不同:HashTable直接使用对象的hashCode,而HashMap重新计算hash值。 7.内部使用的数组初始化和扩容方式不同:Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂;Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。35.Math 类三个用于数值处理的静态方法:ceil(), floor() 和 round().ceil()Math.ceil() 方法返回大于或等于给定数字的最小整数。换句话说,它会将给定的数字向上取整。floor()Math.floor() 方法返回小于或等于给定数字的最大整数。换句话说,它会将给定的数字向下取整。round()Math.round() 方法将给定的数字四舍五入为最接近的整数。36.关于父子类方法重写的错题:class Car extends Vehicle { public static void main (String[] args) { new Car(). run(); } private final void run() { System. out. println ("Car"); } } class Vehicle { private final void run() { System. out. println("Vehicle"); } }下列哪些针对代码运行结果的描述是正确的?A CarB VehicleC Compiler error at line 3D Compiler error at line 5E Exception thrown at runtime正确答案:A你的答案:D参考答案:答案:A 首先final声明的方法是不能被覆盖的,但是这里并不错误,因为方法是private的,也就是子类没有继承父类的run方法,因此子类的run方法跟父类的run方法无关,并不是覆盖。new Car().run()也是调用子类的run方法。37.Java ArrayList扩容在 Java 中,ArrayList 是一种动态数组,其大小(即容量)可以根据需要自动增长。当你向 ArrayList 中添加元素,并且当前的容量不足以容纳新的元素时,ArrayList 会自动进行扩容。下面是 ArrayList 扩容的基本过程:初始化容量:当你创建一个新的 ArrayList 时,你可以指定一个初始容量。如果你不指定,它会使用默认容量,通常是 10。添加元素:当你使用 add 方法向 ArrayList 中添加元素时,它会检查当前数组是否有足够的空间来容纳新元素。扩容:如果当前数组已满,ArrayList 会创建一个新的数组,其容量通常是当前数组的 1.5 倍(确切地说,新容量 = 当前容量 + (当前容量 >> 1)),然后将所有现有元素复制到新数组中。添加新元素:在新数组中,将新元素添加到适当的位置。ArrayList list = new ArrayList(20);中的list扩充几次A 0B 1C 2D 3正确答案:A你的答案:B38.类的final成员变量必须满足以下其中一个条件1、在构造函数中赋值 2、初始化赋值class Foo { final int i; int j; public void doSomething() { System.out.println(++j + i); } }的输出是?A 0B 1C 2D 不能执行,因为编译有错正确答案:D你的答案:B39.定义在同一个包(package)内的类可以不经过import而直接相互使用40.static不能修饰局部变量关于下面的程序Test.java说法正确的是( )。public class Test { static String x="1"; static int y=1; public static void main(String args[]) { static int z=2; System.out.println(x+y+z); } }A 3B 112C 13D 程序有编译错误正确答案:D你的答案:B41.java标识符规则标识符的组成元素是字母(a-z,A-Z),数字(0~9),下划线(_)和美元符号($)。 标识符不能以数字开头。 java的标识符是严格区分大小写的。 标识符的长度可以是任意的。 关键字以及null、true、false不能用于自定义的标识符。下列可作为java语言标识符的是()A a1B $1C _1D 11正确答案:ABC你的答案:AC42.replaceAll()函数的第一个参数是一个正则表达式以下代码将打印出public static void main (String[] args) { String classFile = "com.jd.". replaceAll(".", "/") + "MyClass.class"; System.out.println(classFile); }A com. jdB com/jd/MyClass.classC ///////MyClass.classD com.jd.MyClass正确答案:C你的答案:B官方解析:本题有一处陷阱,replaceAll()函数的第一个参数是一个正则表达式,而"."在正则表达式中代表了全部的字符,因此"com.jd."会全部被替换成"/"。之后字符串正常拼接,输出"///////MyClass.class",答案选择C。如想仅仅替换".",就需要使用转义字符"\."知识点:Java、正则表达式43.关于java的内部类44.Java一维数组的两种初始化方法1、静态初始化int array[] = new int[]{1,2,3,4,5} // 或者 int array[] = {1,2,3,4,5} //需要注意的是,写成如下形式也是错误的 int array[] = new int[5]{1,2,3,4,5}2、动态初始化int array[] = new int[5]; array[0] = 1; array[1] = 2; array[2] = 3; array[3] = 4; array[4] = 5;静态与动态初始化的区别就在于,前者是声明的时候就初始化,后者是先声明,再动态初始化。45.List<>赋值给List<>的限制只看尖括号里边的!!明确点和范围两个概念如果尖括号里的是一个类,那么尖括号里的就是一个点,比如List<A>,List<B>,List<Object>如果尖括号里面带有问号,那么代表一个范围,<? extends A>代表小于等于A的范围,<? super A>代表大于等于A的范围,<?>代表全部范围尖括号里的所有点之间互相赋值都是错,除非是俩相同的点尖括号小范围赋值给大范围,对,大范围赋值给小范围,错。如果某点包含在某个范围里,那么可以赋值,否则,不能赋值List<?>和List 是相等的,都代表最大范围补充:List既是点也是范围,当表示范围时,表示最大范围class A {}class B extends A {}class C extends A {}class D extends B {}下面的哪4个语句是正确的?A The type List<A>is assignable to List.B The type List<B>is assignable to List<A>.C The type List<Object>is assignable to List<?>.D The type List<D>is assignable to List<?extends B>.E The type List<?extends A>is assignable to List<A>.F The type List<Object>is assignable to any List reference.G The type List<?extends B>is assignable to List<?extends A>.正确答案:ACDG你的答案:CDEG46.关于final:修饰方法影响重写,但是不影响重载final修饰方法后,方法是不可被重写的,因为它已经是“最终形态”了。但不会影响重载以下说法错误的是( )A final修饰的方法不能被重载B final可以修饰类、接口、抽象类、方法和属性C final修饰的方法也不能被重写D final修饰的属性是常量,不可以修改正确答案:AB你的答案:B47.关于java的自动类型转换和强制类型转换数据类型的转换,分为自动转换和强制转换。自动转换是程序在执行过程中 “ 悄然 ” 进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换;强制类型转换则必须在代码中声明,转换顺序不受限制。 自动数据类型转换 自动转换按从低到高的顺序转换。不同类型数据间的优先关系如下: 低 ---------------------------------------------> 高 byte,short,char-> int -> long -> float -> double运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下: 运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下:操作数 1 类型操作数 2 类型转换后的类型byte 、 short 、 charintintbyte 、 short 、 char 、 intlonglongbyte 、 short 、 char 、 int 、 longfloatfloatbyte 、 short 、 char 、 int 、 long 、 floatdoubledouble强制数据类型转换 强制转换的格式是在需要转型的数据前加上 “( )” ,然后在括号内加入需要转化的数据类型。有的数据经过转型运算后,精度会丢失,而有的会更加精确设计模式1.备忘录模式(Memento pattern)当你需要让对象返回之前的状态时(例如, 你的用户请求"撤销"), 你使用备忘录模式现在大多数软件都有撤销(Undo)的功能,快捷键一般都是Ctrl+Z。这些软件可能使用了()模式来进行。A 备忘录模式B 访问者模式C 模板方法模式D 责任链正确答案:A你的答案:Dspring1.Spring事务参考资料:Spring事务管理详解-CSDN博客Spring事务的传播属性Spring定义了7个以PROPAGATION\_开头的常量表示它的传播属性。名称值解释PROPAGATION\_REQUIRED0支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是Spring默认的事务的传播。PROPAGATION\_SUPPORTS1支持当前事务,如果当前没有事务,就以非事务方式执行。PROPAGATION\_MANDATORY2支持当前事务,如果当前没有事务,就抛出异常。PROPAGATION\_REQUIRES\_NEW3新建事务,如果当前存在事务,把当前事务挂起。PROPAGATION\_NOT\_SUPPORTED4以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。PROPAGATION\_NEVER5以非事务方式执行,如果当前存在事务,则抛出异常。PROPAGATION\_NESTED6如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION\_REQUIRED类似的操作。Spring事务的隔离级别名称值解释ISOLATION\_DEFAULT-1这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应ISOLATION\_READ\_UNCOMMITTED1这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。ISOLATION\_READ\_COMMITTED2保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。ISOLATION\_REPEATABLE\_READ4这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。ISOLATION\_SERIALIZABLE8这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。2.@Autowired注解用@Autowired注入的流程为 :1.先根据类型进行实现类的匹配,多个实现类则不适用 2.多个实现类则会变为根据名称来匹配,就是比较注入的变量名称是否与实现类的名称相同有如下接口:public interface Student{ public void introduce(); }该接口有两个实现类:@Component public class StudentImplXH implements Student { @Override public void introduce() { System.out.println("我叫小华"); } } @Component public class StudentImplXM implements Student{ @Override public void introduce() { System.out.println("我叫小明"); } }测试类中代码如下:@Autowired private Student student; @Test void StudentTest(){ student.introduce();运行测试代码,控制台会输出什么结果?( )A 我叫小华我叫小明B我叫小华C我叫小明D程序发生异常正确答案:D你的答案:C官方解析:@Autowired注解提供这样的规则,首先根据类型找到对应的Bean,如果对应类型的 Bean 不是唯一的,那么就根据属性名称和Bean的名称进行匹配。如果匹配得上,就会使用该Bean。如果还无法匹配,就会抛出异常。3.BeanFactory和FactoryBeanBeanFactory是所有Spring Bean的容器根接口,其给IoC容器提供了一套完整的规范。FactoryBean是 一种创建Bean的方式,是对Bean的一种扩展。4.Spring容器中Bean作用域• singleton:在每个Spring IoC容器中只有一个Bean实例。 • prototype:一个Bean的定义可以有多个实例。 • request:在Web应用中,为每个HTTP请求创建一个Bean实例。 • session:在Web应用中,为每个HTTP会话创建一个Bean实例。 • global session:在基于portlet的Web应用中,为每个全局HTTP会话创建一个Bean实例。数据库理论1. 在数据库系统中,产生不一致的原因数据库中可能存在不一致的数据,主要有以下三个方面:A.数据冗余;B.并发控制不当;C.故障或者错误下面选项中,在数据库系统中,产生不一致的最重要原因是( )A 数据存储量太大B 没有严格保护数据C 未对数据进行完整性控制D 数据冗余正确答案:D你的答案:C参考答案:选D 数据库中有可能会存在不一致的数据。 造成数据不一致的原因主要有: 数据冗余 如果数据库中存在冗余数据,比如两张表中都存储了用户的地址,在用户的地址发生改变时,如果只更新了一张表中的数据,那么这两张表中就有了不一致的数据。 并发控制不当 比如某个订票系统中,两个用户在同一时间订同一张票,如果并发控制不当,可能会导致一张票被两个用户预订的情况。当然这也与元数据的设计有关。 故障和错误 如果软硬件发生故障造成数据丢失等情况,也可能引起数据不一致的情况。因此我们需要提供数据库维护和数据恢复的一些措施。知识点:数据库2.数据库设计的六个阶段1、需求分析:分析用户的需求,包括数据、功能和性能需求 2、概念结构设计:主要采用E-R模型进行设计,包括画E-R图 3、逻辑结构设计:通过将E-R图转换成表,实现从E-R模型到关系模型的转换 4、数据库物理设计:主要是为所设计的数据库选择合适的存储结构和存取路径 5、数据库的实施:包括编程、测试和试运行 6、数据库运行与维护:系统的运行与数据库的日常维护
2023年12月30日
36 阅读
4 评论
0 点赞
1
2
...
6