Cache
Besu has no query cache, no result cache and no cached relation. Caching is an application decision: only you know when a row stops being true. What the library owns is a rendered statement, and that is a good cache key.
What the driver already caches
sqlx prepares each statement and caches the prepared form per SQL string. That is why
repeating a query shape is cheaper than inventing a new one per call, and why the PostgreSQL
dialect appends a type suffix to statements whose parameter types can vary: two statements with
identical text but different bound types must not share one cache entry. The cache belongs to
the driver; Besu exposes no prepare handle of its own.
Wrapping a query in your own cache
Build the query, render it, and use the text plus the arguments as the key.
to_sql borrows the query, so the same value is rendered and then run; nothing is built twice.
Swap the HashMap for whatever your runtime uses — a RwLock, an LRU, an external store — but
keep two properties: the key is derived from the statement, and the entry has a lifetime you
control.
Why the statement is a stable key
sql.sql() is deterministic for the same builder, dialect and Database::prefixed prefix, and
sql.args() is in bind order. Two calls that build the same query from the same values
produce the same string and the same arguments.
The prefix is part of the text, so a prefixed database and an unprefixed one never share an entry. The dialect is part of the text too, so do not reuse a key across backends.
Gotchas
- You own invalidation. Nothing in Besu tells a cache that a row changed, and a table rebuild or migration changes the meaning of a key without changing the text. Version the cache yourself.
- The argument's
Debugform has no type tag. A UUID and a string of the same characters both print as'…', so a rawFragmentwith one text and different argument types can collide where a typed builder cannot, because the column pins the type. Add a type tag to the key if you cache raw statements. - Caching a
Vec<User>clones it on every hit. The cache saves a round trip, not an allocation; return a reference or anArcif that matters. to_sql()does not run anything. A key can be computed for a statement that then fails, so do not insert an entry before the query succeeds.- The prepared-statement cache is not a result cache. It saves parsing and planning, not the query execution or the rows.
