【业务功能篇56】SpringBoot 日志SLF4J Logback

news2024/9/25 7:21:16

3.5.1 日志框架分类与选择

3.5.1.1 日志框架的分类

日志门面 (日志抽象)日志实现
JCL(Jakarta Commons Logging) SLF4J(Simple Logging Facade for Java)Jul(Java Util Logging) , Log4j , Log4j2 , Logback

记录型日志框架

  1. Jul (Java Util Logging):JDK中的日志记录工具,也常称为JDKLog、jdk-logging,自Java1.4以来的官方日志实现。
  2. Log4j:Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。
  3. Log4j2:一个具体的日志实现框架,是Log4j 1的下一个版本,与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1
  4. Logback:一个具体的日志实现框架,和Slf4j是同一个作者,但其性能更好(推荐使用)。

门面型日志框架

  1. JCL:Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging
  2. SLF4J:是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)

3.5.1.2 日志框架的选择

选择日志框架的方式,就是先选择一个门面(抽象层) ,然后再选择一个实现

  • **日志门面: SLFJ **
  • 日志实现: LogBack

Spring默认使用JCL

SpringBoot默认选用的是SLF4J和 Logback.

Slf4j的设计思想比较简洁,使用了Facade设计模式,Slf4j本身只提供了一个slf4j-api-version.jar包,这个jar中主要是日志的抽象接口,jar中本身并没有对抽象出来的接口做实现。

对于不同的日志实现方案(例如Logback,Log4j…),封装出不同的桥接组件(例如logback-classic-version.jar,slf4j-log4j12-version.jar),这样使用过程中可以灵活的选取自己项目里的日志实现。

3.5.2 SLF4J日志框架

3.5.2.1 如何使用SLF4j

日志方法的调用,不要直接调用日志的实现类, 而是调用日志抽象层里的方法 (面向抽象编程).

阿里的开发手册上有一条关于日志的规范:

  • **强制:应用中不可直接使用日志系统(log4j、logback)中的 API ,而应依赖使用日志框架 SLF4J 中的 API 。使用门面模式的日志框架,有利于维护和各个类的日志处理方式的统一。 **

image.png

日志框架之间的关系

  • Slf4j的设计思想比较简洁,使用了Facade设计模式,Slf4j本身只提供了一个slf4j-api-version.jar包,这个jar中主要是日志的抽象接口,jar中本身并没有对抽象出来的接口做实现。

image.png

代码示例

 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class HelloWorld {
 
   public static void main(String[] args) {
     Logger logger = LoggerFactory.getLogger(HelloWorld.class);
     logger.info("Hello World");
   }
 }

配置文件

  • **每一个日志实现框架都有自己的配置文件,使用slf4j之后,**配置文件还是选用具体日志实现框架的配置文件.

3.5.2.2 其他日志框架转换为slf4j

  • Slf4j的设计思想比较简洁,使用了Facade设计模式,Slf4j本身只提供了一个slf4j-api-version.jar包,这个jar中主要是日志的抽象接口,jar中本身并没有对抽象出来的接口做实现。
  • 对于不同的日志实现方案(例如Log4j…),封装出不同的桥接组件(例如: slf4j-log4j12-version.jar),这样使用过程中可以灵活的选取自己项目里的日志实现。

SLF4j与其它日志组件集成

image.png

应用调了sl4j-api,日志门面接口。日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,上图红框中的组件即是对应的各种桥接器!

3.5.3 SpringBoot结合logback输出日志

3.5.3.1 SpringBoot日志关系

在SpringBoot中,底层是Spring框架,Spring框架默认使用JCL,而****SpringBoot默认集成的日志框架使用的是SLF4j+Logback组合

**因为 **spring-boot-starter-logging 是Logback的日志实现,而Spring Boot启动项spring-boot-starter又依赖了spring-boot-starter-logging,所以Spring Boot就默认集成了Logback。

image.png

SpringBoot默认集成了Logback,可以开箱即用,非常方便。在基于SpringBoot实现的系统中,使用SLF4j方法如下:

日志记录方法的调用,不应该来直接调用日志的实现类,而是应该调用日志抽象层的方法,即直接使用SLF4j日志门面。

在代码中使用的方式如下:

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class LogDemo {

    private final Logger logger = LoggerFactory.getLogger(LogDemo.class);


    @Test
    public void testLog(){
        Logger logger = LoggerFactory.getLogger(LogDemo.class);
        logger.info("Hello LogBack!");
    }
}
 
 //打印结果
 15:16:26.759 [main] INFO  c.m.h.log.LogDemo - [main,15] - Hello LOG !
 

image.png

3.5.3.2 logback配置文件

在resources文件夹下创建 logback.xml,logback会自动在该目录下加载该配置文件,在该文件中对打印日志的级别、形式、保存路径等进行配置。

https://www.springcloud.cc/spring-boot.html#boot-features-logging-format

image.png

如果可能,我们建议您使用 -spring变体进行日志记录配置(例如,logback-spring.xml而不是 logback.xml)。如果使用标准配置位置,Spring无法完全控制日志初始化。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 日志存放路径 -->
    <property name="log.path" value="/home/hejiayun/logs" />

    <!-- 日志输出格式 -->
<!--    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />-->


    <property name="log.pattern"
              value="%red(%date{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %red([%thread]) %boldMagenta(%logger{50}) - [%method,%line] - %cyan(%msg%n)"/>
    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    <!-- 系统日志输出 -->
    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-info.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 60天 -->
            <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>INFO</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onMatch>ACCEPT</onMatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-error.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 60天 -->
            <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>ERROR</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onMatch>ACCEPT</onMatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 用户访问日志输出  -->
    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-user.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 60天 -->
            <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    <!-- 系统模块日志级别控制  -->
    <logger name="com.msb" level="info" />
    <!-- Spring日志级别控制  -->
    <logger name="org.springframework" level="warn" />

    <root level="info">
        <appender-ref ref="console" />
    </root>

    <!--系统操作日志-->
    <root level="info">
        <appender-ref ref="file_info" />
        <appender-ref ref="file_error" />
    </root>

    <!--系统用户操作日志-->
    <logger name="sys-user" level="info">
        <appender-ref ref="sys-user"/>
    </logger>
</configuration>

 <configuration  scan="true" scanPeriod="60 seconds" debug="false">
3.5.3.2.1 configuration 根节点

configuration 根节点包含的属性:

  • scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
  • scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
  • debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
 <configuration> 的子节点有contextName、property、appender、logger、root等,其中contextName和property是属性节点,appender、root、logger是
3.5.3.2.2 property节点

property标签可用于自定义属性,比如定义一个property name=“log.pattern”,然后使用${log.pattern}去引用它。

 <!-- 日志存放路径 -->
 <property name="log.path" value="/home/hejiayun/logs" />
 <!-- 日志输出格式 -->
 <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

日志输出格式说明

 %d表示时间
 
 %thread表示线程名
 
 %-5level 表示日志级别,允许以五个字符长度输出
 
 %logger{20}表示具体的日志输出者,比如类名,括号内表示长度
 
 %method:表示方法名字
 
 %line:表示第几行
 
 %msg表示具体的日志消息,就是logger.info("xxx")中的xxx
 
 %n表示换行
3.5.3.2.3 appender节点

是负责写日志的组件,在这里可以理解为一个日志的渲染器,比如console日志选择器、文件渲染器。有两个必要属性name和class:

  • name指定的名称,表示该渲染器的名字。
  • class指定的全限定名,表示使用的输出策略,常见的有控制台输出策略和文件输出策略。

appender日志输出方式实现类:ConsoleAppender、FileAppender、RollingFileAppender、SocketAppender、SMTPAppender、DBAppender、SyslogAppender、SiftingAppender等.

平时主要使用的是 ConsoleAppenderRollingFileAppender,其中 ConsoleAppender是往控制台打印日志,RollingFileAppender是往磁盘文件追加日志,而且可以按照一定的设置方式动态分割日志

1) 控制台输出–ConsoleAppender

 <!-- 控制台输出 -->
 <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
     <encoder>
         <pattern>${log.pattern}</pattern>
     </encoder>
 </appender>

encoder表示输出格式

2) 文件输入RollingFileAppender

文件输出主要包括配置:以指定格式将日志输出到指定文件夹下的文件中,可以配置该文件的名称、最大大小、保存时间等。

 <!-- 系统日志输出 -->
 <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
     <file>${log.path}/sys-info.log</file>
     <!-- 循环政策:基于时间创建日志文件 -->
     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <!-- 日志文件名格式 -->
         <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
         <!-- 日志最大的历史 60天 -->
         <maxHistory>60</maxHistory>
     </rollingPolicy>
     <encoder>
         <pattern>${log.pattern}</pattern>
     </encoder>
     <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <!-- 过滤的级别 -->
         <level>INFO</level>
         <!-- 匹配时的操作:接收(记录) -->
         <onMatch>ACCEPT</onMatch>
         <!-- 不匹配时的操作:拒绝(不记录) -->
         <onMismatch>DENY</onMismatch>
     </filter>
 </appender>
  1. <rollingPolicy>:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名(重命名文件)。<rollingPolicy>的作用是当发生滚动时,定义RollingFileAppender的行为,其中上面的TimeBasedRollingPolicy是最常用的滚动策略,它根据时间指定滚动策略,既负责滚动也负责触发滚动,有以下节点:
  2. <fileNamePattern>,必要节点,包含文件名及"%d"转换符,"%d"可以包含一个Java.text.SimpleDateFormat指定的时间格式,如%d{yyyy-MM},如果直接使用%d那么格式为yyyy-MM-dd。RollingFileAppender的file子节点可有可无,通过设置file可以为活动文件和归档文件指定不同的位置。
  3. <maxHistory>,可选节点,控制保留的归档文件的最大数量,如果超出数量就删除旧文件,假设设置每个月滚动且 <maxHistory>是6,则只保存最近6个月的文件。
  4. <filter> logbcak允许给日志记录器appender配置一个或多个Filter(或者给整体配置一个或多个TurboFilter),来控制:当满足过滤器指定的条件时,才记录日志(或不满足条件时,拒绝记录日志)
     只记录ERROR级别的日志,其他级别的日志拒绝记录
     <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <!-- 过滤的级别 -->
         <level>ERROR</level>
         <!-- 匹配时的操作:接收(记录) -->
         <onMatch>ACCEPT</onMatch>
         <!-- 不匹配时的操作:拒绝(不记录) -->
         <onMismatch>DENY</onMismatch>
     </filter>
    
3.5.2.3.3 logger节点

<logger>用来设置某一个包或者具体某一个类的日志打印级别、以及指定 <appender><logger>可以包含零个或者多个 <appender-ref>元素,标识这个appender将会添加到这个logger。<logger>仅有一个name属性、一个可选的level属性和一个可选的additivity属性:

 <!-- 系统模块日志级别控制  -->
 <logger name="com.msb" level="info" />
 
 <!-- Spring日志级别控制  -->
 <logger name="org.springframework" level="warn" />
  • name:用来指定受此logger约束的某一个包或者具体的某一个类
  • level:用来设置打印级别,五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR,如果未设置此级别,那么当前logger会继承上级的级别
  • additivity:是否向上级logger传递打印信息,默认为true。
3.5.2.3.4 root节点

root节点实际上是配置启用哪种appender,可以添加多个appender。<root>也是 <logger>元素,但是它是根logger,只有一个level属性,因为它的name就是ROOT。 如果没有指定logger,则那么所有的logger都会继承根logger的level。

 <root level="info">
     <appender-ref ref="console" />
 </root>
 
 <!--系统操作日志-->
 <root level="info">
     <appender-ref ref="file_info" />
     <appender-ref ref="file_error" />
 </root>

appender-ref : 表示level为info级别,启用渲染器`CONSOLE


3.5.3.3 如何进行日志打印

3.5.3.3.1 日志打印级别
 TRACE < DEBUG < INFO <  WARN < ERROR
  • TRACE : 级别最小,打印最详细,使用较少
  • DEBUG:主要用于调试阶段输出,此日志应尽可能详尽。DEBUG日志应该以调试人员满足调试需求为主,生产环境不应输出debug级别日志。
  • INFO:主要用来反馈系统当前状态的输出,应视为系统产品最终呈现给用户的一部分,因此不可滥用。INFO级别通常用来进行日常运维以及错误回溯时查看上下文场景。通过INFO日志可以了解系统的运行情况,对系统进行监控。
  • WARN:主要针对可预知,有解决预案的错误,如下单数量超过该用户所持总量的情况。WARN级别打印关键信息即可,事后用于分析错误原因。
  • ERROR:主要针对不可预知的信息,比如异常和错误。ERROR级别通常指一些较为严重的异常发生,所以需要尽可能多的打印出详细信息,如方法的入参,执行过程产生数据等。

image.png

详解:

  • 项目中设置的日志级别为:TRACE,包括 TRACE / DEBUG / INFO / WARN / ERROR 的日志级别都打印
  • 项目中设置的日志级别为:DEBUG ,包括 DEBUG / INFO / WARN / ERROR 的日志级别都打印
  • 项目中设置的日志级别为:INFO ,包括 INFO / WARN / ERROR 的日志级别都打印
  • 项目中设置的日志级别为:WARN,包括 WARN / ERROR 的日志级别都打印
  • 项目中设置的日志级别为:ERROR ,只打印 ERROR 的日志级别都打印
3.5.3.3.2 日志打印方式
 @RunWith(SpringRunner.class)
 @SpringBootTest
 @Slf4j
 public class LogDemo {
 
     private final Logger logger = LoggerFactory.getLogger(LogDemo.class);
 
     /**
      * 传统方式实现日志
      */
     @Test
     public void test1(){
         logger.error("发生了严重错误,程序阻断了,需要立即处理,发送警报");
         logger.warn("这个错误很少见,不影响程序继续运行,酌情处理");
         logger.info("没有什么问题,单纯想打印个日志");
         logger.debug("你经常写BUG,测试的时候,多打点日志");
         logger.trace("这个级别很少用,为了追踪");
     }
 
     /**
      * Slf4j注解方式实现日志
      * 每次写新的类,就需要重新写logger,麻烦,可以使用@Slf4j注解简化:
      */
     @Test
     public void test2(){
         log.error("发生了严重错误,程序阻断了,需要立即处理,发送警报");
         log.warn("这个错误很少见,不影响程序继续运行,酌情处理");
         log.info("没有什么问题,单纯想打印个日志");
         log.debug("你经常写BUG,测试的时候,多打点日志");
         log.trace("这个级别很少用,为了追踪");
     }
 }
3.5.3.3.2 日志打印实操

日志打印的规范介绍

  • 输出Exceptions的全部Throwable信息
  • 出于日志文件储存和性能的考虑,建议为可能会大量出现的低级别日志添加判断
  • 尽量使用占位符而不是拼接来打印日志,这样的可读性更高,而且只有打印时才会处理函数,提升效率
     @Test
     public void logNorm(){
 
         //使用{}作为占位符,而不是字符串拼接
         String name = "我是大佬";
         log.info("hello {}",name);
         log.debug("hello " + name);
 
         String userId = "10010";
         String orderId = "3242343253253535";
         log.debug("order is paying with userId:[{}] and orderId : [{}]",userId, orderId);
 
         // e.printStackTrace();不使用这种,打印堆栈日志与业务日志混合
         try {
             int i = 1 / 0;
         } catch (Exception e) {
 //            e.printStackTrace();
             log.error("/ by zero",e);
         }
 
         //先拼接字符串“hello”和“name”。然后执行debug方法,判断日志级别。
         log.debug("hello" + name);
 
         //不提前拼接,先判断日志级别, 然后选择是否执行debug方法,拼接字符串“hello”和“world”
         //isDebugEnabled() 可以避免无用的字符串操作,提高性能
         if(log.isDebugEnabled()){
             log.debug("hello" + name);
         }
     }

日志打印的注意事项

  • 尽量不要在日志中调用方法获取值,否则会因为日志而报出空指针异常。(日志不能打断业务逻辑)
  • 上线后除了进行常规的测试外,应可以通过对日志进行观察来判断新功能是否工作正常。
  • 对不同类型的日志进行分类输出,比如ERROR日志单独输出,防止日志数量过大时不利于分析错误信息。
  • 日志文件一般保留周期为15天,防止以周为单位的错误出现,应设置定时任务删除过期日志(如15天前)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

山西电力市场日前价格预测【2023-07-29】

日前价格预测 预测明日&#xff08;2023-07-29&#xff09;山西电力市场全天平均日前电价为337.82元/MWh。其中&#xff0c;最高日前电价为355.66元/MWh&#xff0c;预计出现在09: 15。最低日前电价为314.90元/MWh&#xff0c;预计出现在24: 00。 价差方向预测 1&#xff1a;实…

MySQL基础语法(DDL、DQL、DML、DCL)

目录 SQL通用语法以及分类 SQL通用语法 SQL语句的分类 数据库/表/列的命名规则 DDL语句 DDL设计的数据类型 数据库操作 表操作&#xff08;必须先进入到数据库&#xff09; DQL语句 DQL的执行顺序 基本查询 SELECT 条件查询 WHERE 分组查询 GROUP BY 排序查询 OR…

formatter的用法,深拷贝, Object.assign 方法实战。

1. :formatter的用法 :formatter 接受一个函数作为参数&#xff0c;这个函数有三个参数&#xff1a;row&#xff0c;column 和 cellValue。row 是当前行的数据&#xff0c;column 是当前列的数据&#xff0c;cellValue 是当前单元格的值。 <el-table-column prop"SYS…

Spring Boot——Spring Boot启动原理

系列文章目录 Spring Boot启动原理 系列文章目录一、Spring Boot启动的宏观流程图二、Spring Boot启动流程2.1 初始化new SpringApplication2.1.1Spring Boot入口2.1.2初始化SpringApplication2.1.2.1判断当前应用程序类型2.1.2.2设置应用程序的所有初始化器(initializers)2.1.…

内置 NMOS 单路 PWM 控制的高调光比 LED 降压恒流控制器

概述 OC5401M 是一款内置调光 NMOS 的单路 PWM 控制的高调光比降压恒流驱动控制器&#xff0c;PWM 调光比最高可达 10000&#xff1a;1。 OC5401M 支持 16-60V 输入电压范围。 OC5401M 采用电流滞环控制方式&#xff0c;无需环路补偿。 OC5401M 可通过外接电阻设置 LED输出电流…

Python(四十九)获取列表指定元素的索引

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

Improving Cross-Modal Retrieval with Set of Diverse Embeddings

框架图&#xff1a; Using Triplet Loss: Smooth-Chamfer similarity Using Log-Sum-Exp,

matplotlib从起点出发(5)_Tutorial_5_styleSheets

1 使用样式表和rcParams自定义matplotlib 以下是自定义matplotlib的属性和默认样式的提示。 有三种方式来自定义matplotlib: 在运行时设置rcParams&#xff1b;使用样式表&#xff1b;改写matplotlibrc文件。 在运行时设置rcParams优先于样式表&#xff0c;样式表优先于matp…

[JavaWeb]SQL介绍-DDL语句

SQL介绍-DDL语句 一.SQL简介1.简介2.SQL通用语法3.SQL语言的分类 二.DDL-操作数据库与表1.DDL操作数据库2.DDL操作表①.查询表(Retrieve)②.创建表(Create)③.修改表(Update)④.删除表(Delete) 一.SQL简介 1.简介 SQL: Structured Query Language–结构化查询语言用来操作关系…

如图,△ABC中,AD是角平分线,E、F分别为AC、AB上的点,且∠AED+∠AFD=180°.试问:DE与DF有何关系,并说明理由.

Question&#xff1a; 如图&#xff0c;△ABC中&#xff0c;AD是角平分线&#xff0c;E、F分别为AC、AB上的点&#xff0c;且∠AED∠AFD180&#xff0e;试问&#xff1a;DE与DF有何关系&#xff0c;并说明理由&#xff0e; Answer&#xff1a; 分析&#xff1a;过D作DM⊥AB于…

postgresql搭建主备

文章目录 1. 要求2. 主库设置3. 主库创建复制槽、复制用户4. 导出主库5. 备库设置6. 备库创建standby.signal7. 启动备库8. 备库创建复制槽、查询数据9. 查看日志10. 测试切换11. 同步测试12. 监控主备状态 1. 要求 1.使用流复制&#xff0c;配置复制槽 2.只有一个备库时不配置…

技术分享 | 接口自动化测试中,文件上传该如何测试?

在服务端自动化测试过程中&#xff0c;文件上传类型的接口对应的请求头中的 content-type 为 multipart/form-data; boundary…&#xff0c;碰到这种类型的接口&#xff0c;使用 Java 的 REST Assured 或者 Python 的 Requests 均可解决。 实战练习 Python 版本 在 Python 版…

Mysql原理篇--第三章 事务与锁

文章目录 前言一、mysql 的事务1 .1 mysql 事务:1 .2 mysql 为什么要支持事务: 二、mysql的事务实现&#xff1a;2.1 mysql的事务隔离级别&#xff1a;2.2 mysql 脏读&#xff0c;不可重复读&#xff0c;幻读&#xff1a;2.2.1 脏读&#xff1a;2.2.2 不可重复读&#xff1a;2.…

生态共建 | 5-6月,YashanDB与14款产品完成兼容互认证

5-6月&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB与中科可控信息产业有限公司、云基智慧工程股份有限公司、上海天玑数据技术有限公司、金蝶软件&#xff08;中国&#xff09;有限公司、上海布雷德科技有限公司、深圳市杉岩数据技术有限公司、广东中兴新支点技术有限…

prometheus和cAdvisor组合

文章目录 docker内部署PromethuesPrometheuscAdvisorPrometheus和cAdvisor关系配置 docker内部署Promethues Prometheus Prometheus是一个开源的系统监控和报警工具&#xff0c;由SoundCloud开发并在2012年捐赠给了Cloud Native Computing Foundation (CNCF)。它被广泛用于监…

CAN学习笔记1:计算机网络

计算机网络 1 概述 计算机网络就是把多种形式的计算机用通信线路连接起来&#xff0c;并使其能够互相进行交换的系统。实际上&#xff0c;计算机网络包括了计算机、各种硬件、各种软件、组成网络的体系结构、网络传输介质和网络通信计数。因此&#xff0c;计算机网络是计算机…

第G3周:CGAN|生成手势图像

目录 一、准备工作1. 导入数据2. 数据可视化 二、构建模型1. 构建生成器2. 构建鉴别器 三、训练模型1. 定义损失函数2. 定义优化器3. 训练模型 四、理论基础1.DCGAN原理2.DCGAN网络3.个人感悟 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f…

自动化测试:让软件测试更高效更愉快!

谈谈那些实习测试工程师应该掌握的基础知识&#xff08;一&#xff09;_什么时候才能变强的博客-CSDN博客https://blog.csdn.net/qq_17496235/article/details/131839453谈谈那些实习测试工程师应该掌握的基础知识&#xff08;二&#xff09;_什么时候才能变强的博客-CSDN博客h…

【C++ 进阶】学习导论:C/C++ 进阶学习路线、大纲与目标

目录 一、C 学习路线 二、C 课程大纲与学习目标 &#xff08;1&#xff09;第一阶段&#xff1a;C 语言基础 &#xff08;2&#xff09;第二阶段&#xff1a;C 高级编程 &#xff08;3&#xff09;第三阶段&#xff1a;C 核心编程与桌面应用开发 &#xff08;4&#xf…

Cpp03 — 类和对象、this指针

一、类和对象 类由两部分构成&#xff1a;1.成员变量2.成员函数 C中的struct兼容C的所有用法&#xff0c;同时C中把struct升级成类 注意&#xff1a;类中的成员函数和成员数据都是声明&#xff0c;不是定义 类里的函数不是存到了对象中&#xff0c;而是存在公共区域&#x…