Common recipes for mansart-jakarta-data, mansart-transactions, and mansart-pool. The exhaustive reference (all annotations, all configuration options) lives in Reference.
Jakarta Data repositories
BasicRepository<T, K> and CrudRepository<T, K>
BasicRepository covers save, delete, findById, findAll. CrudRepository adds typed batch variants. To go further, declare specialized methods on the interface; the APT turns them into static query plans.
@Repository
public interface AuthorRepository extends CrudRepository<Author, Long> {
long count();
boolean existsById(Long id);
}
Derived queries (by method name)
Mansart parses the name into a neutral AST, then produces SQL via the target dialect. Supported keywords: findBy, existsBy, countBy, deleteBy, operators 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 (typed parameter matching)
@Find
List<Book> findByAuthorAndPublishedOnBetween(Author author,
LocalDate from,
LocalDate to);
The Java parameter name must match the entity attribute (compile with -parameters).
@Query JDQL
JDQL is the query dialect defined by Jakarta Data 1.0. Simpler than JPQL, sufficient for typed SELECT/UPDATE/DELETE.
@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 and keyset
Page<Author> findByNameLikeOrderByNameAsc(String pattern, PageRequest page);
// Call
var page = authors.findByNameLikeOrderByNameAsc("S%", PageRequest.ofPage(1).size(20));
Keyset cursors (PageRequest.afterKey(…)) avoid drift on long pagination.
Lifecycle annotations
@Insert, @Update, @Delete, @Save typed: parameter = entity, collection or varargs; return void/T/Iterable<T>/int/long/boolean. See Reference.
Transactions
@Transactional (CDI)
The mansart-transactions interceptor materializes @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) { /* ... */ }
}
Connection pool
Minimal configuration
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
With virtual threads, the classic "threads = connections" sizing disappears: dimension on real DB concurrency, not application concurrency. Rule of thumb: maxSize ≈ DB vCPUs × 2..4. Beyond that, the DB becomes the bottleneck — see lien:https://codeberg.org/Vidocq/mansart/src/branch/main/mansart-pool/BENCH.md[mansart-pool BENCH.md].
Composition with other modules
-
Vauban CDI — produces
@Repositorybeans, runs the@Transactionalinterceptor. -
Cassini REST — REST endpoints calling transactional services.
-
Vidocq Runtime — orchestrator that assembles pool + tx + data + REST into an AOT-friendly fat jar.