Untitled

 avatar
unknown
markdown
23 days ago
23 kB
4
Indexable

SPRING, HIBERNATE

Cos'è l'Optimistic Lock in JPA/Hibernate e quando si usa?

Serve per gestire la concorrenza ottimistica. Si implementa con @Version. Hibernate verifica il campo versione al momento dell'update: se è cambiato rispetto al valore originale, genera OptimisticLockException.

Cos’è la MultipleBagFetchException e come la risolvi?

È un'eccezione generata da Hibernate quando provi a eseguire contemporaneamente fetch join di più liste. Puoi risolverla facendo fetch separati, usando Set al posto di List, oppure EntityGraph.

L’annotazione @Transactional funziona sui metodi privati? Perché?

No. Spring crea proxy solo sui metodi pubblici o protetti. I metodi privati non vengono intercettati perché Spring AOP è basato sui proxy generati dinamicamente.

A cosa servono @DynamicInsert e @DynamicUpdate in Hibernate?

Permettono a Hibernate di generare query SQL che contengono solo i campi effettivamente modificati o popolati, evitando aggiornamenti inutili di tutte le colonne.

Come implementeresti Logging distribuito nei microservizi? Che ruolo hanno traceId, spanId e Zipkin?

Usando strumenti come Sleuth e Zipkin, che propagano traceId e spanId nei log per correlare richieste distribuite su più microservizi e analizzare eventuali problemi.

Come gestiresti metriche e tracing (uso CPU, memoria) nei microservizi?

Con Micrometer e sistemi come Prometheus/Grafana, integrati con Zipkin per tracing. Permette monitoraggio continuo e alerting automatico.

Quale è il ciclo di vita di un bean?

  • Istanziazione

    Constructor Injection: avviene proprio in questa fase, ovvero durante la creazione del bean. Tutte le dipendenze dichiarate nel costruttore sono già state istanziate e vengono iniettate immediatamente quando il bean viene creato.
  • Iniezione delle dipendenze (@Autowired, Field Injection)

Dopo che l'oggetto è stato istanziato (e quindi dopo la constructor injection), Spring esegue la field injection (se utilizzata), valorizzando tutti i campi annotati con @Autowired. Questo avviene subito dopo la creazione dell'oggetto e prima che il bean venga usato.

  • Callback di inizializzazione (@PostConstruct)

Dopo che tutte le dipendenze sono state iniettate (tramite costruttore o @Autowired sui campi/metodi), Spring chiama il metodo annotato con @PostConstruct. Qui puoi eseguire ulteriori inizializzazioni che richiedono tutte le dipendenze già pronte.

  • Uso del bean

Il bean è ora pienamente operativo e può essere utilizzato dalla tua applicazione.

  • Callback di distruzione (@PreDestroy)

Prima che il bean venga distrutto, viene invocato il metodo annotato con @PreDestroy, dove puoi eseguire eventuali attività di cleanup.

Cos'è un EntityListener in JPA e quando lo useresti?

Sono classi o metodi annotati per intercettare eventi del ciclo di vita delle entità (es: @PrePersist, @PostLoad). Utile per auditing, logging, operazioni automatiche.

Qual è la differenza tra Event Listener e Entity Listener in Spring?

Event Listener è un meccanismo generico per intercettare eventi Spring a livello applicativo. Entity Listener è specifico per eventi del ciclo di vita delle entity JPA.

Cos'è un Aspect in Spring e quando si usa?

Un Aspect è una logica cross-cutting applicata con AOP. Serve per gestire logging centralizzato, transazioni, sicurezza, o caching senza sporcare il codice di business.

Come documenteresti una REST API usando OpenAPI (Swagger)?

Aggiungendo annotazioni (@Operation, @ApiResponse) o generando automaticamente documentazione da controller con Springdoc o SpringFox, ottenendo interfaccia esplorabile e documentata.

Cos'è un NaturalId in Hibernate?

È un identificativo alternativo della entity, naturale e stabile (es. codice fiscale, email). Utilizzabile con annotazione @NaturalId.

Che cos’è Hibernate Envers e a cosa serve?

È un modulo Hibernate per auditing automatico di entità. Tiene traccia delle modifiche storiche su entità con versionamento automatico dei dati.

Cos'è un Intersection Type in Java?

Un tipo derivato dall'intersezione di più interfacce, utile per esprimere che un parametro o variabile implementa contemporaneamente più interfacce, ad esempio <T extends InterfaceA & InterfaceB>.

Se un oggetto è dichiarato final, posso modificare i suoi campi interni?

Sì, l’oggetto final non può cambiare il riferimento stesso, ma puoi modificare i campi interni se non sono final o immutabili.

Quali tipi di transazioni e livelli di isolamento conosci in Spring/JPA?

Tipi transazione: REQUIRED, REQUIRES_NEW, SUPPORTS, NOT_SUPPORTED, NEVER, MANDATORY, NESTED. Livelli isolamento: READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE.

Se voglio escludere un bean Spring se non ho una certa classe nel classpath, quale annotazione uso?

@ConditionalOnClass

Che differenza c’è tra fetch EAGER e LAZY in Hibernate?

EAGER carica immediatamente l’entità collegata. LAZY posticipa il caricamento finché non si accede esplicitamente.

Quali librerie di mapping DTO-Entity conosci?

MapStruct, ModelMapper, Dozer, JMapper.

Puoi spiegare brevemente cosa sono le proprietà ACID nelle transazioni?

Atomicità (tutto o niente), Coerenza (stato valido), Isolamento (transazioni indipendenti), Durabilità (persistenza permanente).

Cos’è la cache di secondo livello Hibernate e quando la useresti?

Una cache condivisa tra sessioni per evitare continue query al DB. Utile per entità lette spesso e aggiornate raramente.

Qual è la differenza tra save() e persist() in Hibernate?

save() restituisce un identificatore e forza insert immediato. persist() è void e effettua insert al flush o commit.

Cosa sono le query derivate in Spring Data JPA?

Metodi che generano automaticamente query SQL dal nome, come findByNameAndAge.

Cos’è il problema N+1 query e come lo risolvi in Hibernate?

Avviene caricando entità relazionate con LAZY senza fetch join, causando molte query. Si risolve con JOIN FETCH, EntityGraph o batch-size.

Qual è la differenza tra Authentication e Authorization in Spring Security?

Authentication verifica chi è l'utente, Authorization verifica cosa può fare l’utente autenticato.

Qual è la differenza tra JPQL e Criteria API?

JPQL è string-based simile a SQL. Criteria API è tipizzata, più verbosa, ma ideale per query dinamiche sicure.

Cosa cambia tra Spring MVC e Spring WebFlux?

MVC è imperativo e blocking, basato su servlet (thread-per-request). WebFlux è reattivo, non-blocking, basato su Mono e Flux.

La transazione in self invocation rollbacka?

Devono passare per un proxy quindi in questo modo non funziona.

Esempio non funzionante Spring

import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class EmployeeService { private final EmployeeRepository employeeRepository; @EventListener(ApplicationReadyEvent.class) public void test() { testSelfInvocation(); } @Transactional public void testSelfInvocation() { Employee emp1 = new Employee("Henry", "Ford", 22); employeeRepository.save(emp1); // ⚠️ this save is not rolled back BigDecimal.ONE.divide(BigDecimal.ZERO); // ❌ throws ArithmeticException Employee emp2 = new Employee("John", "Wick", 33); employeeRepository.save(emp2); } }

Soluzione Spring (Spostare il metodo @Transactional in un altro bean e iniettarlo)

@Service public class EmployeeService { @Autowired private EmployeeTransactionalService transactionalService; @EventListener(ApplicationReadyEvent.class) public void test() { transactionalService.testSelfInvocation(); // ✅ proxy Spring attivo } } @Service public class EmployeeTransactionalService { @Autowired private EmployeeRepository employeeRepository; @Transactional public void testSelfInvocation() { Employee emp1 = new Employee("Henry", "Ford", 22); employeeRepository.save(emp1); BigDecimal.ONE.divide(BigDecimal.ZERO); // ❌ rollback completo Employee emp2 = new Employee("John", "Wick", 33); employeeRepository.save(emp2); } }

Soluzione Spring (Recuperare il proxy Spring del proprio bean tramite ApplicationContext)

@Service public class EmployeeService { @Autowired private ApplicationContext context; @EventListener(ApplicationReadyEvent.class) public void test() { context.getBean(EmployeeService.class).testSelfInvocation(); // ✅ passa per il proxy } @Transactional public void testSelfInvocation() { Employee emp1 = new Employee("Henry", "Ford", 22); employeeRepository.save(emp1); BigDecimal.ONE.divide(BigDecimal.ZERO); // ❌ rollback Employee emp2 = new Employee("John", "Wick", 33); employeeRepository.save(emp2); } }

QUARKUS

La transazione in self invocation rollbacka?

Problema CDI, le chiamate interne alla stessa classe (this.metodo()) non passano per l'interceptor, quindi il problema della self-invocation resta.

Esempio non funzionante Quarkus

import jakarta.enterprise.context.ApplicationScoped; import jakarta.transaction.Transactional; import jakarta.inject.Inject; import jakarta.annotation.PostConstruct; import jakarta.persistence.EntityManager; import java.math.BigDecimal; @ApplicationScoped public class EmployeeService { @Inject EntityManager em; @PostConstruct void onStartup() { test(); // Self-invocation, transactional NON attiva } public void test() { testSelfInvocation(); // <-- Non passa per l'interceptor } @Transactional public void testSelfInvocation() { Employee emp1 = new Employee("Henry", "Ford", 22); em.persist(emp1); // ⚠️ non sarà rollbackato BigDecimal.ONE.divide(BigDecimal.ZERO); // ❌ ArithmeticException Employee emp2 = new Employee("John", "Wick", 33); em.persist(emp2); } }

Soluzione Quarkus (spostare il metodo Transactional in altro bean e inject)

@Inject EmployeeTransactionalService transactionalService; public void test() { transactionalService.testSelfInvocation(); }

Soluzione Quarkus (Recuperare il proxy CDI tramite @Inject Instance<> o CDI.current())

@Inject Instance<EmployeeService> self; public void test() { self.get().testSelfInvocation(); // <-- PASSA dall'interceptor! }

PATTERN

🧱 Pattern Creazionali

Singleton

Assicura che una classe abbia una sola istanza e fornisce un punto di accesso globale.

public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }

Factory Method

Fornisce un’interfaccia per creare oggetti, lasciando alle sottoclassi la responsabilità dell’istanziazione.

interface Prodotto { void stampa(); } class ProdottoA implements Prodotto { public void stampa() { System.out.println("Prodotto A"); } } class Fabbrica { public static Prodotto creaProdotto() { return new ProdottoA(); } }

Builder

Separa la costruzione di un oggetto complesso dalla sua rappresentazione.

class Pizza { private String impasto; private boolean mozzarella; public static class Builder { private String impasto; private boolean mozzarella; public Builder impasto(String impasto) { this.impasto = impasto; return this; } public Builder mozzarella(boolean mozzarella) { this.mozzarella = mozzarella; return this; } public Pizza build() { Pizza p = new Pizza(); p.impasto = this.impasto; p.mozzarella = this.mozzarella; return p; } } }

🧩 Pattern Strutturali

Adapter

Permette a classi con interfacce incompatibili di lavorare insieme.

class LegacyPrinter { void printLegacy(String s) { System.out.println("Legacy: " + s); } } interface Printer { void print(String s); } class PrinterAdapter implements Printer { private LegacyPrinter legacy; public PrinterAdapter(LegacyPrinter legacy) { this.legacy = legacy; } public void print(String s) { legacy.printLegacy(s); } }

Facade

Fornisce un’interfaccia semplificata a un sottosistema complesso.

class CPU { void start() { System.out.println("CPU avviata"); } } class Memoria { void carica() { System.out.println("Memoria caricata"); } } class ComputerFacade { private CPU cpu = new CPU(); private Memoria memoria = new Memoria(); public void avviaComputer() { cpu.start(); memoria.carica(); } }

⚙️ Pattern Comportamentali

Strategy

Permette di scegliere dinamicamente un algoritmo tra più opzioni.

interface MetodoPagamento { void paga(double importo); } class CartaCredito implements MetodoPagamento { public void paga(double importo) { System.out.println("Pagamento con carta: " + importo); } } class Acquisto { private MetodoPagamento metodo; public Acquisto(MetodoPagamento metodo) { this.metodo = metodo; } public void eseguiPagamento(double importo) { metodo.paga(importo); } }

Observer

Notifica automaticamente più oggetti quando uno stato cambia.

interface Osservatore { void aggiorna(String stato); } class ConcreteOsservatore implements Osservatore { public void aggiorna(String stato) { System.out.println("Aggiornato: " + stato); } } class Soggetto { private List<Osservatore> osservatori = new ArrayList<>(); public void aggiungi(Osservatore o) { osservatori.add(o); } public void notifica(String stato) { for (Osservatore o : osservatori) { o.aggiorna(stato); } } }

Che cos’è il Circuit Breaker pattern?

Pattern per gestire fallimenti temporanei nelle chiamate tra microservizi, evitando sovraccarichi e aumentando resilienza.

Quali sono i principi SOLID?

I principi SOLID sono 5 linee guida fondamentali per progettare software manutenibile, scalabile e robusto, soprattutto in programmazione orientata agli oggetti.

🔹 S – Single Responsibility Principle (Responsabilità Singola)

Ogni classe dovrebbe avere una sola responsabilità e quindi un solo motivo per cambiare.

✅ Una classe che fa solo una cosa è più facile da capire, testare e modificare.
❌ Se una classe gestisce più cose (es. logica di business e accesso ai dati), è più fragile e difficile da manutenere.


🔹 O – Open/Closed Principle (Aperto/Chiuso)

Una classe dovrebbe essere aperta all'estensione ma chiusa alla modifica.

✅ Puoi estendere il comportamento di una classe esistente (ad es. tramite ereditarietà o strategia), senza modificarne il codice sorgente.
❌ Se modifichi ogni volta il codice esistente per aggiungere funzionalità, rischi di introdurre bug.


🔹 L – Liskov Substitution Principle (Sostituibilità di Liskov)

Una sottoclasse deve poter essere usata al posto della sua superclasse senza rompere il comportamento atteso.

✅ Se una funzione usa un oggetto di tipo Base, dovrebbe funzionare anche con un oggetto di tipo Derived.
❌ Se la sottoclasse modifica il comportamento in modo non compatibile (es. lancia eccezioni o ignora metodi), viola questo principio.


🔹 I – Interface Segregation Principle (Separazione delle Interfacce)

È meglio avere interfacce specifiche e piccole, piuttosto che un’unica interfaccia generale e pesante.

✅ Gli oggetti dovrebbero implementare solo i metodi che usano realmente.
❌ Se un’interfaccia ha troppi metodi inutili per una classe, questa sarà costretta a implementarli comunque (spesso con metodi vuoti o non sensati).


🔹 D – Dependency Inversion Principle (Inversione delle Dipendenze)

Le classi dovrebbero dipendere da astrazioni, non da classi concrete.

✅ Le dipendenze principali dovrebbero essere interfacce o classi astratte, non implementazioni dirette.
❌ Se una classe crea direttamente le sue dipendenze (new), è difficile da testare e modificare.

Esempio pratico: usa iniezione delle dipendenze (Dependency Injection) per fornire alla classe ciò di cui ha bisogno.

JAVA

Posso rimuovere da una lista che sto ciclando un oggetto?

No non posso, se proprio devo posso usare un iterator o un removeif da java 8 (concurrent modification exception)

for (String str : myArrayList) { if (someCondition) { myArrayList.remove(str); } }

Come funziona MDC (Mapped Diagnostic Context) e a cosa serve?

Permette di aggiungere contesti specifici ai log, utili per analizzare richieste distribuite (es. aggiunta di traceId o correlationId).

Quanti metodi astratti ha un'interfaccia funzionale?

Un solo metodo astratto. Può avere metodi default e statici, ma sempre solo un abstract method.

Cosa sono covarianza e contravarianza nei generics Java?

Covarianza (extends): permette un tipo più specifico. Contravarianza (super): permette un tipo più generico.

Qual è la differenza tra Predicate, Function e Consumer in Java?

  • Predicate<T>: ritorna un boolean, usato per condizioni (filtri).
  • Function<T, R>: trasforma un tipo in un altro.
  • Consumer<T>: consuma un valore, ma non restituisce nulla.
Predicate<String> isShort = s -> s.length() < 5; System.out.println(isShort.test("ciao")); // true Function<String, Integer> length = s -> s.length(); System.out.println(length.apply("ciao")); // 4 Consumer<String> printer = s -> System.out.println("Ciao " + s); printer.accept("Lorenzo"); // Ciao Lorenzo

Qual è la differenza tra map() e flatMap()?

  • map(): applica una funzione e mantiene la struttura.
  • flatMap(): "appiattisce" una struttura annidata.
List<String> words = List.of("a", "bb", "ccc"); List<Integer> lengths = words.stream() .map(String::length) // List<Integer> .collect(Collectors.toList()); // [1, 2, 3] List<List<String>> list = List.of(List.of("a", "b"), List.of("c")); List<String> flat = list.stream() .flatMap(Collection::stream) .collect(Collectors.toList()); // [a, b, c]

A cosa serve Optional in Java?

Evita null, fornisce API fluente per gestire assenza/presenza di un valore.

Optional<String> maybeName = Optional.of("Lorenzo"); maybeName.ifPresent(System.out::println); // Lorenzo String name = maybeName.orElse("Default"); // name = "Lorenzo"

Differenza tra forEach() e peek() su uno stream

  • forEach(): operazione terminale, esegue un’azione e consuma lo stream.
  • peek(): operazione intermedia, utile per debug/logging.
Stream.of("a", "b", "c") .peek(e -> System.out.println("Peek: " + e)) .map(String::toUpperCase) .forEach(System.out::println); // Peek: a // A // Peek: b // B // Peek: c // C

Se usi solo peek() senza una terminal operation come collect() o forEach(), non viene eseguito nulla.

Qual è il tipo di lista che mantiene l’ordine degli elementi?

ArrayList, LinkedList (mantengono l’ordine di inserimento).

List<String> lista = new ArrayList<>(); lista.add("uno"); lista.add("due"); System.out.println(lista); // [uno, due]

Qual è il tipo di set che mantiene l’ordine degli elementi?

LinkedHashSet mantiene l’ordine di inserimento, TreeSet l’ordine naturale.

Set<String> set1 = new LinkedHashSet<>(List.of("b", "a", "c")); System.out.println(set1); // [b, a, c] Set<String> set2 = new TreeSet<>(List.of("b", "a", "c")); System.out.println(set2); // [a, b, c]

SQL

Che cos’è la normalizzazione del database e cosa comportano le prime tre forme normali?

È un processo per ridurre ridondanza e migliorare l’integrità dei dati.

  • 1NF: Valori atomici e righe uniche.
  • 2NF: Attributi non-chiave dipendono interamente dalla chiave primaria.
  • 3NF: Attributi non-chiave non hanno dipendenze transitive.

Normalizzazione del Database – 1NF, 2NF, 3NF

1NF – Prima Forma Normale

Una tabella è in 1NF se:

  • Ogni colonna contiene valori atomici (non liste o array).
  • Ogni riga è univoca (con chiave primaria).

❌ Esempio NON in 1NF

ID_OrdineArticoli
1Penna, Quaderno
2Matita, Gomma

La colonna "Articoli" contiene più valori → violazione 1NF.

✅ Esempio in 1NF (normalizzato)

ID_OrdineArticolo
1Penna
1Quaderno
2Matita
2Gomma

2NF – Seconda Forma Normale

Una tabella è in 2NF se:

  • È già in 1NF.
  • Ogni colonna non chiave dipende dall’intera chiave primaria, non solo da una parte.

❌ Esempio NON in 2NF

Chiave primaria: (ID_Ordine, Articolo)

ID_OrdineArticoloCliente
1PennaMario Rossi
1QuadernoMario Rossi
2MatitaLuca Bianchi
2GommaLuca Bianchi

"Cliente" dipende solo da ID_Ordine, non da tutta la chiave primaria → violazione 2NF.

✅ Esempio in 2NF

Tabella Ordini

ID_OrdineCliente
1Mario Rossi
2Luca Bianchi

Tabella DettagliOrdine

ID_OrdineArticolo
1Penna
1Quaderno
2Matita
2Gomma

3NF – Terza Forma Normale

Una tabella è in 3NF se:

  • È già in 2NF.
  • Nessuna colonna non chiave dipende da un’altra colonna non chiave (no dipendenze transitive).

❌ Esempio NON in 3NF

ID_OrdineClienteIndirizzo Cliente
1Mario RossiVia Roma, Roma
2Luca BianchiVia Milano, Milano

"Indirizzo Cliente" dipende da "Cliente" e non da ID_Ordineviolazione 3NF.

✅ Esempio in 3NF

Tabella Ordini

ID_OrdineCliente
1Mario Rossi
2Luca Bianchi

Tabella Clienti

ClienteIndirizzo
Mario RossiVia Roma, Roma
Luca BianchiVia Milano, Milano
Leave a Comment