Recrutement d'automne Meituan 2023 - Réussi

Le traitement par lots traite plusieurs SQL sous un seul SQL. Comment améliorer la vitesse ? Si le partitionnement est requis, comment le partitionner ?

1. Utilisez la fonction de traitement par lots de la base de données pour exécuter plusieurs instructions SQL. Cela réduit la surcharge de communication de chaque instruction SQL. addBatch()Les méthodes et dans JDBC executeBatch()peuvent être utilisées pour effectuer des opérations par lots.

Configurez pour désactiver la soumission automatique des transactions au début du programme, ajoutez toutes les instructions SQL à PrepareStatement et annulez la transaction de base de données si une erreur est signalée lors de l'exécution du programme.

    public static void main (String[] arguments) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String nom d'utilisateur = "votre_nom d'utilisateur" ;
        Chaîne mot de passe = "votre_mot de passe" ;

        essayez (Connexion connexion = DriverManager.getConnection(jdbcUrl, nom d'utilisateur, mot de passe)) {
            //Désactivez la validation automatique et activez les transactions
            connexion.setAutoCommit(false);

            String sql = "INSÉRER DANS votre_table (colonne1, colonne2) VALEURS (?, ?)" ;
            essayez (PreparedStatement PrepareStatement = connexion.prepareStatement(sql)) {
                //Ajouter plusieurs instructions SQL au lot
                pour (int je = 0; je < 1000; i++) {
                    PrepareStatement.setInt(1, i);
                    PrepareStatement.setString(2, "Valeur" + i);
                    PrepareStatement.addBatch();
                }

                //Exécuter le traitement par lots
                int[] updateCounts = préparéStatement.executeBatch();

                // Soumettre la transaction
                connexion.commit();
            } catch (SQLException e) {
                //Annulation de la transaction
                connexion.rollback();
                e.printStackTrace();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

2. Utilisez le multithreading pour créer un pool de threads avec cinq threads, soumettez toutes les instructions SQL une par une et exécutez les instructions SQL dans la méthode run du thread.

importer java.io.BufferedReader ;
importer java.io.FileReader ;
importer java.io.IOException ;
importer java.sql.Connection ;
importer java.sql.DriverManager ;
importer java.sql.SQLException ;
importer java.sql.Statement ;
importer java.util.concurrent.ExecutorService ;
importer java.util.concurrent.Executors ;

classe publique MultiThreadSQLExecution {
    public static void main (String[] arguments) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String nom d'utilisateur = "votre_nom d'utilisateur" ;
        Chaîne mot de passe = "votre_mot de passe" ;
        String sqlFilePath = "path_to_your_sql_file.sql";

        int numThreads = 5; //Spécifiez le nombre de threads

        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);

        essayer {
            Connexion connexion = DriverManager.getConnection(jdbcUrl, nom d'utilisateur, mot de passe);
            Lecteur BufferedReader = nouveau BufferedReader (nouveau FileReader (sqlFilePath));
            Ligne de ficelle ;
            
            while ((line = reader.readLine()) != null) {
                // Soumet chaque instruction SQL au pool de threads
                executorService.submit (nouveau SQLExecutionTask (connexion, ligne));
            }

            // Attend que tous les threads se terminent
            executorService.shutdown();
            tandis que (!executorService.isTerminate()) {
                Thread.sleep(100);
            }

            lecteur.close();
            connexion.close();
        } catch (SQLException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    la classe statique SQLExecutionTask implémente Runnable {
        connexion de connexion privée ;
        chaîne privée sql ;

        SQLExecutionTask (Connexion, String sql) {
            this.connection = connexion ;
            ceci.sql = sql;
        }

        @Passer outre
        public void run() {
            try (Instruction de déclaration = connexion.createStatement()) {
                instruction.execute(sql);
                System.out.println("SQL exécuté : " + sql);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

Code d'erreur réseau 500, 403

1xx - Code d'état informatif (informatif)

  • 100 Continuer : Le client doit poursuivre sa demande.
  • 101 Protocoles de commutation : le serveur demande au client de changer de protocole.

2xx - Code d'état réussi (Réussi)

  • 200 OK : la demande a réussi.
  • 201 Créé : La demande a créé une nouvelle ressource.
  • 204 Aucun contenu : la demande a été traitée avec succès, mais aucun corps de réponse n'a été renvoyé.

3xx - Code d'état de redirection (Redirection)

  • 301 Déplacé de façon permanente : la ressource demandée a été définitivement déplacée vers un nouvel emplacement.
  • 302 Trouvé : la ressource demandée a été temporairement déplacée vers un nouvel emplacement.
  • 304 Non modifié : la ressource n'a pas été modifiée et peut être mise en cache.

4xx – Erreurs client

  • 400 Bad Request : la demande est incorrecte et le serveur ne comprend pas ou ne peut pas traiter la demande.
  • 401 Non autorisé : une authentification est requise pour accéder à la ressource.
  • 403 Interdit : L'accès à la ressource est refusé.
  • 404 Not Found : la ressource demandée n’a pas été trouvée.

5xx - Erreurs de serveur

  • 500 Erreur interne du serveur : le serveur a rencontré une erreur inattendue.
  • 502 Bad Gateway : le serveur, agissant en tant que passerelle ou proxy, a reçu une réponse non valide du serveur en amont.
  • 503 Service indisponible : le serveur est actuellement incapable de traiter la demande, généralement temporairement.
  • 504 Gateway Timeout : Le serveur, agissant en tant que passerelle ou proxy, n'a pas reçu de réponse du serveur en amont à temps.

Algorithme : renvoie la nième valeur à partir de la dernière de la liste chaînée

En utilisant la méthode du double pointeur, le pointeur rapide se déplace de n pas devant le pointeur lent, puis les pointeurs rapide et lent démarrent en même temps. Enfin, lorsque le pointeur rapide atteint la fin, le pointeur lent est la réponse.

classe publique ListNode {
    int val;
    ListNode suivant ;

    ListNode(int val) {
        this.val = val;
    }
}

public int findNthFromEnd (tête ListNode, int n) {
    ListNode lent = tête ;
    ListNode rapide = tête ;

    // Déplace le pointeur rapide vers l'avant de n nœuds
    pour (int je = 0; je < n; i++) {
        si (rapide == nul) {
            return -1 ; // Gère la situation où n est supérieur à la longueur de la liste chaînée
        }
        rapide = rapide.suivant ;
    }

    // Déplacez les pointeurs lent et rapide en même temps jusqu'à ce que le pointeur rapide atteigne la fin de la liste chaînée
    while (rapide != null) {
        lent = lent.suivant ;
        rapide = rapide.suivant ;
    }

    // A ce moment, slow pointe vers le nième nœud à partir du bas
    retourner slow.val;
}

Quelle est la différence entre les demandes de publication et les demandes d'obtention ? Quel est le contenu du corps de la demande de publication ?

HTTP (Hypertext Transfer Protocol) est un protocole utilisé pour transférer des données, qui définit les règles de communication entre le client et le serveur. En HTTP, GET et POST sont deux méthodes de requête courantes, et elles présentent quelques différences dans l'utilisation et le contenu du corps de la requête.

Requête GET :

  1. Scénario d'utilisation : la requête GET est utilisée pour obtenir des données du serveur, généralement pour obtenir des ressources, interroger des données, etc. Elle est idempotente, c'est-à-dire que l'exécution de la même requête GET plusieurs fois devrait avoir le même résultat et ne devrait pas avoir d'effets secondaires sur le serveur.
  2. Corps de la requête : les requêtes GET ne contiennent généralement pas de corps de requête. Tous les paramètres et données seront ajoutés à la chaîne de requête de l'URL et apparaîtront à la fin de l'URL sous la forme de paires clé-valeur, par exemple : http:/ /example.com/resource?param1 =value1¶m2=value2
  3. Transmission de données : les données de la requête GET sont transmises via l'URL, elles peuvent donc être vues directement dans le navigateur, il y a une limite de longueur et elles sont généralement utilisées pour transmettre de petites quantités de données.
  4. Sécurité : les requêtes GET ont des exigences moindres en matière de sécurité des données, car les données de la requête peuvent être facilement visualisées et modifiées, elles ne conviennent donc pas à la transmission d'informations sensibles.

Requête POST :

  1. Scénarios d'utilisation : les requêtes POST sont généralement utilisées pour soumettre des données au serveur, telles que la soumission de formulaires, le téléchargement de fichiers, etc. Ce n'est pas idempotent, c'est-à-dire que l'exécution de la même requête POST plusieurs fois peut produire des résultats différents et avoir des effets secondaires sur le serveur.
  2. Corps de la requête : la requête POST contient un corps de requête, qui stocke les données à transmettre, qui peuvent être des données de formulaire, des données JSON, des données XML, etc. Il n'y a pas de limite de longueur de données.
  3. Transmission de données : les données de la requête POST ne seront pas affichées dans l'URL, mais seront placées dans le corps de la requête, elles sont donc plus adaptées à la transmission de grandes quantités de données, et elles sont également plus sûres car les données ne seront pas directement transmises. exposé dans l’URL.
  4. Sécurité : les requêtes POST ont des exigences élevées en matière de sécurité des données, car les données contenues dans le corps de la requête ne sont pas faciles à visualiser et à modifier et conviennent à la transmission d'informations sensibles.

Compréhension profonde

GET et POST sont tous deux des méthodes de requête http, et la couche inférieure est le protocole TCP/IP ; généralement GET génère un paquet de données TCP ; POST génère deux paquets de données TCP (mais Firefox envoie un paquet de données). Pour la requête GET, le navigateur http l'en-tête et les données seront envoyés ensemble et le serveur répondra avec 200

(Données renvoyées) indique le succès ; pour le POST, le navigateur envoie d'abord l'en-tête, le serveur répond par 100, puis le navigateur continue d'envoyer des données, et le serveur

Le serveur répond avec 200 (renvoie des données).

La demande de publication peut-elle transmettre des données via une URL ?

Les requêtes POST transfèrent généralement les données dans le corps de la requête, plutôt que d'ajouter les données à l'URL comme les requêtes GET. Il s'agit d'une utilisation typique des requêtes POST, car les requêtes POST sont généralement utilisées pour transmettre de plus grandes quantités de données, telles que la soumission de formulaires, le téléchargement de fichiers, etc. Bien que vous puissiez théoriquement ajouter des données à l'URL, cela ne constitue pas une pratique standard pour les requêtes POST et peut entraîner des données manquantes ou incomplètes en raison des restrictions de longueur de l'URL.

Comment Redis et MySQL assurent la cohérence des données

Définir le délai d'expiration du cache est le point clé

1. Toutes les opérations d'écriture sont soumises à la base de données. Tant que le délai d'expiration du cache est atteint, le cache sera supprimé.

2. S'il y a une autre demande de lecture plus tard, la nouvelle valeur sera lue dans la base de données et le cache sera rempli.

Stratégie de double suppression retardée

Effectuez l'opération redis.del(key) avant et après l'écriture de la base de données et définissez un délai d'attente raisonnable.

1. Supprimez d'abord le cache 2. Ensuite, écrivez dans la base de données 3. Mettez en veille pendant xxx millisecondes (en fonction de l'heure de travail spécifique) 4. Supprimez à nouveau le cache

Cache de mise à jour asynchrone (basé sur le mécanisme de synchronisation des journaux binaires Mysql)

1. Pour les opérations de données mises à jour, utilisez Mysql binlog pour une consommation d'abonnement incrémentielle.

2. Envoyez le message à la file d'attente des messages

3. Mettre à jour les données incrémentielles vers Redis via la consommation de la file d'attente de messages

4. État de fonctionnement

Comment concevoir le cache Redis

  1. Stratégie de stockage des données : Sélection de la structure des données : choisissez une structure de données Redis appropriée en fonction des caractéristiques des données, telles que des chaînes, des tables de hachage, des listes, des ensembles ou des ensembles ordonnés. Partitionnement des données : si vous devez stocker une grande quantité de données, vous pouvez envisager de partitionner les données sur plusieurs nœuds Redis pour augmenter la capacité de stockage et les performances.
  2. Politique de mise à jour du cache : Politique d'écriture : détermine le moment où les données sont écrites dans le cache. Les stratégies courantes incluent la mise à jour lors de la lecture et de l'écriture, la synchronisation périodique, le modèle de publication/abonnement, etc. Synchronisation des données : assurez-vous que les données dans le cache sont cohérentes avec la source de données persistante (telle qu'une base de données). La double écriture, la synchronisation périodique ou la file d'attente de messages peuvent être utilisées.
  3. Politique d'invalidation du cache : Délai d'expiration : définissez un délai d'expiration approprié pour le cache afin de garantir que les données n'existent pas indéfiniment dans le cache. Invalidation manuelle : lorsque les données changent, les données dans le cache sont marquées comme invalides dans le temps afin qu'elles puissent être obtenues à partir des données source lors de leur prochaine lecture.
  4. Haute disponibilité du cache : réplication maître-esclave : utilisez le mécanisme de réplication maître-esclave de Redis pour garantir la sauvegarde des données et la haute disponibilité. Mode Sentinel : utilisez Redis Sentinel pour surveiller et gérer les instances Redis afin de basculer automatiquement vers le nœud de sauvegarde en cas de panne du nœud principal. Mode cluster : utilisez Redis Cluster pour obtenir le partage des données et la haute disponibilité.
  5. Pénétration du cache et prévention des avalanches : filtre Bloom : utilisez le filtre Bloom pour empêcher la pénétration du cache, c'est-à-dire interroger des données inexistantes. Délai d'expiration aléatoire : ajoutez un caractère aléatoire lors de la définition du délai d'expiration du cache pour éviter une avalanche de cache.
  6. Sécurité : restreindre l'accès externe : restreindre l'accès externe au service Redis via des pare-feu ou d'autres moyens pour protéger la sécurité des données. Authentification par mot de passe : définissez un mot de passe Redis pour garantir que seuls les utilisateurs autorisés peuvent accéder à Redis.
  7. Sauvegarde et récupération : sauvegarde régulière : sauvegardez régulièrement les données Redis pour faire face à la perte ou aux dommages de données. Plan de reprise après sinistre : élaborez un plan de reprise après sinistre pour garantir que les données peuvent être rapidement restaurées en cas de panne grave.

Pourquoi Linux doit-il configurer le mode utilisateur et le mode noyau ?

Parmi les instructions du CPU, certaines sont très dangereuses et entraîneront un crash du système si elles ne sont pas utilisées correctement, comme effacer la mémoire, régler l'horloge, etc. Par conséquent, le CPU divise les instructions en instructions privilégiées et instructions non privilégiées. Pour les instructions dangereuses, seuls le système d'exploitation et ses modules associés peuvent être utilisés, et les applications ordinaires ne peuvent utiliser que des instructions non dangereuses.

  • Le processeur Intel divise le niveau de privilège en 4 niveaux : Ring0~Ring3, tandis que Linux utilise le niveau Ring3 pour exécuter le mode utilisateur et Ring0 comme mode noyau.
  • Lorsque le système d'exploitation démarre, la mémoire est divisée. Les données du système d'exploitation sont stockées dans l'espace noyau et les données du processus utilisateur sont stockées dans l'espace utilisateur. Les programmes au niveau du mode utilisateur ne peuvent accéder qu'à l'espace utilisateur, tandis que les programmes au niveau du mode noyau peuvent accéder à la fois à l'espace utilisateur et à l'espace noyau.
  • Lorsqu'un processus exécute un appel système et est piégé dans le code du noyau, on dit que le processus est en mode noyau.

Quelle est la différence entre les cookies et les sessions ?

Lieu de stockage : Cookies : Les cookies sont de petits fichiers texte stockés dans le navigateur de l'utilisateur. Chaque fois qu'un utilisateur visite un site Web, le serveur peut envoyer un ou plusieurs cookies au navigateur de l'utilisateur, et le navigateur enregistre ensuite ces cookies sur l'ordinateur local de l'utilisateur. Session : les données de session sont généralement stockées côté serveur. Le serveur crée un identifiant unique pour chaque session (correspondant généralement à une session d'accès d'un utilisateur), puis stocke les données pertinentes dans la mémoire du serveur ou les conserve dans une base de données.

Sécurité : Cookies : Les cookies sont stockés dans le navigateur de l'utilisateur et peuvent donc être modifiés ou supprimés par l'utilisateur. Bien que la technologie de cryptage puisse être utilisée pour améliorer la sécurité des cookies, ils restent vulnérables aux attaques telles que le cross-site scripting (XSS). Session : les données de session sont stockées sur le serveur et ne peuvent pas être directement consultées ou modifiées par les utilisateurs. Cela rend les sessions généralement plus sécurisées que les cookies, mais la sécurité côté serveur reste essentielle.

Capacité de stockage : Cookie : Les navigateurs ont des limites sur la capacité de stockage des cookies. Généralement, la taille de chaque cookie ne doit pas dépasser quelques Ko. Cela limite la quantité de données qu'un cookie peut stocker. Session : le stockage côté serveur est généralement plus grand et peut stocker plus de données sans être limité par le navigateur.

Durée de validité : Cookie : Vous pouvez paramétrer la durée d'expiration du Cookie. Il peut s'agir d'un cookie de session (expire après la fermeture du navigateur) ou d'un cookie persistant (expire après une certaine période de temps). Session : les données de session expirent généralement automatiquement lorsque l'utilisateur ferme le navigateur, mais leur validité peut également être prolongée en définissant un délai d'expiration.

Finalité : Cookie : principalement utilisé pour suivre l’identité de l’utilisateur, enregistrer les préférences de l’utilisateur, les informations sur le panier, etc. Ils sont généralement utilisés pour la gestion de l'état du client. Session : utilisée pour maintenir l'état de session de l'utilisateur côté serveur, généralement utilisée pour la gestion de l'état côté serveur, telle que l'authentification, l'autorisation et la gestion du panier.

Livraison entre pages : Cookies : Les données peuvent être transmises entre différentes pages car elles sont stockées dans le navigateur et peuvent être lues par le code JavaScript sur différentes pages. Session : les données de session sont généralement stockées sur le serveur et peuvent être partagées entre différentes pages du serveur, mais doivent être accessibles via un identifiant de session.

mécanisme de verrouillage

Plus précisément, les verrous de fichiers sont généralement divisés en deux types :

  1. Verrouillage partagé : plusieurs processus ou threads peuvent acquérir des verrous partagés sur des fichiers en même temps pour les opérations de lecture. Les verrous partagés ne bloquent pas les opérations de lecture effectuées par d'autres processus ou threads, mais ils bloquent les opérations d'écriture.
  2. Verrou exclusif : un seul processus ou thread peut obtenir un verrou exclusif sur un fichier pour les opérations d'écriture. Les verrous exclusifs bloquent les opérations de lecture et d'écriture d'autres processus ou threads.

http et protocole http

Sécurité : HTTP : HTTP est un protocole non sécurisé. Toutes les données sont transmises en texte clair et peuvent facilement être interceptées par des attaques de l'homme du milieu et voler des informations sensibles. HTTPS : HTTPS ajoute des fonctionnalités de sécurité au protocole HTTP et utilise le protocole SSL/TLS pour crypter et authentifier les données. Cela signifie que dans la communication HTTPS, les données sont cryptées pendant la transmission et ne peuvent pas être facilement volées ou falsifiées, offrant ainsi une sécurité accrue.

Cryptage : HTTP : HTTP ne fournit pas de cryptage des données, toutes les données sont donc transmises en texte clair. HTTPS : HTTPS utilise le protocole SSL/TLS pour crypter les données de communication et garantir que les données restent confidentielles pendant la transmission.

Authentification : HTTP : HTTP ne fournit pas de mécanisme d'authentification du serveur, ce qui rend difficile la garantie que le point de terminaison de connexion est connecté au serveur prévu. HTTPS : HTTPS utilise un certificat numérique pour vérifier l'identité du serveur et garantir que vous vous connectez au bon serveur. Cela évite les attaques de l’homme du milieu.

Pourquoi devrions-nous diviser les processus et les threads ?

  1. Isolation des ressources : Processus : Chaque processus possède son propre espace mémoire indépendant, de sorte que les données entre les processus sont isolées les unes des autres. Cela signifie qu'un bug ou un crash dans un processus n'affecte généralement pas les autres processus. Threads : les threads partagent l’espace mémoire du même processus, afin qu’ils puissent partager des données et communiquer plus facilement. Mais de ce fait, une erreur dans un thread peut affecter d’autres threads du même processus.
  2. Surcharge de création et de destruction : Processus : La création et la destruction de processus prennent généralement du temps car chaque processus doit allouer de l'espace mémoire et des ressources système indépendantes. Threads : la surcharge liée à la création et à la destruction de threads est relativement faible car ils partagent les mêmes ressources de processus.
  3. Concurrence : processus : la concurrence entre les processus est faible car le changement de processus implique un changement de contexte et une réallocation des ressources. Threads : la concurrence entre les threads est plus élevée car ils peuvent partager des données et communiquer plus facilement sans changer de processus.
  4. Utilisation multicœur : Processus : les processeurs multicœurs peuvent exécuter plusieurs processus en parallèle, améliorant ainsi les performances du système. Threads : les processeurs multicœurs peuvent exécuter plusieurs threads en parallèle, permettant une utilisation plus efficace des ressources multicœurs.
  5. Répartition des tâches : Processus : généralement utilisé pour effectuer des tâches indépendantes et n'a pas besoin de partager fréquemment des données. Threads : généralement utilisés pour effectuer des sous-tâches liées à la tâche principale et doivent partager fréquemment des données.

おすすめ

転載: blog.csdn.net/qq_51118755/article/details/133344891