Recettes courantes pour mansart-jakarta-data, mansart-transactions et mansart-pool. La référence exhaustive (toutes annotations, toutes options de config) est dans Référence.

Repositories Jakarta Data

BasicRepository<T, K> et CrudRepository<T, K>

BasicRepository couvre save, delete, findById, findAll. CrudRepository ajoute des variantes batch typées. Pour aller plus loin, on déclare des méthodes spécialisées sur l’interface ; l’APT les transforme en plans de requête statiques.

@Repository
public interface AuthorRepository extends CrudRepository<Author, Long> {
    long count();
    boolean existsById(Long id);
}

Derived queries (par nom de méthode)

Mansart parse le nom et produit un AST neutre, puis du SQL via le dialecte cible. Mots-clés supportés : findBy, existsBy, countBy, deleteBy, opérateurs And, Or, Like, Between, LessThan, GreaterThan, LessThanEqual, GreaterThanEqual, IgnoreCase, OrderBy<Asc|Desc>.

List<Author> findByName(String name);
Optional<Author> findOneByName(String name);
List<Author> findByNameLike(String pattern);
List<Author> findByNameIgnoreCase(String name);
List<Author> findAllByOrderByNameAsc();
long deleteByName(String name);

@Find (matching par paramètres typés)

@Find
List<Book> findByAuthorAndPublishedOnBetween(Author author,
                                             LocalDate from,
                                             LocalDate to);

Le nom du paramètre Java doit correspondre à l’attribut entité (compiler avec -parameters).

@Query JDQL

JDQL est le dialecte de requête défini par Jakarta Data 1.0. Plus simple que JPQL, suffisant pour le SELECT/UPDATE/DELETE typés.

@Query("FROM Author WHERE name LIKE :pattern AND id > :minId")
List<Author> search(String pattern, Long minId);

@Query("UPDATE Author SET name = :newName WHERE name = :oldName")
long rename(String oldName, String newName);

Pagination — offset et keyset

Page<Author> findByNameLikeOrderByNameAsc(String pattern, PageRequest page);

// Appel
var page = authors.findByNameLikeOrderByNameAsc("S%", PageRequest.ofPage(1).size(20));

Les curseurs keyset (PageRequest.afterKey(…​)) évitent le drift en pagination longue.

Lifecycle annotations

@Insert, @Update, @Delete, @Save typés : paramètre = entité, collection ou varargs ; retour void/T/Iterable<T>/int/long/boolean. Voir Référence.

Transactions

@Transactional (CDI)

L’intercepteur de mansart-transactions matérialise @jakarta.transaction.Transactional (TxType REQUIRED, REQUIRES_NEW, MANDATORY, SUPPORTS, NEVER, NOT_SUPPORTED).

@ApplicationScoped
public class AuthorService {

    @Inject AuthorRepository authors;

    @Transactional
    public Author register(String name) {
        return authors.save(new Author(name));
    }

    @Transactional(Transactional.TxType.REQUIRES_NEW)
    public void audit(String message) { /* ... */ }
}

UserTransaction (programmatique)

@Inject UserTransaction tx;

void run() throws Exception {
    tx.begin();
    try {
        authors.save(new Author("Marguerite Yourcenar"));
        tx.commit();
    } catch (Exception e) {
        tx.rollback();
        throw e;
    }
}

Suspend / resume

TransactionManager.suspend() et resume(Transaction) couvrent les cas batch / scheduler. Le contexte transactionnel est porté par un ScopedValue<TransactionContext>, donc transparent à travers les virtual threads créés par StructuredTaskScope.

Pool de connexions

Configuration minimale

var ds = MansartDataSource.create(PoolConfig.builder()
    .jdbcUrl("jdbc:postgresql://db.local:5432/shop")
    .username("shop").password("...")
    .minSize(4).maxSize(32)
    .acquireTimeout(Duration.ofSeconds(5))
    .idleTimeout(Duration.ofMinutes(10))
    .maxLifetime(Duration.ofMinutes(30))
    .validationMode(ValidationMode.IS_VALID)
    .build());

Sizing

Avec virtual threads, le sizing classique « threads = connections » disparaît : on dimensionne sur la concurrence DB réelle, pas sur la concurrence applicative. Règle de pouce : maxSize ≈ vCPUs DB × 2..4. Au-delà, le DB devient le goulot — voir lien:https://codeberg.org/Vidocq/mansart/src/branch/main/mansart-pool/BENCH.md[mansart-pool BENCH.md].

Détection de fuites

leakDetectionThreshold(Duration) log un warning + stack-trace d’acquisition quand une connexion reste empruntée plus longtemps que le seuil. À activer en staging, désactiver en prod si l’overhead est mesuré.

Composition avec les autres modules

  • Vauban CDI — produit les beans @Repository, gère l’intercepteur @Transactional.

  • Cassini REST — endpoints REST appelant les services transactionnels.

  • Vidocq Runtime — orchestrateur qui assemble pool + tx + data + REST dans un fat-jar AOT-friendly.