”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 开始使用 SPRING BATCH 进行编程

开始使用 SPRING BATCH 进行编程

发布于2024-11-02
浏览:568

Introduction

Dans vos projets personnels ou professionnels, Il vous arrive de faire des traitements sur de gros volumes de données. Le traitement par lots de données est un moyen efficace de traiter de gros volumes de données où celles-ci sont collectées, traitées, puis les résultats par lots sont produits. Le traitement par lots peut être appliqué dans de nombreux cas d'utilisation. Un cas d'utilisation courant du traitement par lots consiste à transformer un grand ensemble de fichiers CSV ou JSON en un format structuré prêt pour un traitement ultérieur.

Dans ce tutoriel, nous allons essayer de voir comment mettre cette architecture en place avec Spring Boot qui est un framework qui facilite le développement d'applications fondées sur Spring.

Qu'est-ce que Spring-Batch?

Spring Batch est un framework open source pour le traitement par lots. Il s'agit d'une solution légère et complète conçue pour permettre le développement d'applications par lots robustes, que l'on trouve souvent dans les systèmes d'entreprise modernes. Son développement est issu d'une collaboration entre SpringSource et Accenture.

Il permet de pallier à des problème récurrents lors de développement de batchs:

  • productivité
  • gestion de gros volumes de données
  • fiabilité
  • réinvention de la roue.

N.B: En informatique, un batch est un programme fonctionnant en StandAlone, réalisant un ensemble de traitements sur un volume de données.

Architecture de base de Spring Batch

Commencer la programmation avec SPRING BATCH

Pour gérer les données d'un batch, on utilise principalement les trois outils suivants:

JobLauncher : il s'agit du composant chargé de lancer/démarrer le programme de traitement par lot (batch). Il peut être configuré pour s'auto déclencher ou pour être déclenché par un évènement extérieur (lancement manuel). Dans le workflow Spring Batch, le JobLauncher est chargé d'exécuter un Job (tâche).

Job : il s'agit du composant qui représente la tâche à qui on délègue la responsabilité du besoin métier traité dans le programme. Il est chargé de lancer de façon séquentielle une ou plusieurs Step.

Step : c'est le composant qui enveloppe le cœur même du besoin métier à traiter. Il est chargé de définir trois sous-composants structurés comme suit :

ItemReader : c'est le composant chargé de lire les données d'entrées à traiter. Elles peuvent provenir de diverses sources (bases de données, fichiers plats (csv, xml, xls, etc.), queue) ;

ItemProcessor : c'est le composant responsable de la transformation des données lues. C'est en son sein que toutes les règles de gestion sont implémentées .

ItemWriter : ce composant sauvegarde les données transformées par le processor dans un ou plusieurs conteneurs désirés (bases de données, fichiers plats (csv, xml, xls, etc.), cloud).

JobRepository : c'est le composant chargé d'enregistrer les statistiques issues du monitoring sur le JobLauncher, le Job et la (ou les) Step à chaque exécution. Il offre deux techniques possibles pour stocker ces statistiques : le passage par une base de données ou le passage par une Map. Lorsque le stockage des statistiques est fait dans une base de données, et donc persisté de façon durable, cela permet le suivi continuel du Batch dans le temps à l'effet d'analyser les éventuels problèmes en cas d'échec. A contrario lorsque c'est dans une Map, les statistiques persistées seront perdues à la terminaison de chaque instance d'exécution du Batch. Dans tous les cas, il faut configurer l'un ou l'autre obligatoirement.

Pour plus d'informations, je vous conseille de consulter le site de Spring.

Après cette explication bref de l'architecture de spring batch,essayons dès à présent de montrer comment mettre en place un job spring batch qui va lire des données à partir d'un fichier CSV que nous allons par la suite insérer dans une base de données."Let's get into coding".

Commencer la programmation avec SPRING BATCH

Configuration du projet

Le moyen le plus simple de générer un projet Spring Boot consiste à utiliser l'outil de démarrage Spring avec les étapes ci-dessous:

  • Se rendre sur le site Spring Initializr
  • Sélectionner Maven Project et langage Java
  • Ajouter Spring Batch, JPA, Lombok, H2 Database
  • Entrer le nom du groupe comme "com.example" et l'artefact comme "SpringBatch"
  • Cliquez le bouton generate

Commencer la programmation avec SPRING BATCH

Une fois le projet généré, il faut le dézipper  ensuite l'importer dans votre IDE.

Technologies utilisées:

  • JDK 1.8
  • Maven
  • IntelliJ
  • Lombok
  • Spring data JPA
  • H2 Database

Dépendances du projet

Toutes les dépendances du projet sont dans le fichier pom.xml. Les trois lettres POM sont l'acronyme de Project Object Model. Sa représentation XML est traduite par Maven en une structure de données qui représente le modèle du projet.



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.3.RELEASE
         
    
    com.pathus
    SpringBatchExample
    0.0.1-SNAPSHOT
    SpringBatchExample
    Demo of spring batch project 

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-batch
        
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        

        
            com.h2database
            h2
            runtime
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
        
            org.springframework.batch
            spring-batch-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


Structure du Projet

La structure du projet se présente comme suit:

Commencer la programmation avec SPRING BATCH

Configuration du Job

Pour activer le traitement par lots, nous devons annoter la classe de configuration avec @EnableBatchProcessing. Nous devons par la suite créer un reader pour lire notre fichier CSV, créer un processor pour traiter les données d'entrée avant d'écrire, créer un writer pour écrire dans la base de données.

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.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import com.pathus90.springbatchexample.batch.StudentProcessor;
import com.pathus90.springbatchexample.batch.StudentWriter;
import com.pathus90.springbatchexample.model.Student;
import com.pathus90.springbatchexample.model.StudentFieldSetMapper;

@Configuration
@EnableBatchProcessing
@EnableScheduling
public class BatchConfig {

    private static final String FILE_NAME = "results.csv";
    private static final String JOB_NAME = "listStudentsJob";
    private static final String STEP_NAME = "processingStep";
    private static final String READER_NAME = "studentItemReader";

    @Value("${header.names}")
    private String names;

    @Value("${line.delimiter}")
    private String delimiter;

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Step studentStep() {
        return stepBuilderFactory.get(STEP_NAME)
                .chunk(5)
                .reader(studentItemReader())
                .processor(studentItemProcessor())
                .writer(studentItemWriter())
                .build();
    }

    @Bean
    public Job listStudentsJob(Step step1) {
        return jobBuilderFactory.get(JOB_NAME)
                .start(step1)
                .build();
    }

    @Bean
    public ItemReader studentItemReader() {
        FlatFileItemReader reader = new FlatFileItemReader();
        reader.setResource(new ClassPathResource(FILE_NAME));
        reader.setName(READER_NAME);
        reader.setLinesToSkip(1);
        reader.setLineMapper(lineMapper());
        return reader;

    }

    @Bean
    public LineMapper lineMapper() {

        final DefaultLineMapper defaultLineMapper = new DefaultLineMapper();
        final DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
        lineTokenizer.setDelimiter(delimiter);
        lineTokenizer.setStrict(false);
        lineTokenizer.setNames(names.split(delimiter));

        final StudentFieldSetMapper fieldSetMapper = new StudentFieldSetMapper();
        defaultLineMapper.setLineTokenizer(lineTokenizer);
        defaultLineMapper.setFieldSetMapper(fieldSetMapper);

        return defaultLineMapper;
    }

    @Bean
    public ItemProcessor studentItemProcessor() {
        return new StudentProcessor();
    }

    @Bean
    public ItemWriter studentItemWriter() {
        return new StudentWriter();
    }
}

Configuration du job et de la Step

La première méthode définit le job et la seconde définit une seule step. Les jobs sont créés à partir des steps, où chaque step peut impliquer un reader, un processor et un writer. Dans la définition de la step, on définit la quantité de données à écrire à la fois et dans notre cas, il écrit jusqu'à 5 enregistrements à la fois. Ensuite, on  configure le reader, le processor  et le writer à l'aide des beans injectés précédemment. Quand  la définition de notre job, il pourra définir différentes step au sein de notre exécution à travers un ordre précis. la step studentStep sera exécutée par le job  listStudentsJob.

@Bean
    public Step studentStep() {
        return stepBuilderFactory.get(STEP_NAME)
                .chunk(5)
                .reader(studentItemReader())
                .processor(studentItemProcessor())
                .writer(studentItemWriter())
                .build();
    }

    @Bean
    public Job listStudentsJob(Step step1) {
        return jobBuilderFactory.get(JOB_NAME)
                .start(step1)
                .build();
    }

Définition du Reader

Dans la configuration de notre batch, le Reader lit une source de données et est appelé successivement au sein d'une étape et retourne des objets pour lequel il est défini (Student dans notre cas).

 @Bean
    public ItemReader studentItemReader() {
        FlatFileItemReader reader = new FlatFileItemReader();
        reader.setResource(new ClassPathResource(FILE_NAME));
        reader.setName(READER_NAME);
        reader.setLinesToSkip(1);
        reader.setLineMapper(lineMapper());
        return reader;
    }

La classe FlatFileItemReader utilise la classe DefaultLineMapper qui utilise à son tour la classe DelimitedLineTokenizer. Le rôle de DelimitedLineTokenizer est de décomposer chaque ligne dans un objet FieldSet  et la propriété names donne le format de l'entête du fichier et permet d'identifier les données de chaque ligne. Cette propriété names est utilisée par la classe d'implantation de transformation de données en objet métier  à travers l'objet FieldSet. Il s'agit de la classe indiquée par la propriété fieldSetMapper ( StudentFieldSetMapper).

import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;

public class StudentFieldSetMapper implements FieldSetMapper {
    @Override
    public Student mapFieldSet(FieldSet fieldSet) {
        return Student.builder()
                .rank(fieldSet.readString(0))
                .firstName(fieldSet.readString(1))
                .lastName(fieldSet.readString(2))
                .center(fieldSet.readString(3))
                .pv(fieldSet.readString(4))
                .origin(fieldSet.readString(5))
                .mention(fieldSet.readString(6))
                .build();
    }
}

L'interface LineMapper quand à elle est utilisée pour mapper des lignes (chaînes) vers des objets généralement utilisée pour mapper des lignes lues à partir d'un fichier

  @Bean
    public LineMapper lineMapper() {

        final DefaultLineMapper defaultLineMapper = new DefaultLineMapper();
        final DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
        lineTokenizer.setDelimiter(delimiter);
        lineTokenizer.setStrict(false);
        lineTokenizer.setNames(names.split(delimiter));

        final StudentFieldSetMapper fieldSetMapper = new StudentFieldSetMapper();
        defaultLineMapper.setLineTokenizer(lineTokenizer);
        defaultLineMapper.setFieldSetMapper(fieldSetMapper);

        return defaultLineMapper;
    }

Definition du Processor

Contrairement à un Reader, les implémentations d'un Processor sont plutôt pour des besoins fonctionnels. Il n'est pas obligatoire et on peut s'en passer si aucun besoin fonctionnel n'est prévu dans notre traitement Dans notre exemple, on a écrit un simple processor qui ne fait que convertir quelques attributs de notre objet student en majuscules et on peut aller au delà de cet exemple avec des cas fonctionnels plus concrets.

import org.springframework.batch.item.ItemProcessor;

import com.pathus90.springbatchexample.model.Student;

public class StudentProcessor implements ItemProcessor {

    @Override
    public Student process(Student student) {
        student.setFirstName(student.getFirstName().toUpperCase());
        student.setLastName(student.getLastName().toUpperCase());
        student.setCenter(student.getCenter().toUpperCase());
        student.setOrigin(student.getOrigin().toUpperCase());
        student.setMention(student.getMention().toUpperCase());
        return student;
    }
}

Definition du Writer

Le Writer écrit les données provenant du processor (ou directement lues par le Reader). Dans notre cas, Il reçoit du processor les objets transformés et chaque objet sera par la suite persisté dans notre base de donnés et transaction sera validée.

import java.util.List;

import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;

import com.pathus90.springbatchexample.model.Student;
import com.pathus90.springbatchexample.service.IStudentService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class StudentWriter implements ItemWriter {

    @Autowired
    private IStudentService studentService;

    @Override
    public void write(List extends Student> students) {
        students.stream().forEach(student -> {
            log.info("Enregistrement en base de l'objet {}", student);
            studentService.insertStudent(student);
        });
    }
}

Fichier de configuration du batch (application.properties)

# Enabling H2 Console
spring.h2.console.enabled=true

# To See H2 Console in Browser:
spring.h2.console.path=/h2-console
spring.h2.console.settings.web-allow-others=true

# ===============================
# DB
# ===============================

spring.datasource.url=jdbc:h2:file:~/test1
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# ===============================
# JPA / HIBERNATE
# ===============================

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.datasource.continue-on-error=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

header.names= Rang,Prenoms,Noms,Centre,PV,Origine,Mention
line.delimiter=,

logging.level.org.springframework.web=ERROR
logging.level.com.pathus90=DEBUG

Fichier CSV à écrire en base de données

Rang,Prenoms,Noms,Centre,PV,Origine,Mention
1,Mamadou Sanou ,diallo,TOMBO 2,1686,MES FLEURS,BIEN
2,SAFIATOU,DIALLO,A.S. TOURE,191,JACQUELINE,BIEN
3,BoubA ,Camara, vh,1686,koumba diawara ,BIEN
4,SAFIATOU,CondE,kk3,1951,kipe,BIEN

Lancement de l'application

Une fois que que avions fini de mettre en place la configuration du batch, regardons dès à present voir si tout ce qui a été dit plus haut fonctionne 

Pour exécuter l'application, il faut chercher le fichier qui contient l'annotation @SpringBootApplication qui est le main de notre application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class SpringBatchExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBatchExampleApplication.class, args);
    }
}

Le lancement du main ci-dessus va démarrer notre job et le batch launcher se présente comme suit :

package com.pathus90.springbatchexample;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BatchLauncher {

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private Job job;

    public BatchStatus run() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
        JobParameters parameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()).toJobParameters();
        JobExecution jobExecution = jobLauncher.run(job, parameters);
        return jobExecution.getStatus();
    }
}

Un scheduler (planificateur) a été mis en place pour permettre au batch de s'auto déclencher. Dans cet exemple, le batch une fois lancé s'exécuter toutes les 8 secondes. Vous pouvez jouer avec en changeant la valeur fixedDelayen millisecondes.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class Scheduler {

    @Autowired
    private BatchLauncher batchLauncher;

    @Scheduled(fixedDelay = 8000)
    public void perform() throws Exception {
        log.info("Batch programmé pour tourner toutes les 8 secondes");
        batchLauncher.run();
    }
}

En plus  d'exécuter le fichier main ci-dessus pour démarrer le batch, on peut également lancé la commande mvn spring-boot:run  tout en utilisant une invite de commande.

On peut aussi lancer l'application avec le fichier d'archive JAR et dans ce cas il faut :

  1. Se mettre dans le dossier parent du projet en utilisant une invite de commande et exécuter la commande mvn clean package qui va packager notre projet.

  2. Dans le dossier target, un fichier jar sera crée.

  3. Pour exécuter l'application, utiliser la commande java -jar target/nom_du_fichier_généré-0.0.1-SNAPSHOT.jar

S'assurer aussi que la console H2console a déjà démarré lors du lancement notre application spring batch et la base de données est automatiquement générée ainsi que la creation de la table Student.

Commencer la programmation avec SPRING BATCH

On observe bien que notre fichier a été bien intégré dans notre base de données.

N.B:Si on souhaite aussi démarrer le batch manuellement sans passer un schedulerqui va se déclencher en fonction de notre paramétrage , j'ai e xposé une API à l'aide du contrôleur pour appeler le Job Spring Batch.

package com.pathus90.springbatchexample.controller;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.pathus90.springbatchexample.BatchLauncher;

import lombok.extern.slf4j.Slf4j;

@RestController
@RequestMapping("/load")
@Slf4j
public class StudentController {

    @Autowired
    private BatchLauncher batchLauncher;

    @GetMapping
    public BatchStatus load() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
        log.info("Batch demarré à la demande");
        return batchLauncher.run();
    }
}

il suffit juste de lancer L'URL : http://localhost:8080/load et le batch se lancera 

Commencer la programmation avec SPRING BATCH

On arrive en fin de notre premier apprentissage sur la programmation des batchs grâce au framework Spring. Laissez des commentaires ou des questions si vous en aviez !

Bonne apprentissage à tous et j'espère que ce premier tutoriel vous sera bénéfique.

Vous trouverez le code source disponible ici

Références

  1. https://spring.io/guides/gs/batch-processing/
  2. https://jeremy-jeanne.developpez.com/tutoriels/spring/spring-batch/#LIII-B-3
  3. https://www.baeldung.com/introduction-to-spring-batch
版本声明 本文转载于:https://dev.to/pathus90/commencer-la-programmation-avec-spring-batch-5ec7?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    [2这里: https://webthemez.com/demo/sticky-multi-header-scroll/index.html </main> <section> { display:grid; grid-template-...
    编程 发布于2025-05-10
  • 如何正确使用与PDO参数的查询一样?
    如何正确使用与PDO参数的查询一样?
    在pdo 中使用类似QUERIES在PDO中的Queries时,您可能会遇到类似疑问中描述的问题:此查询也可能不会返回结果,即使$ var1和$ var2包含有效的搜索词。错误在于不正确包含%符号。通过将变量包含在$ params数组中的%符号中,您确保将%字符正确替换到查询中。没有此修改,PDO...
    编程 发布于2025-05-10
  • 为什么尽管有效代码,为什么在PHP中捕获输入?
    为什么尽管有效代码,为什么在PHP中捕获输入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,输出...
    编程 发布于2025-05-10
  • 如何在php中使用卷发发送原始帖子请求?
    如何在php中使用卷发发送原始帖子请求?
    如何使用php 创建请求来发送原始帖子请求,开始使用curl_init()开始初始化curl session。然后,配置以下选项: curlopt_url:请求 [要发送的原始数据指定内容类型,为原始的帖子请求指定身体的内容类型很重要。在这种情况下,它是文本/平原。要执行此操作,请使用包含以下标头...
    编程 发布于2025-05-10
  • 表单刷新后如何防止重复提交?
    表单刷新后如何防止重复提交?
    在Web开发中预防重复提交 在表格提交后刷新页面时,遇到重复提交的问题是常见的。要解决这个问题,请考虑以下方法: 想象一下具有这样的代码段,看起来像这样的代码段:)){ //数据库操作... 回声“操作完成”; 死(); } ?> ...
    编程 发布于2025-05-10
  • 在Java中如何为PNG文件添加坐标轴和标签?
    在Java中如何为PNG文件添加坐标轴和标签?
    如何用java 在现有png映像中添加轴和标签的axes和labels如何注释png文件可能具有挑战性。与其尝试可能导致错误和不一致的修改,不如建议在图表创建过程中集成注释。使用JFReechArt import java.awt.color; 导入java.awt.eventqueue; 导入...
    编程 发布于2025-05-10
  • 如何解决由于Android的内容安全策略而拒绝加载脚本... \”错误?
    如何解决由于Android的内容安全策略而拒绝加载脚本... \”错误?
    Unveiling the Mystery: Content Security Policy Directive ErrorsEncountering the enigmatic error "Refused to load the script..." when deployi...
    编程 发布于2025-05-10
  • 为什么不使用CSS`content'属性显示图像?
    为什么不使用CSS`content'属性显示图像?
    在Firefox extemers属性为某些图像很大,&& && && &&华倍华倍[华氏华倍华氏度]很少见,却是某些浏览属性很少,尤其是特定于Firefox的某些浏览器未能在使用内容属性引用时未能显示图像的情况。这可以在提供的CSS类中看到:。googlepic { 内容:url(&#...
    编程 发布于2025-05-10
  • 如何使用组在MySQL中旋转数据?
    如何使用组在MySQL中旋转数据?
    在关系数据库中使用mySQL组使用mySQL组进行查询结果,在关系数据库中使用MySQL组,转移数据的数据是指重新排列的行和列的重排以增强数据可视化。在这里,我们面对一个共同的挑战:使用组的组将数据从基于行的基于列的转换为基于列。 Let's consider the following ...
    编程 发布于2025-05-10
  • 如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    postgresql:为每个唯一标识符在postgresql中提取最后一行,您可能需要遇到与数据集合中每个不同标识的信息相关的信息。考虑以下数据:[ 1 2014-02-01 kjkj 在数据集中的每个唯一ID中检索最后一行的信息,您可以在操作员上使用Postgres的有效效率: id dat...
    编程 发布于2025-05-10
  • 如何使用PHP从XML文件中有效地检索属性值?
    如何使用PHP从XML文件中有效地检索属性值?
    从php $xml = simplexml_load_file($file); foreach ($xml->Var[0]->attributes() as $attributeName => $attributeValue) { echo $attributeName,...
    编程 发布于2025-05-10
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-05-10
  • C++中如何将独占指针作为函数或构造函数参数传递?
    C++中如何将独占指针作为函数或构造函数参数传递?
    在构造函数和函数中将唯一的指数管理为参数 unique pointers( unique_ptr [2启示。通过值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法将唯一指针的所有权转移到函数/对象。指针的内容被移至功能中,在操作...
    编程 发布于2025-05-10
  • 如何克服PHP的功能重新定义限制?
    如何克服PHP的功能重新定义限制?
    克服PHP的函数重新定义限制在PHP中,多次定义一个相同名称的函数是一个no-no。尝试这样做,如提供的代码段所示,将导致可怕的“不能重新列出”错误。 但是,PHP工具腰带中有一个隐藏的宝石:runkit扩展。它使您能够灵活地重新定义函数。 runkit_function_renction_re...
    编程 发布于2025-05-10
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法表示的字符串时,您可能会遇到错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && ...
    编程 发布于2025-05-10

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3