I think it’s a judgement call: I like clearly indicating when there’s always a single output path but wouldn’t use the single return style in that cache example if it involved an extra lookup operation for a value which is already known.
Yes - the cache example is bad; my point is the general idea of avoiding branches that merge back into the main function.
In your example above, the branch does merge back, and clearly that's fine for a small function - and common pattern - like this. But the general idea would be to avoid it if possible, because that removes unnecessary complexity.
One small problem is that depending on how your threading and cache works it might be possible for the cache to be cleared after the contains call but before the get.
imho, a get() from cache when you already have the value seems like an unnecessary waste of cycles and network traffic.
plus this arrangement would seem vulnerable to a pathological case where you found the V from the db, but have a full/failed/partitioned cache and end up faulting or otherwise not returning the V.