I prefer the repositoryTable Data Gateway pattern, i.e. a stateless object for roughly each entity type, containg methods such as
void CustomerRepository.createCustomer(Customer c)
List<Customer> CustomerRepository.getCustomersByCountry(String country)
- Easy to add additional handling such as serialization, error handling, logging, validation, caching.
- Easy to find the correct function
- Less likely to have duplicate code
- Easy to migrate to a different database technology
- Easy to mock for testing
- Easy to instrument for performance monitoring