Data Stores
A data store represents a database or any other source of data in your application.
Jmix core subsystem provides JpaDataStore which stores JPA entities in a relational database. This is the main persistence mechanism in Jmix applications, and when we mention a data store in this manual, we mean the JPA data store if not explicitly stated otherwise.
The REST DataStore add-on provides RestDataStore which works with DTO entities mapped to the REST API exposed by a remote Jmix application. The REST data store has some limitations compared to the JPA data store.
Supported Databases
The following databases are supported in Jmix out-of-the-box:
- 
HSQLDB (Java in-memory database) 
- 
PostgreSQL 
- 
MySQL 5.1+ 
- 
MariaDB 
- 
Microsoft SQL Server 2008+ 
- 
Oracle 
The data store editor in Studio automatically configures connection properties and adds an appropriate JDBC driver to the list of dependencies in build.gradle.
| When using MariaDB with Jmix 2.4 - 2.6, downgrade Liquibase by adding the following code to your  See issue #3888 for more information. | 
If you need to connect a relational database not supported in Jmix out-of-the-box, follow instructions in the Studio: Connecting to Unsupported Databases section.
A non-relational database can be used by creating a custom data store or directly as described in the MongoDB Integration in Jmix guide.
Main Store
When you create a new Jmix project in Studio, it has a single data store called main that connects to a relational database. The connection parameters are specified in the following application properties:
main.datasource.url = jdbc:hsqldb:file:.jmix/hsqldb/demo
main.datasource.username = sa
main.datasource.password =
main.liquibase.change-log = com/company/demo/liquibase/changelog.xml| Use Studio data store management features to define database connection properties for a data store. | 
The main application class contains a corresponding JDBC DataSource bean declaration:
@Bean
@Primary
@ConfigurationProperties("main.datasource")
DataSourceProperties dataSourceProperties() {
    return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("main.datasource.hikari")
DataSource dataSource(final DataSourceProperties dataSourceProperties) {
    return dataSourceProperties.initializeDataSourceBuilder().build();
}All JPA entities by default are associated with the main data store.
Additional Stores
In order to work with multiple databases, you need additional data stores.
| Use Studio data store management features to define additional data stores. | 
Each additional store has a unique name, which is specified in the comma-separated list of the jmix.core.additional-stores application property. Parameters of the database connection have the store name as a prefix. In the examples below, the locations additional store is configured:
jmix.core.additional-stores = locations,inmem
locations.datasource.url = jdbc:hsqldb:file:.jmix/hsqldb/locations
locations.datasource.username = sa
locations.datasource.password =
locations.liquibase.change-log = com/company/demo/liquibase/locations-changelog.xmlFor each additional store, Studio creates a Spring configuration class and defines the JDBC DataSource and other related beans in it:
@Configuration
public class LocationsStoreConfiguration {
    @Bean
    @ConfigurationProperties("locations.datasource")
    DataSourceProperties locationsDataSourceProperties() {
        return new DataSourceProperties();
    }
    @Bean
    @ConfigurationProperties(prefix = "locations.datasource.hikari")
    DataSource locationsDataSource(@Qualifier("locationsDataSourceProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }
    @Bean
    LocalContainerEntityManagerFactoryBean locationsEntityManagerFactory(
            @Qualifier("locationsDataSource") DataSource dataSource,
            JpaVendorAdapter jpaVendorAdapter,
            DbmsSpecifics dbmsSpecifics,
            JmixModules jmixModules,
            Resources resources
    ) {
        return new JmixEntityManagerFactoryBean("locations", dataSource, jpaVendorAdapter, dbmsSpecifics, jmixModules, resources);
    }
    @Bean
    JpaTransactionManager locationsTransactionManager(@Qualifier("locationsEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JmixTransactionManager("locations", entityManagerFactory);
    }
    @Bean("locationsLiquibaseProperties")
    @ConfigurationProperties(prefix = "locations.liquibase")
    public LiquibaseProperties locationsLiquibaseProperties() {
        return new LiquibaseProperties();
    }
    @Bean("locationsLiquibase")
    public SpringLiquibase locationsLiquibase(@Qualifier("locationsDataSource") DataSource dataSource,
                                              @Qualifier("locationsLiquibaseProperties") LiquibaseProperties liquibaseProperties) {
        return JmixLiquibaseCreator.create(dataSource, liquibaseProperties);
    }
}To associate an entity with an additional data store, use the @Store annotation on the entity class:
@Store(name = "locations")
@JmixEntity
@Table(name = "COUNTRY")
@Entity
public class Country {| Studio adds @Storeannotation when you select an additional data store for the entity in the entity designer. | 
In the example above, the Country entity will be stored in the database connected as the locations data store.
Custom Data Store
A custom data store may help you to work with some DTO entities in the same way as with JPA entities - by using DataManager. If your DTO entity is associated with a custom store, DataManager will delegate its CRUD operations to your data store and use it when resolving references to your DTOs from other entities.
Let’s consider the process of creating a custom data store. Imagine a transient Metric entity and an in-memory store for it.
- 
Create a class that implements the DataStoreinterface. The class must be a Spring prototype bean. The example below contains a primitive implementation that is capable of storing entities of different types in memory.@Component @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class InMemoryStore implements DataStore { // ... }
- 
Create a class that implements the StoreDescriptorinterface. It must be a Spring singleton bean, and itsgetBeanName()method must return the name of the data store implementation bean created on the previous step:@Component public class InMemoryStoreDescriptor implements StoreDescriptor { @Override public String getBeanName() { return "inMemoryStore"; } @Override public boolean isJpa() { return false; } }
- 
Add the data store name ( inmemin this case) to thejmix.core.additionalStoresproperty:jmix.core.additional-stores = locations,inmem
- 
Set the StoreDescriptorbean name in thejmix.core.store-descriptor-<store_name>property:jmix.core.store-descriptor-inmem = inMemoryStoreDescriptor
- 
Add @Storeannotation to the entity:@Store(name = "inmem") (1) @JmixEntity(annotatedPropertiesOnly = true) (2) public class Metric {1 The @Storeannotation specifies a custom data store.2 See @JmixEntity description for more details. 
- 
Now you can save and load the entity using DataManagerand it will delegate the CRUD operations to your custom data store:Metric metric = dataManager.create(Metric.class); metric.setName("test"); metric.setValue(10.0); dataManager.save(metric); Metric metric1 = dataManager.load(Id.of(metric)).one();Also, if another entity has a reference to Metric, theMetricinstance will be loaded automatically when accessing the reference attribute.