Most contrib modules have no reason to talk to the database directly instead a combination of configuration management, key value storage and the entity system should be used.
The feature here is useful for modules which wants to use proprietary features of a specific database and also for database drivers.
Before
In order to swap out the implementation of a service you could always change the container on compile() time:
class Example implements CompilerPassInterface {
public function process(ContainerBuilder $container) {
$container->set('views.date_sql', new Definition('Drupal\views\Plugin\views\query\PostgresqlDateSql'));
}
}
After
The service you want to replace has to be tagged with backend_overridable and a backend specific override can be defined like this:
views.date_sql:
class: Drupal\views\Plugin\views\query\MysqlDateSql
arguments: ['@database']
tags:
- { name: backend_overridable }
pgsql.views.date_sql:
class: Drupal\views\Plugin\views\query\PostgresqlDateSql
arguments: ['@database']
public: false
If Drupal is installed on PostgreSQL then pgsql.views.date_sql replaces the views.date_sql service.
In order to facilitate this easy override, services injecting the database service should be tagged as backend_overridable.
The default backend is defined by the container parameter default_backend. Setting it to the empty string disables this feature. If this parameter is not set then the values return by the current database Connection::driver() and Connection::databaseType() methods are used in this order.