Spring Batch 入门之 CSV-to-DB

本文介绍如何使用Spring Batch从CSV文件读取记录,通过自定义处理器转换数据,并使用StaxEventItemWriter输出为XML,同时展示如何将数据写入MySQL数据库。

学习使用Spring batch从CSV文件读取记录,并使用 StaxEventItemWriter 输出经过处理的记录转换为 XML 的数据。

spring-batch-reference-model.png

  1. JobLauncher: 顾名思义,该领域对象就是Job的启动器,其作用就是绑定一组JobParameters到Job上,然后运行该Job。

  2. Job: 定义,配置批处理任务的领域对象,该对象的作用,第一是做Step的容器,配置该批处理任务需要的Step,以及他们之间的逻辑关系。第二是配置该批处理任务的特征,比方说名字,是否可重启,是否对JobParameters进行验证以及验证规则等。

  3. Step: 定义批处理任务中一个对立的逻辑任务处理单元。基本上的业务逻辑处理代码都是封装在Step中的。Step有2种实现形式,一种是Tasklet形式的,这种形式非常自由,开发人员只需要实现Tasklet接口,其中的逻辑完全有自己决定,另一种是Chunk-Oriented形式的,这种形式定义了一个Step的流程必须是“读-处理(可选)-写”,当然Spring Batch也对每一个步骤提供了接口ItemReader, ItemProcessor,ItemWriter还有很多常用的默认实现(读文件,读数据库,写文件,写数据库等等)。 每一个Step只能由一个Tasklet或者一个Chunk构成。

  4. JobRepository: 该领域对象会为Spring Batch的运维数据提供一种持久化机制。其为所有的运维数据的提供CRUD的操作接口,并为所有的操作提供事务支持。

项目概述

在这个应用程序中,我们将执行以下任务:

  1. 使用 FlatFileItemReader 从CSV文件读取交易记录
  2. 使用 CustomItemProcessor 进行项目的业务处理。当 ItemReader 读取一个项目,而 ItemWriter 写入它们时,
    ItemProcessor 提供一个转换或应用其他业务处理的访问点。
  3. 使用 StaxEventItemWriter 获取 CustomItemProcessor 的处理结果,并将它转换成 XML 类型数据作为最终输出。
  4. 使用 MyBatisBatchItemWriter 获取 CustomItemProcessor 的处理结果,并将它转换成 XML 类型数据作为最终输出。
  5. 查看MySQL

工程结构

在这里插入图片描述

Maven 依赖

sqlite-jdbcmysql-connector-java 可以选择其中一个。
当选择其中一种时,同时也要在 applicationContext.xml 文件中做出相应的改动。

改动:

  • 依赖的版本由 platform-bom 来统一管理
  • 添加 mybatis, mybatis-spring
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.littlefxc.example</groupId>
    <artifactId>Spring-CSV-to-DB</artifactId>
    <version>1.0-snapshot</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>5.0.9.RELEASE</spring.version>
        <spring.batch.version>4.0.1.RELEASE</spring.batch.version>
        <sqlite.version>3.8.11.2</sqlite.version>
        <mysql.version>5.1.47</mysql.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.spring.platform</groupId>
                <artifactId>platform-bom</artifactId>
                <version>Cairo-RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- MySQL database driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- spring的XML文件处理依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

</project>

applicationContext.xml

我们将使用 FlatFileItemReader 读取 CSV 文件。
我们将使用它的标准配置,包括 DefaultLineMapperDelimitedLineTokenizerBeanWrapperFieldSetMapper 类。
为了在XML文件中输出记录,我们将使用 StaxEventItemWriter 作为标准编写器。

改动:

  • 将输出XML变为输出到mysql
  • Spring Batch 持久层框架由 spring-jdbc 改为 mybatis, mybatis-spring

当然,原来的输出 itemWriter 去掉注释后,仍然起作用

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:batch="http://www.springframework.org/schema/batch"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
       http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:property-placeholder location="classpath:application.properties"/>
    <context:component-scan base-package="com.littlefxc.examples.batch"/>

    <!-- 1. 数据库脚本:这里是为了方便起见保证每次重启程序数据库都是最新的(生产环境中不要这么做!!!) -->
    <jdbc:initialize-database>
        <jdbc:script location="${batch.schema-drop}"/>
        <jdbc:script location="${batch.schema-create}"/>
        <jdbc:script location="${project.schema-drop}"/>
        <jdbc:script location="${project.schema-create}"/>
    </jdbc:initialize-database>

    <!-- 2. 连接数据库:可以选择其它的数据源实现 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
          p:driverClassName="${jdbc.driver-class-name}"
          p:url="${jdbc.url}"
          p:username="${jdbc.username}"
          p:password="${jdbc.password}"/>

    <!-- 3. 事务管理 -->
    <!--<bean id="transactionManager" class="org.springframework.batch.support.transactionRecord.ResourcelessTransactionManager"/>-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource"/>

    <!-- 3.1 申明式事务 -->
    <tx:annotation-driven/>

    <!-- 3.2 mybatis 配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
          p:dataSource-ref="dataSource"
          p:typeAliasesPackage="${mybatis.type-aliases-package}"
          p:configLocation="${mybatis.configuration}"/>

    <!-- 3.3 mybatis dao 配置 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
          p:basePackage="com.littlefxc.examples.batch.dao"
          p:sqlSessionFactoryBeanName="sqlSessionFactory"/>

    <!-- 4. 为JobLauncher,Job和Step实现提供CRUD操作 -->
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
          p:dataSource-ref="dataSource"
          p:transactionManager-ref="transactionManager"
          p:databaseType="mysql"/>

    <!-- 5. JobLauncher表示一个简单的接口,用于使用给定的 JobParameter 启动作业 -->
    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"
          p:jobRepository-ref="jobRepository"/>

    <!-- 6. batch 输入 -->
    <bean id="itemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
        <!-- 输入资源 -->
        <property name="resource" value="input/record.csv"/>
        <!-- 不读取第一行数据 -->
        <property name="linesToSkip" value="1"/>
        <!-- 将输入资源转化为对象 -->
        <property name="lineMapper">
            <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <property name="lineTokenizer">
                    <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                        <property name="names" value="username,user_id,transaction_date,transaction_amount"/>
                    </bean>
                </property>
                <property name="fieldSetMapper" ref="recordFieldSetMapper"/>
            </bean>
        </property>
    </bean>

    <!-- 7. batch的处理器 -->
    <bean id="itemProcessor" class="com.littlefxc.examples.batch.service.CustomItemProcessor"/>

    <!-- 8. batch 输出:输出为xml -->
    <!--<bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
        <property name="resource" value="file:xml/output.xml"/>
        <property name="marshaller">
            &lt;!&ndash; xml 与 对象的转换器 &ndash;&gt;
            <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
                  p:packagesToScan="com.littlefxc.examples.batch.model"/>
        </property>
        <property name="rootTagName" value="transactionRecord"/>
    </bean>-->
    <!-- 8. batch 输出:输出到mysql -->
    <!--<bean id="itemWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter"
          p:dataSource-ref="dataSource" p:sql="${batch.sql}">
        <property name="itemSqlParameterSourceProvider">
            <bean class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider"/>
        </property>
    </bean>-->
    <!-- 8. batch 输出:使用 mybatis 输出到mysql -->
    <bean id="itemWriter" class="org.mybatis.spring.batch.MyBatisBatchItemWriter">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!-- 与 mybatis 关联的 dao 层的接口名:com.littlefxc.examples.batch.dao.TransactionRecordDao.insertTransactionRecord -->
        <property name="statementId" value="insertTransactionRecord"/>
    </bean>

    <!-- 9. 配置batch的输入(6)、处理器(7)、输出(8) -->
    <!-- commit-interval:提交事务之前将处理的项目数。 -->
    <batch:job id="firstBatchJob">
        <batch:step id="step1">
            <batch:tasklet>
                <batch:chunk reader="itemReader" processor="itemProcessor" writer="itemWriter" commit-interval="2"/>
            </batch:tasklet>
        </batch:step>
    </batch:job>

</beans>

RecordFieldSetMapper

ItemReader 的属性,作用是将 FieldSet 转换为对象

package com.littlefxc.examples.batch.service;

import com.littlefxc.examples.batch.model.TransactionRecord;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;

import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * 将 FieldSet 转换为对象
 * @author fengxuechao
 * @date 2019/1/4
 **/
public class RecordFieldSetMapper implements FieldSetMapper<Transaction> {

    public Transaction mapFieldSet(FieldSet fieldSet) throws BindException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        Transaction transactionRecord = new Transaction();

        transactionRecord.setUsername(fieldSet.readString("username"));
        transactionRecord.setUserId(fieldSet.readInt("user_id"));
        transactionRecord.setAmount(fieldSet.readDouble("transaction_amount"));
        String dateString = fieldSet.readString("transaction_date");
        try {
            transactionRecord.setTransactionDate(dateFormat.parse(dateString));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return transactionRecord;
    }
}

CustomItemProcessor

自定义实现接口 ItemProcessor, 作为 ItemReaderItemWriter 的转换点。

package com.littlefxc.examples.batch.service;

import com.littlefxc.examples.batch.model.TransactionRecord;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;

import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * 将读取到的数据集合转换为对象
 * @author fengxuechao
 * @date 2019/1/4
 **/
public class RecordFieldSetMapper implements FieldSetMapper<Transaction> {

    public Transaction mapFieldSet(FieldSet fieldSet) throws BindException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        Transaction transactionRecord = new Transaction();

        transactionRecord.setUsername(fieldSet.readString("username"));
        transactionRecord.setUserId(fieldSet.readInt("user_id"));
        transactionRecord.setAmount(fieldSet.readDouble("transaction_amount"));
        String dateString = fieldSet.readString("transaction_date");
        try {
            transactionRecord.setTransactionDate(dateFormat.parse(dateString));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return transactionRecord;
    }
}

模型

package com.littlefxc.examples.batch.model;

import lombok.Data;

import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;

/**
 * @author fengxuechao
 */
@Data
@XmlRootElement(name = "transactionRecord")
public class Transaction {

    private String username;

    private int userId;

    private Date transactionDate;

    private double amount;
}

record.csv

devendra, 1234, 31/10/2015, 10000
john    , 2134, 3/12/2015 , 12321
robin   , 2134, 2/02/2015 , 23411

启动程序

package com.littlefxc.examples.batch;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
        context.setConfigLocations("classpath:spring-context.xml");
        context.refresh();

        JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
        Job job = (Job) context.getBean("firstBatchJob");
        System.out.println("Starting the batch job");
        try {
            JobExecution execution = jobLauncher.run(job, new JobParameters());
            System.out.println("Job Status : " + execution.getStatus());
            System.out.println("Job completed");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Job failed");
        }
    }
}

验证

<?xml version="1.0" encoding="UTF-8"?>
<transactionRecord>
    <transactionRecord>
        <amount>10000.0</amount>
        <transactionDate>2015-10-31T00:00:00+08:00</transactionDate>
        <userId>1234</userId>
        <username>devendra</username>
    </transactionRecord>
    <transactionRecord>
        <amount>12321.0</amount>
        <transactionDate>2015-12-03T00:00:00+08:00</transactionDate>
        <userId>2134</userId>
        <username>john</username>
    </transactionRecord>
    <transactionRecord>
        <amount>23411.0</amount>
        <transactionDate>2015-02-02T00:00:00+08:00</transactionDate>
        <userId>2134</userId>
        <username>robin</username>
    </transactionRecord>
</transactionRecord>

附录:

application.properties

batch.schema-drop=org/springframework/batch/core/schema-drop-mysql.sql
batch.schema-create=org/springframework/batch/core/schema-mysql.sql
batch.sql=INSERT INTO transaction_record (user_id, username, transaction_date, amount) VALUES (:userId, :username, :transactionDate, :amount)

jdbc.url=jdbc:mysql://192.168.120.63:3306/batch?useSSL=false
jdbc.username=root
jdbc.password=123456
jdbc.driver-class-name=com.mysql.jdbc.Driver

# 自定义数据库删除脚本
project.schema-drop=classpath:schema-drop.sql
# 自定义数据库创建脚本
project.schema-create=classpath:schema.sql

# Mybatis Config
mybatis.configuration=classpath:mybatis-config.xml
mybatis.type-aliases-package=com.littlefxc.examples.batch.model
mybatis.mapper.base-package=com.littlefxc.examples.batch.dao

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="multipleResultSetsEnabled" value="true"/>
        <setting name="useColumnLabel" value="true"/>
        <setting name="useGeneratedKeys" value="false"/>
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <setting name="defaultStatementTimeout" value="25"/>
        <setting name="defaultFetchSize" value="100"/>
        <setting name="safeRowBoundsEnabled" value="false"/>
        <setting name="mapUnderscoreToCamelCase" value="false"/>
        <setting name="localCacheScope" value="SESSION"/>
        <setting name="jdbcTypeForNull" value="OTHER"/>
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    </settings>
</configuration>

schema.sql

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50722
 Source Host           : localhost:3306
 Source Schema         : batch

 Target Server Type    : MySQL
 Target Server Version : 50722
 File Encoding         : 65001

 Date: 31/01/2019 10:27:20
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for transaction_record
-- ----------------------------
# DROP TABLE IF EXISTS `transaction_record`;
CREATE TABLE `transaction_record`  (
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `transaction_date` datetime(6) NOT NULL,
  `amount` double(11, 0) NOT NULL,
  PRIMARY KEY (`username`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

schema-drop.sql

DROP TABLE IF EXISTS `transaction_record`;
内容概要:本文围绕“单相逆变器闭环逆变电路PWM模型仿真研究”展开,基于Simulink平台构建单相逆变器的闭环控制系统仿真模型,重点研究PWM调制技术在逆变电路中的应用与实现。文中详细阐述了系统架构设计、电压电流双闭环控制策略的实现原理、控制器参数设计及仿真建模全过程,并通过仿真结果验证了控制方案在动态响应、稳态精度与系统稳定性方面的有效性。同时,文档还涵盖多种电力电子系统典型应用场景,如多类型短路故障仿真(中性点不接地、经小电阻接地、经消弧线圈接地等)、软开关技术、微电网能量管理、MPPT控制等,体现出较强的技术综合性和工程实践价值。; 适合人群:电气工程、自动化、电力电子与新能源等相关专业的高校本科生、研究生、科研人员,以及从事电力系统仿真、逆变器设计与新能源并网技术研发的工程技术人员。; 使用场景及目标:①掌握基于Simulink的单相逆变器闭环控制系统建模与PWM仿真方法;②深入理解双闭环控制、SPWM/SVPWM调制、系统稳定性分析等核心技术原理;③为课程设计、毕业设计、科研项目或实际工程开发提供可复用的仿真模型与技术支持; 阅读建议:建议结合文中仿真模型动手实践,重点掌握PI控制器参数整定、PWM信号生成机制与仿真结果分析方法,同时可延伸学习文档中涉及的软开关、故障仿真、微电网控制等关联技术,以拓展系统级设计能力。
重要提示】本资源设置为0积分下载,若非0积分请勿轻易下载 亲爱的CSDN用户: 首先感谢你点进这个资源页面。我需要提前说明一个重要情况: 本资源原本已设置为“0积分下载”,即作者希望完全免费共享。但CSDN平台有时会根据文件的下载热度、文件大小、用户权限等因素,自动将部分资源的积分调整为非0数值(如1积分、2积分、5积分等)。这是平台系统的自动行为,而非作者本人的设定。 因此,如果你当前看到该资源的下载所需积分不是0(例如显示为1、2、3……),请谨慎决定是否下载。 如果你按照非0积分支付并下载后发现资源内容不符合预期、链接失效,或者实际上该资源本应是免费的,作者无法为此承担积分损失或退还操作。强烈建议:仅在页面显示为0积分时进行下载。 另外,本资源描述中并未直接提供具体的下载地址或外部链接,因为它本身是一个通过CSDN官方上传通道提交的文件/内容包。如果你看到描述中没有外部网盘地址,这是正常的——资源文件应通过CSDN内置的“下载”按钮获取。若因平台积分显示异常导致你支付了积分,请优先联系CSDN客服咨询积分退还政策,作者没有权限修改平台自动设定的积分值。 感谢你的理解与支持。技术分享本应开放,但受限于平台规则,特此提醒如上。祝学习进步!
重要提示】本资源设置为0积分下载,若非0积分请勿轻易下载 亲爱的CSDN用户: 首先感谢你点进这个资源页面。我需要提前说明一个重要情况: 本资源原本已设置为“0积分下载”,即作者希望完全免费共享。但CSDN平台有时会根据文件的下载热度、文件大小、用户权限等因素,自动将部分资源的积分调整为非0数值(如1积分、2积分、5积分等)。这是平台系统的自动行为,而非作者本人的设定。 因此,如果你当前看到该资源的下载所需积分不是0(例如显示为1、2、3……),请谨慎决定是否下载。 如果你按照非0积分支付并下载后发现资源内容不符合预期、链接失效,或者实际上该资源本应是免费的,作者无法为此承担积分损失或退还操作。强烈建议:仅在页面显示为0积分时进行下载。 另外,本资源描述中并未直接提供具体的下载地址或外部链接,因为它本身是一个通过CSDN官方上传通道提交的文件/内容包。如果你看到描述中没有外部网盘地址,这是正常的——资源文件应通过CSDN内置的“下载”按钮获取。若因平台积分显示异常导致你支付了积分,请优先联系CSDN客服咨询积分退还政策,作者没有权限修改平台自动设定的积分值。 感谢你的理解与支持。技术分享本应开放,但受限于平台规则,特此提醒如上。祝学习进步!
内容概要:本文系统阐述了CUDA并行计算的核心优化技巧,围绕提升SM利用率、最大化内存带宽、隐藏访存延迟和减少指令开销四大目标,从GPU硬件架构、线程模型、内存访问、指令执行、内核设计及工程实践六个维度展开。重点讲解了线程块配置、Warp分支发散规避、全局内存合并访问、共享内存Bank冲突避免、寄存器与常量内存使用、异步传输与多流并行、快速数学函数、原子操作优化、内核拆分与融合、Tensor Core利用等关键技术,并提供了编译优化参数和Nsight系列性能分析工具的使用指导,形成了一套完整的CUDA性能优化方法论。; 适合人群:具备CUDA编程基础,从事高性能计算、深度学习、科学计算或GPU加速开发的工程师与研究人员,尤其适合工作2年以上的开发者提升底层优化能力。; 使用场景及目标:①解决CUDA程序中SM利用率低、内存带宽不足、访存延迟高等性能瓶颈;②掌握从基础到高阶的系统性优化策略,实现程序性能的指数级提升;③结合Nsight工具进行性能剖析与迭代优化。; 阅读建议:学习时应结合实际代码调试与性能分析工具(如Nsight Compute和Nsight Systems)进行验证,优先实施线程块配置、合并访问、-O3编译等低成本高回报的基础优化,再逐步深入共享内存优化、内核融合、Tensor Core利用等高阶技术,同时推荐优先使用cuBLAS、cuDNN等NVIDIA官方优化库以逼近硬件极限性能。
内容概要:本文提供了一份完整的“大学生创新创业训练计划项目”申报材料模板包,围绕“基于深度学习的智能垃圾分类回收箱设计与实现”项目,详细展示了从项目申报书、答辩PPT、中期检查表到结题报告的全套规范文档。内容涵盖项目背景、目标、研究内容、技术路线、创新点、进度安排、预期成果、经费预算及风险应对等关键环节,并以实际案例呈现各阶段成果,如YOLOv8轻量级模型识别准确率达96%、单台成本控制在780元、校园试点回收520kg可回收物、获得软著与论文成果等,形成可复制推广的校园绿色解决方案。; 适合人群:参与大学生创新创业训练计划(大创项目)的本科生团队,尤其是工科类、计算机相关专业、有意向开展人工智能+环保类实践项目的1-3年级学生;同时也适用于指导教师和项目评审人员作为参考模板。; 使用场景及目标:①帮助学生团队系统规划并撰写高质量的大创项目申报书与结题报告;②指导项目全过程管理,包括技术实施、进度控制、经费使用与成果凝练;③支撑项目答辩展示,提升项目规范性与竞争力,冲击“互联网+”“挑战杯”等赛事奖项; 阅读建议:此资源不仅提供文本模板,更体现了项目从立项到结题的完整逻辑链条,使用者应结合自身课题,参照其结构化表达方式、量化目标设定和技术落地路径进行模仿与创新,注重理论与实践结合,强化数据支撑与成果可视化。
内容概要:本文提供了一个基于Simulink的光伏储能单相逆变器并网仿真模型,系统实现了并网逆变电路的PWM调制控制、闭环控制策略及并网运行特性的仿真分析,涵盖系统建模、控制算法设计、稳定性验证与动态性能评估等关键环节。该模型不仅支持对单相逆变器在并网过程中的电流谐波、功率因数、电能质量及系统稳定性的深入研究,还可拓展应用于多类型电力系统仿真场景,如MPPT控制、软开关技术、微电网能量管理、短路故障分析(包括单相、两相接地及相间短路)、直流电机双闭环控制、Buck/Boost类变换器控制等,展现出广泛的科研适配性与工程实践价值。; 适合人群:面向具备电力电子、自动控制理论或电气工程背景,熟练掌握Simulink/Matlab仿真工具,从事新能源发电系统、微电网控制、逆变器拓扑与控制策略研究的硕士/博士研究生、科研人员及电力系统相关领域的工程技术人员。; 使用场景及目标:①开展光伏发电系统并网控制策略的设计与仿真验证;②学习并掌握单相逆变器PWM调制、锁相环(PLL)、电压电流双闭环控制等核心技术的建模方法;③作为课程设计、毕业设计或科研项目的仿真平台,支撑控制系统开发与优化;④结合文中提供的多种电力系统案例(如故障仿真、储能控制、微网调度),进行横向对比与综合能力提升; 阅读建议:建议读者结合文中列出的多个仿真案例进行扩展学习,重点关注控制器参数设计与系统动态响应之间的关系,动手复现模型并进行仿真调试,通过改变负载、电网条件或控制参数,深入理解并网逆变器的工作机理与控制规律,从而提升实际科研与工程应用能力。
重要提示】本资源设置为0积分下载,若非0积分请勿轻易下载 亲爱的CSDN用户: 首先感谢你点进这个资源页面。我需要提前说明一个重要情况: 本资源原本已设置为“0积分下载”,即作者希望完全免费共享。但CSDN平台有时会根据文件的下载热度、文件大小、用户权限等因素,自动将部分资源的积分调整为非0数值(如1积分、2积分、5积分等)。这是平台系统的自动行为,而非作者本人的设定。 因此,如果你当前看到该资源的下载所需积分不是0(例如显示为1、2、3……),请谨慎决定是否下载。 如果你按照非0积分支付并下载后发现资源内容不符合预期、链接失效,或者实际上该资源本应是免费的,作者无法为此承担积分损失或退还操作。强烈建议:仅在页面显示为0积分时进行下载。 另外,本资源描述中并未直接提供具体的下载地址或外部链接,因为它本身是一个通过CSDN官方上传通道提交的文件/内容包。如果你看到描述中没有外部网盘地址,这是正常的——资源文件应通过CSDN内置的“下载”按钮获取。若因平台积分显示异常导致你支付了积分,请优先联系CSDN客服咨询积分退还政策,作者没有权限修改平台自动设定的积分值。 感谢你的理解与支持。技术分享本应开放,但受限于平台规则,特此提醒如上。祝学习进步!
因为工作需要,每天需要打很多次卡,然后忙起来就忘了,忙完了就会想,刚才打卡了吗?弄错就会漏打卡了,漏打卡会有处罚。就想到写一个程序来解决这个痛点。就有了本次发布的这个程序。 PHP项目,修改起来也简单,也方便二开。本来就是H5页面布局,部署好,直接手机浏览器打开,或者使用封装工具,封装成apk。本人已打包为微信小程序,使用起来很方便。 项目简介 本项目是一个多用户打卡记录系统,基于 PHP + MySQL 开发,提供简洁的用户打卡功能和记录管理。 核心功能 功能模块 描述 用户认证 支持用户注册、登录、密码修改、密码重置 打卡功能 用户可进行每日打卡,记录打卡时间 记录查询 支持按日期查询打卡记录 用户管理 支持头像上传、个人信息查看 数据统计 提供打卡统计功能 技术特点 轻量级架构:纯 PHP 开发,无需框架依赖,部署简单 响应式设计:移动端友好的 UI 界面,支持触摸操作 安全性: 使用 prepare + bind_param 防止 SQL 注入 密码采用哈希加密存储 Session 会话管理用户状态 模块化设计:API 接口与前端分离,便于扩展 项目结构 Plain Text ├── api/ # RESTful API 接口 │ ├── checkin.php # 打卡接口 │ ├── login.php # 登录接口 │ ├── register.php # 注册接口 │ ├── records.php # 记录查询接口 │ ├── stats.php # 统计接口 │ └── … ├── config/ # 配置文件 │ ├── database.php # 数据库配置 │ └── auth.php # 认证配置 ├── sql/ # 数据库脚本 │ └── init.sql # 初始化脚本 ├── avatars/ # 头像存储目录 ├── ind
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值