It is a matter of tradeoffs and requirements. Arc<RwLock> is a solid solution for most use cases. If the requirement is (just making up an unlikely extreme scenario) to have a huge amount of threads which constantly lock the RwLock a better solution might be to just open multiple connections per database, each per thread. SQLite, for example, is build with this in mind.
For a reasonable amount of locking, The Arc / RwLock dance offers good performance (other languages, like Swift, use something like Arc for every property access (although the compiler tries to optimise it away)).
The safety is actually better because you're forced to think about the failure case. I don't have good memories of Objective-C where some Foundation calls don't throw (in they don't have an error parameter), but just throw random undocumented exceptions. (Not saying that some Rust calls don't panic, but knowing that something can go wrong is much better than learning about it in production).
For a reasonable amount of locking, The Arc / RwLock dance offers good performance (other languages, like Swift, use something like Arc for every property access (although the compiler tries to optimise it away)).
The safety is actually better because you're forced to think about the failure case. I don't have good memories of Objective-C where some Foundation calls don't throw (in they don't have an error parameter), but just throw random undocumented exceptions. (Not saying that some Rust calls don't panic, but knowing that something can go wrong is much better than learning about it in production).