SpringBatch简单处理多表批量动态更新

         项目需要处理一堆表,这些表数据量不是很大都有经纬度信息,但是这些表的数据没有流域信息,需要按经纬度信息计算所属流域信息。比较简单的项目,按DeepSeek提示思索完成开发,AI真好用。

       阿里AI个人版本IDEA安装

      IDEA中使用DeepSeek满血版的手把手教程来了!

代码实现

1、controller

/**
 * 批量流域处理任务
 */
@Tag(name = "批量流域处理任务")
@ApiSupport(order = 2)
@RequestMapping("/job")
@RestController
public class SysBatchJobController {

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    JobOperator jobOperator;

    @Autowired
    @Qualifier("updateWaterCodeJob")
    private Job updateWaterCodeJob;

    // 多线程分页更新数据
    @GetMapping("/asyncJob")
    public void asyncJob() throws Exception {
        JobParameters jobParameters = new JobParametersBuilder().addLong("time",System.currentTimeMillis()).toJobParameters();
        JobExecution run = jobLauncher.run(updateWaterCodeJob, jobParameters);
        run.getId();
    }

}

2、批量处理表

/**
 * 需要批量处理的业务表信息
 */
@Builder
@AllArgsConstructor
@Data
@TableName(value = "ads_t_sys_batch_update_table")
public class SysBatchUpdateTable extends BaseEntity implements Serializable {

    private static final long serialVersionUID = -7367871287146067724L;

    @TableId(type = IdType.ASSIGN_UUID)
    private String pkId;

    /**
     * 需要更新的表名
     **/
    @TableField(value = "table_name")
    private String tableName;

    /**
     * 所需更新表所在数据库ID
     **/
    @TableField(value = "data_source_id")
    private String dataSourceId;

    /**
     * 表对应的主键字段
     **/
    @TableField(value = "key_id")
    private String keyId;

    /**
     * 表对应的流域字段
     **/
    @TableField(value = "water_code_column")
    private String waterCodeColumn;

    /**
     * 表对应的经度字段
     **/
    @TableField(value = "lon_column")
    private String lonColumn;

    /**
     * 表对应的纬度字段
     **/
    @TableField(value = "lat_column")
    private String latColumn;


    public SysBatchUpdateTable() {
        
    }

}

3、Mapper,传递参数比较麻烦,可以考虑将参数动态整合到sql里面构造

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bigdatacd.panorama.system.domain.po.SysBatchUpdateTable;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
import java.util.Map;

@Mapper
public interface UpdateTableMapper extends BaseMapper<SysBatchUpdateTable> {

    /**
     * 根据表名分页查询数据
     * @param tableName 表名
     * @return
     */
    List<Map<String, Object>> selectUpdateTableByPage(String tableName);

    /**
     * 更新数据
     * @param tableName 表名
     * @param waterCode 流域编码
     * @param pkId  表主键ID
     */
    void updateWaterCode(String tableName,
                         String waterCode,
                         String pkId);
}


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bigdatacd.panorama.system.mapper.UpdateTableMapper">

    <!-- 动态分页查询通过#和$区别动态构造更新所需参数 -->
    <select id="selectUpdateTableByPage" resultType="java.util.HashMap">
        <!--如果有分页查询就直接使用分页查询sql-->
        SELECT
        ${keyId} as pkId,
        #{keyId} as keyId,
        ${waterCodeColumn} as waterCode,
        #{waterCodeColumn} as waterCodeColumn,
        ${lonColumn} as lon,
        ${latColumn} as lat,
        #{tableName} as tableName
        FROM ${tableName}  a  where ${waterCodeColumn} is null
        ORDER BY ${keyId} <!-- 确保分页顺序 -->
        LIMIT #{_pagesize} OFFSET #{_skiprows}
    </select>

    <!-- 动态更新 -->
    <update id="updateWaterCode">
        UPDATE ${tableName}
        SET ${waterCodeColumn} = #{waterCode}
        WHERE ${keyId} = #{pkId} <!-- 假设主键为id -->
    </update>
</mapper>

4、配置文件

Spring
 batch:
    job:
      enabled: false   #启动时不启动job
    jdbc:
      initialize-schema: always  
  sql:
    init:
      schema-locations: classpath:/org/springframework/batch/core/schema-mysql.sql    

数据源url加个批处理参数rewriteBatchedStatements=true
 url: jdbc:mysql://localhost:3306/xxxx?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&&serverTimezone=GMT%2b8&useSSL=false&rewriteBatchedStatements=true

5、主配置类调整(按表分区)

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.batch.MyBatisPagingItemReader;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.step.skip.AlwaysSkipItemSkipPolicy;
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.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.HashMap;
import java.util.Map;

// 1. 主配置类调整(按表分区)
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 主任务
     *
     * @return
     */
    @Bean("updateWaterCodeJob")
    public Job updateWaterCodeJob(
            @Qualifier("masterStep") Step masterStep
    ) {
        return jobBuilderFactory.get("updateWaterCodeJob")
                .start(masterStep)
                .build();
    }

    @Bean("masterStep")
    public Step masterStep(
            @Qualifier("updateBatchTableData") Step updateBatchTableData,
            @Qualifier("multiTablePartitioner") MultiTablePartitioner multiTablePartitioner
    ) {
        return stepBuilderFactory.get("masterStep")
                .partitioner(updateBatchTableData.getName(), multiTablePartitioner) // 分区器按表名分区一个表一个分区
                .step(updateBatchTableData)
                .gridSize(10) // 按表分区了 并发数一般设置为核心数
                .taskExecutor(taskExecutor())
                .listener(new BatchJobListener())
                .build();
    }

    // 线程池配置(核心线程数=表数量)
    @Bean("batchTaskExecutor")
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setThreadNamePrefix("table-processor-");
        return executor;
    }

    /**
     * 处理分页数据更新步骤
     * @return
     */
    @Bean("updateBatchTableData")
    public Step updateBatchTableData(
            @Qualifier("dynamicTableReader") MyBatisPagingItemReader<Map<String, Object>> myBatisPagingItemReader,
            @Qualifier("batchUpdateWriter") BatchUpdateWriter batchUpdateWriter,
            @Qualifier("tableProcessor") TableProcessor tableProcessor

    ) {
        return stepBuilderFactory.get("updateBatchTableData")
                .<Map<String, Object>, Map<String, Object>>chunk(100)
                .reader(myBatisPagingItemReader)
                .processor(tableProcessor)
                .writer(batchUpdateWriter)
                .faultTolerant()
                .skipPolicy(new AlwaysSkipItemSkipPolicy())
                .build();
    }


    /**
     * 分页获取需要更新的表数据
     * @return
     */
    @Bean
    @StepScope
    public MyBatisPagingItemReader<Map<String, Object>> dynamicTableReader(
            @Value("#{stepExecutionContext['keyId']}") String keyId, //需要更新的表ID字段
            @Value("#{stepExecutionContext['waterCodeColumn']}") String waterCodeColumn,// 需要更新的流域字段
            @Value("#{stepExecutionContext['lonColumn']}") String lonColumn,// 经度纬度字段
            @Value("#{stepExecutionContext['latColumn']}") String latColumn,// 经度纬度字段
            @Value("#{stepExecutionContext['tableName']}") String tableName // 需要更新的表名
            ) {

        MyBatisPagingItemReader<Map<String, Object>> reader = new MyBatisPagingItemReader<>();
        reader.setSqlSessionFactory(sqlSessionFactory);
        reader.setQueryId("com.bigdatacd.panorama.system.mapper.UpdateTableMapper.selectUpdateTableByPage");
        Map<String,Object> param = new HashMap<>();
        param.put("keyId",keyId);
        param.put("waterCodeColumn",waterCodeColumn);
        param.put("lonColumn",lonColumn);
        param.put("latColumn",latColumn);
        param.put("tableName",tableName);
        reader.setParameterValues(param);
        reader.setPageSize(2000);
        return reader;
    }

}


import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

// 批量更新Writer
@Component("batchUpdateWriter")
@StepScope
public class BatchUpdateWriter implements ItemWriter<Map<String, Object>> {

    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;

    @Override
    public void write(List<? extends Map<String, Object>> items) {
        // 构造动态sql更新数据
        StringBuilder sb = new StringBuilder();
        sb.append("UPDATE ");
        sb.append((String) items.get(0).get("tableName"));
        sb.append(" SET ");
        sb.append((String) items.get(0).get("waterCodeColumn"));
        sb.append(" = :waterCode");
        sb.append(" WHERE ");
        sb.append((String) items.get(0).get("keyId"));
        sb.append(" = :pkId");

        jdbcTemplate.batchUpdate(sb.toString(), items.stream()
                .map(item -> new MapSqlParameterSource()
                        .addValue("waterCode", item.get("waterCode"))
                        .addValue("tableName", item.get("tableName"))
                        .addValue("waterCodeColumn", item.get("waterCodeColumn"))
                        .addValue("keyId", item.get("keyId"))
                        .addValue("pkId", item.get("pkId"))
                )
                .toArray(SqlParameterSource[]::new));
    }
}

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class MultiTablePartitioner implements Partitioner {

    private final DataSource dataSource;

    public MultiTablePartitioner(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    @Override
    public Map<String, ExecutionContext> partition(int gridSize) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "SELECT key_id as keyId,water_code_column as waterCodeColumn,lon_column as lonColumn,lat_column as latColumn,page_sql as pageSql,table_name as tableName FROM ads_t_sys_batch_update_table where deleted = 0 and data_status = '0'";
        List<Map<String,Object>> tables = jdbcTemplate.queryForList(sql);
        log.info("查询" + sql);
        Map<String, ExecutionContext> partitions = new HashMap<>();
        for (int i = 0; i < tables.size(); i++) {
            ExecutionContext ctx = new ExecutionContext();
            // 将需要传递的参数放到上下文中,用于动态批量更新的sql用
            ctx.putString("keyId", String.valueOf(tables.get(i).get("keyId")));
            ctx.putString("waterCodeColumn", String.valueOf(tables.get(i).get("waterCodeColumn")));
            ctx.putString("lonColumn", String.valueOf(tables.get(i).get("lonColumn")));
            ctx.putString("latColumn", String.valueOf(tables.get(i).get("latColumn")));
            //ctx.putString("pageSql", String.valueOf(tables.get(i).get("pageSql")));
            ctx.putString("tableName", String.valueOf(tables.get(i).get("tableName")));
            partitions.put("partition" + i, ctx);
        }
        return partitions;
    }
}


import com.bigdatacd.panorama.common.utils.GeoJsonUtil;
import lombok.Builder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;

import java.util.Map;

// 处理数据的经纬度所在流域
@Component("tableProcessor")
@Builder
public class TableProcessor implements ItemProcessor<Map<String, Object>, Map<String, Object>> {

    @Override
    public Map<String, Object> process(Map<String, Object> item) {
        // 处理数据经纬度查找对应的流域
        item.put("waterCode", GeoJsonUtil.getWaterCode(Double.parseDouble(item.get("lon").toString()), Double.parseDouble(item.get("lat").toString())));
        return item;
    }
}


import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;

/**
 * Job 监听
 */
public class BatchJobListener implements JobExecutionListener {

    private long beingTime;
    private long endTime;

    @Override
    public void beforeJob(JobExecution jobExecution) {
        beingTime = System.currentTimeMillis();
        System.out.println(jobExecution.getJobInstance().getJobName() + "  beforeJob...... " + beingTime);
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        endTime = System.currentTimeMillis();
        System.out.println(jobExecution.getJobInstance().getJobName() + "  afterJob...... " + endTime);
        System.out.println(jobExecution.getJobInstance().getJobName()  + "一共耗耗时:【" + (endTime - beingTime) + "】毫秒");
    }

}


 6、通过经纬度计算流域工具类

import lombok.extern.slf4j.Slf4j;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.*;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;


/**
 * @Description: GeoJSON工具类
 * @author: Mr.xulong
 * @date: 2023年01月09日 14:39
 */
@Slf4j
public class GeoJsonUtil {

    /*public static void main(String[] args) {
        try {
            FeatureCollection featureCollection = getFeatureCollection("sichuanliuyu.json");
            double x = 106.955085;
            double y = 32.09546061139062;
            System.out.println(JSON.toJSONString(properties(x,y,featureCollection)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }*/
    private static String geoJsonFilePath = "sichuanliuyu.json";

    private GeoJsonUtil() {
    }
    /**
     * 获取区域数据集合
     *
     * @return
     */
    public static FeatureCollection getFeatureCollection() {
        // 读取 GeoJson 文件
        InputStream resourceAsStream = GeoJsonUtil.class.getResourceAsStream("/json/" + geoJsonFilePath);
        FeatureJSON featureJSON = new FeatureJSON();
        try {
            return featureJSON.readFeatureCollection(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断指定区域集合是否包含某个点
     * @param longitude
     * @param latitude
     * @param featureCollection
     * @return
     */
    public static boolean contains(double longitude, double latitude, FeatureCollection featureCollection) {
        FeatureIterator features = featureCollection.features();
        try {
            while (features.hasNext()) {
                Feature next = features.next();
                if (isContains(longitude, latitude, next)) {
                    return true;
                }
            }
        } finally {
            features.close();
        }
        return false;
    }

    /**
     * 判断指定区域集合是否包含某个点,如果包含,则返回所需属性
     * @param longitude
     * @param latitude
     * @param featureCollection
     * @return
     */
    public static Map<String, Object> properties(double longitude, double latitude, FeatureCollection featureCollection) {
        FeatureIterator features = featureCollection.features();
        try {
            while (features.hasNext()) {
                Feature next = features.next();
                boolean contains = isContains(longitude, latitude, next);
                // 如果点在面内则返回所需属性
                if (contains) {
                    HashMap<String, Object> properties = new HashMap<>();
                    properties.put("waterCode", next.getProperty("FID").getValue());
                    properties.put("waterName", next.getProperty("name").getValue());
                    return properties;
                }
            }
        } finally {
            features.close();
        }
        return null;
    }

    /**
     * 判断指定区域集合是否包含某个点,如果包含,则返回所需属性
     * @param longitude
     * @param latitude
     * @return
     */
    public static Map<String, Object> properties(double longitude, double latitude) {
        FeatureCollection featureCollection = getFeatureCollection();
        FeatureIterator features = featureCollection.features();
        try {
            while (features.hasNext()) {
                Feature next = features.next();
                boolean contains = isContains(longitude, latitude, next);
                // 如果点在面内则返回所需属性
                if (contains) {
                    HashMap<String, Object> properties = new HashMap<>();
                    properties.put("waterCode", next.getProperty("FID").getValue());
                    properties.put("waterName", next.getProperty("name").getValue());
                    return properties;
                }
            }
        } finally {
            features.close();
        }
        return null;
    }

    /**
     * 判断指定区域集合是否包含某个点,如果包含,则返回所需属性
     * @param longitude
     * @param latitude
     * @return
     */
    public static String getWaterCode(double longitude, double latitude) {
        FeatureCollection featureCollection = getFeatureCollection();
        FeatureIterator features = featureCollection.features();
        try {
            while (features.hasNext()) {
                Feature next = features.next();
                boolean contains = isContains(longitude, latitude, next);
                // 如果点在面内则返回所需属性
                if (contains) {
                    return String.valueOf(next.getProperty("FID").getValue());
                }
            }
        } finally {
            features.close();
        }
        return null;
    }

    private static boolean isContains(double longitude, double latitude, Feature feature) {
        // 获取边界数据
        Property geometry = feature.getProperty("geometry");
        Object value = geometry.getValue();
        // 创建坐标的point
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
        Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
        boolean contains = false;
        // 判断是单面还是多面
        if (value instanceof MultiPolygon) {
            MultiPolygon multiPolygon = (MultiPolygon) value;
            contains = multiPolygon.contains(point);
        } else if (value instanceof Polygon) {
            Polygon polygon = (Polygon) value;
            contains = polygon.contains(point);
        }
        return contains;
    }
}

7、地图依赖

<geotools.version>27-SNAPSHOT</geotools.version>
<!--地图-->
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>${geotools.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.geotools</groupId>
                    <artifactId>gt-main</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-main</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-geojson</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-swing</artifactId>
            <version>${geotools.version}</version>
        </dependency>


<repositories>
    <repository>
        <id>osgeo</id>
        <name>OSGeo Release Repository</name>
        <url>https://repo.osgeo.org/repository/release/</url>
        <snapshots><enabled>false</enabled></snapshots>
        <releases><enabled>true</enabled></releases>
    </repository>
    <repository>
        <id>osgeo-snapshot</id>
        <name>OSGeo Snapshot Repository</name>
        <url>https://repo.osgeo.org/repository/snapshot/</url>
        <snapshots><enabled>true</enabled></snapshots>
        <releases><enabled>false</enabled></releases>
    </repository>
    </repositories>

参考git项目 springbatch: 这是一个SpringBoot开发的SpringBatch批处理示例,示例主要是将文件30W条数据使用多线程导入到t_cust_temp表,然后又将t_cust_temp表数据使用分片导入到t_cust_info表。下载即可用。

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

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

相关文章

在Linux桌面上创建Idea启动快捷方式

1、在桌面新建idea.desktop vim idea.desktop [Desktop Entry] EncodingUTF-8 NameIntelliJ IDEA CommentIntelliJ IDEA Exec/home/software/idea-2021/bin/idea.sh Icon/home/software/idea-2021/bin/idea.svg Terminalfalse TypeApplication CategoriesApplication;Developm…

将DeepSeek接入vscode的N种方法

接入deepseek方法一:cline 步骤1:安装 Visual Studio Code 后,左侧导航栏上点击扩展。 步骤2:搜索 cline,找到插件后点击安装。 步骤3:在大模型下拉菜单中找到deep seek,然后下面的输入框输入你在deepseek申请的api key,就可以用了 让deepseek给我写了一首关于天气的…

单片机总结【GPIO/TIM/IIC/SPI/UART】

一、GPIO 1、概念 通用输入输出口&#xff1b;开发者可以根据自己的需求将其配置为输入或输出模式&#xff0c;以实现与外部设备进行数据交互、控制外部设备等功能。简单来说&#xff0c;GPIO 就像是计算机或微控制器与外部世界沟通的 “桥梁”。 2、工作模式 工作模式性质特…

Vxe UI 根据vxe-tabs 绑定不同的值,渲染生成不同的 tabls(页签)内容

VxeUI tabs控件&#xff0c;根据绑定不同的内容&#xff0c;动态渲染不同的表格数据放置在不同的 tab 页 效果图如下&#xff1a; 代码实现 <template><vxe-tabs :options"detailTabList"><vxe-tab-pane v-for"(item, index) in detailTabList&…

洛谷 P8705:[蓝桥杯 2020 省 B1] 填空题之“试题 E :矩阵” ← 卡特兰数

【题目来源】 https://www.luogu.com.cn/problem/P8705 【题目描述】 把 1∼2020 放在 21010 的矩阵里。要求同一行中右边的比左边大&#xff0c;同一列中下边的比上边的大。一共有多少种方案? 答案很大&#xff0c;你只需要给出方案数除以 2020 的余数即可。 【答案提交】 …

今日运维之-Mac笔记本python环境问题

1. 问题&#xff1a;MAC升级系统后git报错&#xff1f; Error: Cant create update lock in /usr/local/var/homebrew/locks! Fix permissions by running:sudo chown -R $(whoami) /usr/local/var/homebrew Traceback (most recent call last):11: from /usr/local/Homebrew/…

鸿蒙Next如何自定义标签页

前言 项目需求是展示标签&#xff0c;标签的个数不定&#xff0c;一行展示不行就自行换行。但是&#xff0c;使用鸿蒙原生的 Grid 后发现特别的难看。然后就想着自定义控件。找了官方文档&#xff0c;发现2个重要的实现方法&#xff0c;但是&#xff0c;官方的demo中讲的很少&…

Python - Python连接数据库

Python的标准数据库接口为&#xff1a;Python DB-API&#xff0c;Python DB-API为开发人员提供了数据库应用编程接口。 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个实现库&#xff0c;Python2中则使用mysqldb。 PyMySQL 遵循 Python 数据库 API v2.0 规范&…

(python)Arrow库使时间处理变得更简单

前言 Arrow库并不是简单的二次开发,而是在datetime的基础上进行了扩展和增强。它通过提供更简洁的API、强大的时区支持、丰富的格式化和解析功能以及人性化的显示,填补了datetime在某些功能上的空白。如果你需要更高效、更人性化的日期时间处理方式,Arrow库是一个不错的选择…

MySQL的锁机制和锁算法

锁机制和InnoDB锁算法 MyISAM和InnoDB存储引擎使用的锁&#xff1a; MyISAM采用表级锁(table-level locking)。 InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁 表级锁和行级锁对比&#xff1a; 表级锁&#xff1a; MySQL中锁定 粒度最大 的一种锁&#xff0c;…

PyTorch 源码学习:GPU 内存管理之深入分析 CUDACachingAllocator

因引入 expandable_segments 机制&#xff0c;PyTorch 2.1.0 版本发生了较大变化。本文关注的是 PyTorch 原生的 GPU 内存管理机制&#xff0c;故研究的 PyTorch 版本为 2.0.0。代码地址&#xff1a; c10/cuda/CUDACachingAllocator.hc10/cuda/CUDACachingAllocator.cpp 更多内…

Rk3568驱动开发_驱动编写和挂载_2

1.字符驱动介绍&#xff1a; 字符驱动&#xff1a;按照字节流镜像读写操作的设备&#xff0c;读写数据分先后顺序&#xff0c;例如&#xff1a;点灯、按键、IIC、SPI、等等都是字符设备&#xff0c;这些设备的驱动叫字符驱动设备 Linux应用层如何调用驱动&#xff1a; 字符设…

记录一下在k3s快速创建gitlab

废话不多说&#xff0c;直接上配置文件 需要修改的地方&#xff08;备注都有写&#xff09;&#xff1a; 1.命名空间 namespace 2. claimName 文件挂载 Deployment kind: Deployment apiVersion: apps/v1 metadata:name: gitlabnamespace: cicd # 替换为您的命名空间la…

leetcode 1656. 设计有序流 简单

有 n 个 (id, value) 对&#xff0c;其中 id 是 1 到 n 之间的一个整数&#xff0c;value 是一个字符串。不存在 id 相同的两个 (id, value) 对。 设计一个流&#xff0c;以 任意 顺序获取 n 个 (id, value) 对&#xff0c;并在多次调用时 按 id 递增的顺序 返回一些值。 实现…

应对现代生活的健康养生指南

在科技飞速发展的现代社会&#xff0c;人们的生活方式发生了巨大改变&#xff0c;随之而来的是一系列健康问题。快节奏的生活、高强度的工作以及电子产品的过度使用&#xff0c;让我们的身体承受着前所未有的压力。因此&#xff0c;掌握正确的健康养生方法迫在眉睫。 针对久坐不…

大连本地知识库的搭建--数据收集与预处理_01

1.马蜂窝爬虫 编程语言&#xff1a;Python爬虫框架&#xff1a;Selenium&#xff08;用于浏览器自动化&#xff09;解析库&#xff1a;BeautifulSoup&#xff08;用于解析HTML&#xff09; 2.爬虫策略 目标网站&#xff1a;马蜂窝&#xff08;https://www.mafengwo.cn/&…

SQL笔记#复杂查询

一、视图 1、视图和表 使用试图时会执行SELECT语句并创建一张临时表。视图中保存的是SELECT语句;表中保存的是实际数据。 2、创建视图的方法 CREATE VIEW 视图名称(<视图列名1>,<视图列名2>,……) AS <SELECT语句> CREATE VIEW ProductSum (prod…

文件系统

目录 1.认识磁盘 磁盘的物理结构 CHS定位法 磁盘的逻辑结构 2.认识文件系统 inode 分区和分组 磁盘上的文件系统 3.软硬链接 软链接 软链接的操作 创建软链接 查看软链接 删除软链接 软链接的特点 软链接的使用场景 硬链接 硬链接的操作 创建硬链接 查看硬…

学习路之PHP --TP6异步执行功能 (无需安装任何框架)

学习路之PHP --异步执行功能 &#xff08;无需安装任何框架&#xff09; 简介一、工具类二、调用三、异步任务的操作四、效果&#xff1a; 简介 执行异步任务是一种很常见的需求&#xff0c;如批量发邮箱&#xff0c;短信等等执行耗时任务时&#xff0c;需要程序异步执行&…

一键部署DeepSeek

腾讯Cloud Studio提供DeepSeek一键部署功能&#xff0c;0行代码&#xff0c;秒级部署使用&#xff01; 重点是每月免费提供10000分钟&#xff01; 不用等待模型下载&#xff0c;创建即可使用。 内置 Ollama、DeepSeek-R1 1.5B、7B、8B、14B 及 32B 模型。 热门模板 AI模板 前…