Springboot整合定时任务quartz(非集群)

文章目录

  • 前言
  • 一、Springboot 整合
    • 1.1 Springboot 初步整合quartz
      • 1.1 jar 引入:
      • 1.2 添加任务:
        • 1.2.1 方式1 PostConstruct 注入任务:
        • 1.2.2 方式2 @Bean 注入任务:
  • 二、quartz持久化:
    • 2.1 mysql 引入:
    • 2.2 业务共用一个数据源:
      • 2.2.1 配置jdbc datasource:
      • 2.2.2 Springboot 整合quartz 持久化:
    • 2.3 Springboot 整合quartz 持久化(独立数据源)
  • 三、 扩展:
    • 3.1 initialize-schema 初始化:
  • 四、总结:
  • 五、参考:


前言

在 工具篇-- 定时任务quartz 我们已经知道了quartz 的基本特性和简单使用,在项目开发中我们通常都是集成到springboot 项目中。


一、Springboot 整合

1.1 Springboot 初步整合quartz

1.1 jar 引入:

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-quartz -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

1.2 添加任务:

1.2.1 方式1 PostConstruct 注入任务:

JobInit :

import com.example.springmvctest.job.quartz.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

// 定义 JobInit  为一个bean 从而可以被spring 管理
@Component
public class JobInit {

    @Autowired
    private Scheduler scheduler;

	// JobInit  这个bean 在初始化之后调用的方法
    @PostConstruct
    public  void  job(){
        // 每次执行 都生成新的  MyJob 实例,避免并发情境下,多个线程共用一个MyJob 的实例
        JobDetail jobDetail = JobBuilder.newJob(QuartzTest.class)
                .usingJobData("job","jobDetail")
                .usingJobData("name","jobDetail")
                .usingJobData("count",0)
                .withIdentity("job","group1").build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1","trigger1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                        .repeatForever())
                .usingJobData("trigger","trigger")
                .usingJobData("name","trigger")
                .build();


        try {
            scheduler.scheduleJob(jobDetail,trigger);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }

    }
}

任务执行:
(1) 任务定义:
QuartzTest :

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringJoiner;

public class QuartzTest extends QuartzJobBean {
    @Autowired
    private HelloService helloService;
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        System.out.println("\"job 执行\" = " + "job 执行" + sdf.format(new Date()));
        StringJoiner outStr = new StringJoiner("")
                .add("QuartzTest 执行")
                .add(sdf.format(new Date()))
                .add(Thread.currentThread().getName())
                .add(context.getTrigger().getKey().getName())
                .add(helloService.toString())
                .add(helloService.hello());

        System.out.println(outStr);
    }
}

(2) HelloService :

import org.springframework.stereotype.Service;

@Service
public class HelloService {

    public String hello(){
        return "hello";
    }
}
1.2.2 方式2 @Bean 注入任务:

JobConfigure :中定义的JobDetail 和Trigger 会自动被 scheduler 关联起来

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JobConfigure {

    @Bean
    public JobDetail jobDetail1() {
        return JobBuilder.newJob(QuartzTest.class)
                .usingJobData("job", "jobDetail")
                .usingJobData("name", "jobDetail")
                .usingJobData("count", 0)
                .storeDurably()
                .withIdentity("jobConfigure", "group1").build();
    }

    @Bean
    public Trigger trigger1() {
        return TriggerBuilder.newTrigger()
                .withIdentity("triggerConfigure", "trigger1")
                .forJob("jobConfigure","group1")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                        .repeatForever())
                .usingJobData("trigger", "trigger")
                .usingJobData("name", "trigger")
                .build();
    }

    @Bean
    public JobDetail jobDetail2() {
        return JobBuilder.newJob(QuartzTest.class)
                .usingJobData("job", "jobDetail2")
                .usingJobData("name", "jobDetail2")
                .usingJobData("count", 0)
                .storeDurably()
                .withIdentity("jobConfigure2", "group1").build();
    }

    @Bean
    public Trigger trigger2() {
        return TriggerBuilder.newTrigger()
                .withIdentity("triggerConfigure2", "trigger2")
                .forJob("jobConfigure2","group1")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)
                        .repeatForever())
                .usingJobData("trigger", "trigger2")
                .usingJobData("name", "trigger2")
                .build();
    }
}

在这里插入图片描述

二、quartz持久化:

如果不将Job 进行持久化,那么Job 只存在于内存中,一旦项目重启,之前的任务状态将全部丢失,所以quartz 还支持通过关系型数据库将任务持久化:

2.1 mysql 引入:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<!-- 分页 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.6</version>
</dependency>

2.2 业务共用一个数据源:

业务系统和定时任务使用同一个数据源。

2.2.1 配置jdbc datasource:

(1)HikariBaseConfig:

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Configuration;

/**
 * 线程池
 */
@Configuration
public class HikariBaseConfig {

    @Value("${spring.datasource.hikari.pool-name}")
    private String poolName;
    @Value("${spring.datasource.hikari.maximum-pool-size}")
    private Integer maximumPoolSize;
    @Value("${spring.datasource.hikari.connection-timeout}")
    private Long connectionTimeout;
    @Value("${spring.datasource.hikari.minimum-idle}")
    private Integer minimumIdle;
    @Value("${spring.datasource.hikari.max-lifetime}")
    private Long maxLifetime;
    @Value("${spring.datasource.hikari.connection-test-query}")
    private String connectionTestQuery;


    public HikariDataSource getDataSource(String driverClassName, String url, String username, String password){
        HikariDataSource hikariDataSource = DataSourceBuilder.create().type(HikariDataSource.class).driverClassName(driverClassName).username(username).url(url).password(password).build();
        hikariDataSource.setConnectionTestQuery(connectionTestQuery);
        hikariDataSource.setMaxLifetime(maxLifetime);
        hikariDataSource.setMinimumIdle(minimumIdle);
        hikariDataSource.setConnectionTimeout(connectionTimeout);
        hikariDataSource.setPoolName(poolName);
        hikariDataSource.setMaximumPoolSize(maximumPoolSize);
        return hikariDataSource;
    }

}

(2)DataSourceConfig:


//import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
//import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
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.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.github.pagehelper.PageHelper;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @Description TODO
 * @Date 2021/11/18 11:00
 * @Author lgx
 * @Version 1.0
 */
// 标明注解
@Configuration
// 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可
@EnableTransactionManagement
// 配置xml 扫描文件位置
@MapperScan(basePackages = {"com.example.springmvctest.mapper"}, sqlSessionFactoryRef = "bluegrassSqlSessionFactory")
public class DataSourceConfig {
    @Value("${spring.datasource.bluegrass.jdbc-url}")
    private String url;

    @Value("${spring.datasource.bluegrass.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.bluegrass.username}")
    private String username;

    @Value("${spring.datasource.bluegrass.password}")
    private String password;

    @Autowired
    private HikariBaseConfig hikariBaseConfig;

    @Primary
    @Bean(name = "bluegrassDataSource")
    public DataSource masterDataSource() {
        return hikariBaseConfig.getDataSource(driverClassName, url, username, password);
    }

    @Primary
    @Bean
    public JdbcTemplate jdbcTemplate(@Qualifier("bluegrassDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Primary
    @Bean(name = "bluegrassSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("bluegrassDataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/quartz/**/*.xml"));
// 全局字段创建人/更新人/创建时间/更新时间 字段的填充
//        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new BluegrassMetaHandler());
//        sessionFactoryBean.setGlobalConfig(globalConfig);
        // sessionFactoryBean.setPlugins(new Interceptor[]{pageHelper()});
        Interceptor[] plugins = {paginationInterceptor()};
        sessionFactoryBean.setPlugins(plugins);
        return sessionFactoryBean.getObject();
    }

    @Primary
    @Bean(name = "bluegrassSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("bluegrassSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    /**
     * 事务管理
     *
     * @param dataSource
     * @return
     */
    @Primary
    @Bean(name = "bluegrassTransactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("bluegrassDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 分页插件
     */
    @Primary
    @Bean
    public PageHelper pageHelper() {
        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("offsetAsPageNum", "true");
        properties.setProperty("rowBoundsWithCount", "true");
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        return pageHelper;
    }

    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor().setDialectType("mysql");
    }

}

(3)数据源配置:
application.yml:

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource  #数据源类型
    hikari:
      pool-name: KevinHikariPool  #连接池名称,默认HikariPool-1
      maximum-pool-size: 20   #最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值
      connection-timeout: 60000 #连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒
      minimum-idle: 10  #最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size
      idle-timeout: 500000   # 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放
      max-lifetime: 600000   #连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
      connection-test-query: SELECT 1   #连接测试查询
    bluegrass:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3406/quartz?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
      username: root
      password: ddsoft

2.2.2 Springboot 整合quartz 持久化:

在application.yml: 增加 quartz 持久化参数即可:

spring:
  # quartz 定义
  quartz:
  	 # 持久化类型为jdbc
    job-store-type: jdbc
	# 定义任务的初始化类型
    jdbc:
      initialize-schema: always
#      initialize-schema: never

注意第一次启动项目 initialize-schema 可以设置为 always,进行数据库quartz 对应表的生成,后续启动项目 改值可以调整为 never (不出初始化),该参数可以在 三, 扩展 章节详细了解;

2.3 Springboot 整合quartz 持久化(独立数据源)

(1)在application.yml: 增加 quartz 持久化单独的数据源:

spring:
	quartz:
	     driver-class-name: com.mysql.cj.jdbc.Driver
	     jdbc-url: jdbc:mysql://localhost:3406/quartz-oneself?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
	     username: root
	     password: ddsoft

(2)标识quartz 数据源:

QuartzDataSourceConfig


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class QuartzDataSourceConfig {

    @Value("${spring.datasource.quartz.jdbc-url}")
    private String url;

    @Value("${spring.datasource.quartz.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.quartz.username}")
    private String username;

    @Value("${spring.datasource.quartz.password}")
    private String password;

    @Autowired
    private HikariBaseConfig hikariBaseConfig;

    @Bean
    // 标识quartz 数据源
    @QuartzDataSource
    public DataSource QuartzDataSource() {
        return hikariBaseConfig.getDataSource(driverClassName, url, username, password);
    }
}


三、 扩展:

3.1 initialize-schema 初始化:

初始化的方式,其取值可以是alwaysneverembedded

  • always:表示当Quartz启动时,它始终会尝试自动初始化数据库表结构。如果表已经存在,Quartz将首先删除现有的表,然后创建新的表。这样可以确保数据库表结构始终与Quartz的期望一致。
  • never:表示Quartz在启动时不会尝试自动初始化数据库表结构。这意味着您必须手动创建和维护Quartz所需的表结构。
  • embedded:表示Quartz会自动检查数据库中的表结构。如果表已经存在且符合预期的结构,Quartz将继续使用现有的表。否则,它会尝试自动创建所需的表结构。

如果您使用Spring框架与Quartz集成,可以在Spring的配置文件中使用以下属性来设置org.quartz.jobStore.initialize-schema

spring.quartz.properties.org.quartz.jobStore.initialize-schema=always

通过根据需要设置org.quartz.jobStore.initialize-schema参数,可以控制Quartz在启动时如何处理数据库表结构的初始化。

四、总结:

Springboot 通过引入quartz 对应的start jar 包,随后就可以在业务中定义相应的job 和 trigger 然后使用调度器进行关联后,就可以完成任务的调度。

五、参考:

1 spring quartz 参数配置参考;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

flutter 文件上传组件和大文件分片上传

文件分片上传 资料 https://www.cnblogs.com/caijinglong/p/11558389.html 使用分段上传来上传和复制对象 - Amazon Simple Storage Service 因为公司使用的是亚马逊的s3桶 下面是查阅资料获得的 亚马逊s3桶的文件上传分片 分段上分为三个步骤&#xff1a;开始上传、上传对…

Linux常见的指令

目录 01. ls 指令02. pwd命令03. cd 指令04. touch指令05.mkdir指令&#xff08;重要&#xff09;&#xff1a;06.rmdir指令 && rm 指令&#xff08;重要&#xff09;&#xff1a;07.man指令&#xff08;重要&#xff09;&#xff1a;08.cp指令&#xff08;重要&#x…

人工智能讲师AI讲师大模型讲师叶梓介绍及大语言模型技术原理与实践提纲

叶梓&#xff0c;上海交通大学计算机专业博士毕业&#xff0c;高级工程师。主研方向&#xff1a;数据挖掘、机器学习、人工智能。历任国内知名上市IT企业的AI技术总监、资深技术专家&#xff0c;市级行业大数据平台技术负责人。 长期负责城市信息化智能平台的建设工作&#xff…

JUC并发编程学习与实践

文章目录 学习资料创建和运行线程方法一&#xff1a;直接使用Thread方法二&#xff1a;使用Runnable配合Thread方法三&#xff1a;FutureTask配合Thread 线程的常见方法start与runsleep与yield线程的优先级 join方法详解interrupt线程打断interrupt线程打断后&#xff0c;线程不…

4.7 Verilog 循环语句

关键词&#xff1a;while, for, repeat, forever Verilog 循环语句有 4 种类型&#xff0c;分别是 while&#xff0c;for&#xff0c;repeat&#xff0c;和 forever 循环。循环语句只能在 always 或 initial 块中使用&#xff0c;但可以包含延迟表达式。 while 循环 while 循…

科普|什么是数据脱敏

在当今数字化的时代&#xff0c;数据已经成为企业的重要资产和核心竞争力。然而&#xff0c;随着数据量的不断增加&#xff0c;数据安全和隐私保护问题也日益突出。 什么是数据脱敏呢&#xff1f; 数据脱敏&#xff0c;也称为数据去隐私化或数据匿名化&#xff0c;是一种将敏感…

electron学习和新建窗口

首先我们要先下载electron npm install --save-dev electron 建立入口文件main.js 新建一个入口文件 main.js&#xff0c;然后导入eletron新建一个窗口。 const { app, BrowserWindow, ipcMain } require("electron"); const path require("path");func…

JavaWeb——002JS Vue快速入门

目录 一、JS快速入门​编辑 1、什么是JavaScript?​编辑 2、JS引入方式​编辑 2.1、示例代码 3、JS基础语法 3.1、书写语法 3.2、变量​编辑 3.3、数据类型 3.4、运算符​编辑 3.5、流程控制语句​编辑 4、JS函数 4.1、第一种函数定义方式 function funcName(参数…

C#知识点-15(匿名函数、使用委托进行窗体传值、反射)

匿名函数 概念&#xff1a;没有名字的函数&#xff0c;一般情况下只调用一次。它的本质就是一个方法&#xff0c;虽然我们没有定义这个方法&#xff0c;但是编译器会把匿名函数编译成一个方法 public delegate void Del1();//无参数无返回值的委托public delegate void Del2(s…

Linux 安装RocketMQ

官网&#xff1a; https://rocketmq.apache.org/zh/安装RocketMQ 5.2.0 wget https://dist.apache.org/repos/dist/release/rocketmq/5.2.0/rocketmq-all-5.2.0-bin-release.zip unzip rocketmq-all-5.2.0-bin-release.zip#启动之前修改jvm启动内存 cd bin #修改&#xff1a;…

车辆管理系统设计与实践

车辆管理系统是针对车辆信息、行驶记录、维护保养等进行全面管理的系统。本文将介绍车辆管理系统的设计原则、技术架构以及实践经验&#xff0c;帮助读者了解如何构建一个高效、稳定的车辆管理系统。 1. 系统设计原则 在设计车辆管理系统时&#xff0c;需要遵循以下设计原则&…

顺序表经典算法及其相关思考

27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 思路一 利用顺序表中的SLDestroy函数的思想&#xff0c;遇到等于val值的就挪动 思路二 双指针法&#xff1a;不停的将和val不相等的数字往前放。此时的des更像一个空数组&#xff0c;里面存放的都是和val不相等、能够存…

【Rust敲门砖】 Windows环境下配置及安装环境

一、安装C环境 rust底层是依赖C环境的连接器&#xff0c;所以需要先安装C/C编译环境, 有两种选择:安装微软的msvc或者安装mingw/cygwin。 如果使用msvc的Visual Studio&#xff0c;只需要安装好C/C编译环境,然后一路默认就行了&#xff0c;缺点是体积比较大&#xff0c;下载安…

YOLO v9 思路复现 + 全流程优化

YOLO v9 思路复现 全流程优化 提出背景&#xff1a;深层网络的 信息丢失、梯度流偏差YOLO v9 设计逻辑可编程梯度信息&#xff08;PGI&#xff09;&#xff1a;使用PGI改善训练过程广义高效层聚合网络&#xff08;GELAN&#xff09;&#xff1a;使用GELAN改进架构 对比其他解法…

day16_map课后练习 - 参考答案

文章目录 day16_课后练习第1题第2题第3题第4题第5题第6题 day16_课后练习 第1题 开发提示&#xff1a;可以使用Map&#xff0c;key是字母&#xff0c;value是该字母的次数 效果演示&#xff1a;例如&#xff1a;String str “Your future depends on your dreams, so go to …

KafKa3.x基础

来源&#xff1a;B站 目录 定义消息队列传统消息队列的应用场景消息队列的两种模式 Kafka 基础架构Kafka 命令行操作主题命令行操作生产者命令行操作消费者命令行操作 Kafka 生产者生产者消息发送流程发送原理生产者重要参数列表 异步发送 API普通异步发送带回调函数的异步发送…

【springBoot】springAOP

AOP的概述 AOP是面向切面编程。切面就是指某一类特定的问题&#xff0c;所以AOP也可以理解为面向特定方法编程。AOP是一种思想&#xff0c;拦截器&#xff0c;统一数据返回和统一异常处理是AOP思想的一种实现。简单来说&#xff1a;AOP是一种思想&#xff0c;对某一类事务的集…

(提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战

文章目录 &#xff08;提供数据集下载&#xff09;基于大语言模型LangChain与ChatGLM3-6B本地知识库调优&#xff1a;数据集优化、参数调整、提示词Prompt优化本地知识库目标操作步骤问答测试的预设问题原始数据情况数据集优化&#xff1a;预处理&#xff0c;先后准备了三份数据…

C#使用一个泛型方法操作不同数据类型的数组

目录 一、泛型方法及其存在的意义 二 、实例 1.源码 2.生成效果 再发一个泛型方法的示例。 一、泛型方法及其存在的意义 实际应用中&#xff0c;查找或遍历数组中的值时&#xff0c;有时因为数组类型的不同&#xff0c;需要对不同的数组进行操作&#xff0c;那么,可以使用…

Java学习-21 网络编程

什么是网络编程&#xff1f; 可以让设备中的程序与网络上其他设备中的程序进行数据交互&#xff08;实现网络通信的&#xff09; 基本的通信架构 基本的通信架构有2种形式: CS架构(Client客户端/Server服务端) BS架构(Browser浏览器/Server服务端)。 网络通信三要素 IP …