Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
eadl:bloc3:dev_av:td2 [2025/10/07 23:35] – jcheron | eadl:bloc3:dev_av:td2 [2025/10/08 00:18] (Version actuelle) – [4.4 Optimisation des identifiants avec Tsid] jcheron | ||
---|---|---|---|
Ligne 124: | Ligne 124: | ||
GET / | GET / | ||
GET / | GET / | ||
+ | </ | ||
+ | |||
+ | ===== Partie 4 : Hypersistence Utils - Outils avancés (30min-1h) ===== | ||
+ | |||
+ | ==== 4.1 Introduction à Hypersistence Utils ==== | ||
+ | |||
+ | <WRAP round bloc info> | ||
+ | **Hypersistence Utils** est une bibliothèque créée par Vlad Mihalcea qui apporte : | ||
+ | * Des types personnalisés (JSON, Array, etc.) | ||
+ | * Des utilitaires de diagnostic de performance | ||
+ | * Des listeners pour optimiser les opérations | ||
+ | * Des identifiants optimisés (Tsid) | ||
+ | </ | ||
+ | |||
+ | === Dépendance Maven === | ||
+ | |||
+ | <sxh xml; | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== 4.2 Détection automatique des problèmes N+1 ==== | ||
+ | |||
+ | <WRAP round bloc important> | ||
+ | **Objectif :** Détecter automatiquement les problèmes de performance sans analyse manuelle des logs | ||
+ | </ | ||
+ | |||
+ | === Configuration === | ||
+ | |||
+ | <sxh bash; | ||
+ | # application.properties - Ajout pour Hypersistence | ||
+ | |||
+ | # Détection des problèmes N+1 | ||
+ | logging.level.io.hypersistence.utils=DEBUG | ||
+ | |||
+ | # Limites d' | ||
+ | hypersistence.query.fail.on.pagination.over.collection.fetch=false | ||
+ | </ | ||
+ | |||
+ | === Utilisation du QueryStackTraceLogger === | ||
+ | |||
+ | <sxh java; | ||
+ | // Configuration globale (classe @Configuration) | ||
+ | @Configuration | ||
+ | public class HypersistenceConfiguration { | ||
+ | | ||
+ | @Bean | ||
+ | public QueryStackTraceLogger queryStackTraceLogger() { | ||
+ | return new QueryStackTraceLogger(); | ||
+ | } | ||
+ | | ||
+ | @EventListener | ||
+ | public void onApplicationEvent(ApplicationReadyEvent event) { | ||
+ | // Active la détection des problèmes N+1 | ||
+ | QueryStackTraceLogger.INSTANCE.setThreshold(10); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **Exercice :** | ||
+ | * Activer le logger sur l' | ||
+ | * Observer les alertes automatiques | ||
+ | * Corriger les problèmes détectés | ||
+ | |||
+ | ==== 4.3 Types JSON natifs ==== | ||
+ | |||
+ | <WRAP round bloc todo> | ||
+ | **Cas d' | ||
+ | </ | ||
+ | |||
+ | === Exemple : Attributs dynamiques produit === | ||
+ | |||
+ | <sxh java; | ||
+ | @Entity | ||
+ | @Table(name = " | ||
+ | public class Product { | ||
+ | // ... attributs existants | ||
+ | | ||
+ | @Type(JsonType.class) | ||
+ | @Column(columnDefinition = " | ||
+ | private Map< | ||
+ | | ||
+ | // Pour PhysicalProduct : {" | ||
+ | // Pour DigitalProduct : {" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === Données exemple === | ||
+ | |||
+ | <sxh json; | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **Exercice :** | ||
+ | * Ajouter le champ '' | ||
+ | * Créer un endpoint '' | ||
+ | * Filtrer les produits par attribut : '' | ||
+ | |||
+ | ==== 4.4 Optimisation des identifiants avec Tsid ==== | ||
+ | |||
+ | <WRAP round bloc info> | ||
+ | **Tsid (Time-Sorted Identifiers)** : | ||
+ | * Alternative performante aux UUID | ||
+ | * Triables chronologiquement | ||
+ | * Plus compacts (Long au lieu de UUID) | ||
+ | * Meilleure performance en base | ||
+ | </ | ||
+ | |||
+ | === Comparaison UUID vs Tsid === | ||
+ | |||
+ | <sxh java; | ||
+ | // Avant (UUID) | ||
+ | @Id | ||
+ | @GeneratedValue(strategy = GenerationType.UUID) | ||
+ | private UUID id; | ||
+ | |||
+ | // Après (Tsid) - Pour nouvelles entités | ||
+ | @Id | ||
+ | @TsidGenerator | ||
+ | private Long id; | ||
+ | </ | ||
+ | |||
+ | **Exercice optionnel :** | ||
+ | * Créer une nouvelle entité '' | ||
+ | * Comparer les performances d' | ||
+ | |||
+ | < | ||
+ | <uml> | ||
+ | @startuml Review Domain Model | ||
+ | |||
+ | class Review { | ||
+ | - id : Long | ||
+ | - rating : Integer | ||
+ | - title : String | ||
+ | - comment : String | ||
+ | - verified : Boolean | ||
+ | - helpfulCount : Integer | ||
+ | - createdAt : LocalDateTime | ||
+ | - updatedAt : LocalDateTime | ||
+ | } | ||
+ | |||
+ | class Product { | ||
+ | - id : UUID | ||
+ | - name : String | ||
+ | - price : BigDecimal | ||
+ | - stock : Integer | ||
+ | } | ||
+ | |||
+ | class User { | ||
+ | - id : UUID | ||
+ | - username : String | ||
+ | - email : String | ||
+ | } | ||
+ | |||
+ | Product " | ||
+ | User " | ||
+ | |||
+ | note right of Review | ||
+ | Contraintes métier : | ||
+ | • rating ∈ [1..5] | ||
+ | • 1 review max par (user, product) | ||
+ | • verified = true si achat confirmé | ||
+ | • helpfulCount >= 0 | ||
+ | | ||
+ | Tsid Generator pour l'id | ||
+ | (performance + tri chronologique) | ||
+ | end note | ||
+ | |||
+ | @enduml | ||
+ | |||
+ | |||
+ | |||
+ | </ | ||
+ | < | ||
+ | |||
+ | ==== 4.5 Monitoring des requêtes en temps réel ==== | ||
+ | |||
+ | === DataSourceProxyBeanPostProcessor === | ||
+ | |||
+ | <sxh java; | ||
+ | @Configuration | ||
+ | public class DataSourceProxyConfiguration { | ||
+ | | ||
+ | @Bean | ||
+ | public DataSourceProxyBeanPostProcessor dataSourceProxyBeanPostProcessor() { | ||
+ | return new DataSourceProxyBeanPostProcessor() { | ||
+ | @Override | ||
+ | protected DataSourceProxy createDataSourceProxy(DataSource dataSource) { | ||
+ | return new DataSourceProxy(dataSource, | ||
+ | } | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **Exercice :** | ||
+ | * Mettre en place le monitoring | ||
+ | * Créer un test d' | ||
+ | * Exemple : '' | ||
+ | |||
+ | ==== 4.6 Exercice intégratif ==== | ||
+ | |||
+ | <WRAP round bloc todo> | ||
+ | **Mission :** Améliorer l' | ||
+ | |||
+ | < | ||
+ | GET / | ||
+ | </ | ||
+ | |||
+ | **Avec Hypersistence :** | ||
+ | * Détecter automatiquement les problèmes N+1 | ||
+ | * Limiter à 5 requêtes maximum (assertion en test) | ||
+ | * Stocker les préférences utilisateur en JSON | ||
+ | * Logger les performances de la recommandation | ||
+ | |||
+ | **Structure JSON recommandée :** | ||
+ | <sxh json; | ||
+ | // User.preferences (JSON) | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== Configuration complète ===== | ||
+ | |||
+ | <sxh bash; | ||
+ | # application.properties - Configuration complète Séance 2 | ||
+ | |||
+ | # H2 Database | ||
+ | spring.datasource.url=jdbc: | ||
+ | spring.datasource.driverClassName=org.h2.Driver | ||
+ | spring.datasource.username=sa | ||
+ | spring.datasource.password= | ||
+ | |||
+ | # H2 Console | ||
+ | spring.h2.console.enabled=true | ||
+ | spring.h2.console.path=/ | ||
+ | |||
+ | # JPA/ | ||
+ | spring.jpa.hibernate.ddl-auto=update | ||
+ | spring.jpa.show-sql=true | ||
+ | spring.jpa.properties.hibernate.format_sql=true | ||
+ | spring.jpa.properties.hibernate.use_sql_comments=true | ||
+ | spring.jpa.properties.hibernate.generate_statistics=true | ||
+ | |||
+ | # Logging SQL et statistiques | ||
+ | logging.level.org.hibernate.SQL=DEBUG | ||
+ | logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE | ||
+ | logging.level.org.hibernate.stat=DEBUG | ||
+ | logging.level.org.hibernate.orm.jdbc.bind=TRACE | ||
+ | |||
+ | # Hypersistence Utils | ||
+ | logging.level.io.hypersistence.utils=DEBUG | ||
</ | </ | ||
Ligne 135: | Ligne 405: | ||
* ✅ Résolution problème N+1 sur au moins 2 endpoints | * ✅ Résolution problème N+1 sur au moins 2 endpoints | ||
* ✅ Implémentation héritage produits (1 stratégie au choix) | * ✅ Implémentation héritage produits (1 stratégie au choix) | ||
+ | * ✅ **Hypersistence : détection automatique N+1 activée** | ||
* ✅ Tests d' | * ✅ Tests d' | ||
**Nice to have :** | **Nice to have :** | ||
* Comparaison des 3 stratégies d' | * Comparaison des 3 stratégies d' | ||
- | * DTO Projections avec MapStruct | + | * **Type JSON pour attributs dynamiques produits** |
- | * Benchmark avant/ | + | * **Tsid sur une nouvelle entité (Review, Wishlist...)** |
+ | * Benchmark avant/ | ||
* Documentation des choix architecturaux | * Documentation des choix architecturaux | ||
</ | </ | ||
- | |||
- | ===== Critères d' | ||
- | |||
- | ^ Critère ^ Points ^ | ||
- | | Associations correctement mappées | 25% | | ||
- | | Résolution problèmes N+1 | 30% | | ||
- | | Implémentation héritage | 25% | | ||
- | | Tests et qualité code | 20% | | ||
- | |||
- | ===== Configuration supplémentaire ===== | ||
- | |||
- | <sxh yaml; | ||
- | # application.yml - pour la séance | ||
- | spring: | ||
- | jpa: | ||
- | show-sql: true | ||
- | properties: | ||
- | hibernate: | ||
- | format_sql: true | ||
- | use_sql_comments: | ||
- | generate_statistics: | ||
- | logging: | ||
- | level: | ||
- | org.hibernate.stat: | ||
- | </ | ||
===== Ressources ===== | ===== Ressources ===== | ||
* [[https:// | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
* [[https:// | * [[https:// | ||
+ | |||
<WRAP round bloc info> | <WRAP round bloc info> |