Skip to content

Commit

Permalink
HOTFIX v0.3.2 | Fix issues with Transactional and Flushing behaviors …
Browse files Browse the repository at this point in the history
…while using multiple data sources (#25)

* Replaced the use of native entity manager factory from `LocalContainerEntityManagerFactoryBean` with `EntityManagerFactory` Spring Proxy bean while creating `PlatformTransactionManager` bean to ensure that Transactional and Flush behaviour  works as expected across all data sources.

Also made some minor documentation improvement for dealing with hibernate properties with multiple spring data sources.

* Fix documentation
  • Loading branch information
Dhi13man authored Aug 4, 2024
1 parent 86746fc commit 13deed2
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 26 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Releases

## [0.3.2] - 4th August 2024

- **HOTFIX:** Replaced the use of native entity manager factory
from `LocalContainerEntityManagerFactoryBean` with `EntityManagerFactory` Spring Proxy bean
while creating `PlatformTransactionManager` bean to ensure that Transactional and Flush behaviour
works as expected across all data sources.
- This will not lead to any changes in your implementation layer. This is a fix in the generated
configuration layer.
- Some minor documentation improvement for dealing with hibernate properties with multiple spring
data sources.

## [0.3.1] - 13th July 2024

- BREAKING CHANGE: Exact entity packages are now mandatory for each data source. This is to ensure
Expand Down
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,29 +68,29 @@ for configuring multi-data source configurations for a service. Let's break down
- It can be applied to a class (target: `ElementType.TYPE`).

- It has the following attributes:
- `exactEntityPackages`: An array of exact packages to scan for entities. These packages are
- `exactEntityPackages`: An array of exact packages to scan for entities. These packages are
scanned to find the entities related to the data sources.
- `repositoryPackages`: An array of packages to scan for repositories. These packages are
- `repositoryPackages`: An array of packages to scan for repositories. These packages are
scanned to find the repositories related to the data sources.
- `datasourcePropertiesPrefix`: The prefix of the data source properties in the
- `datasourcePropertiesPrefix`: The prefix of the data source properties in the
application properties file. The properties for each data source will be placed under this
prefix followed by the kebab case of the data source name. Eg. When set as `spring.datasource`
for master and readReplica data sources, the properties will be placed under
`spring.datasource.master` and `spring.datasource.read-replica` respectively.
- `generatedConfigPackage`: The package where the generated data source configs will
- `generatedConfigPackage`: The package where the generated data source configs will
be placed. The generated config class with relevant beans will follow a specific naming
format. If this is not specified, the generated config will be placed in the same package as
the class where this annotation is applied, followed by `.generated.config`.
- `generatedRepositoryPackagePrefix`: The prefix of the package where the generated copies
- `generatedRepositoryPackagePrefix`: The prefix of the package where the generated copies
of the repositories will be placed. The generated repositories will follow a specific
naming format. If this is not specified, the generated repositories will be placed in the
same package as the class where this annotation is applied, followed by
`.generated.repositories` and then `.<data_source_name>`.
- `primaryDataSourceConfig`: A `@DataSourceConfig` annotation. This annotation represents
- `primaryDataSourceConfig`: A `@DataSourceConfig` annotation. This annotation represents
the primary data source and its configuration. The primary data source will be able
to access every repository other than the repositories generated for the secondary data
sources.
- `secondaryDataSourceConfigs`: An array of `@DataSourceConfig` annotations. Each annotation
- `secondaryDataSourceConfigs`: An array of `@DataSourceConfig` annotations. Each annotation
represents a data source and its configuration. The secondary data sources will only be able
to access the repositories generated for them.

Expand All @@ -101,12 +101,12 @@ for configuring multi-data source configurations for a service. Let's break down
the `dataSourceConfigs` attribute of `@EnableMultiDataSourceConfig`.

- It has the following attributes:
- `dataSourceName`: The name of the data source. It is used to generate the data source
- `dataSourceName`: The name of the data source. It is used to generate the data source
beans and to name the generated classes, packages, and property paths for the data
source properties.
- `dataSourceClassPropertiesPath`:The application properties key/path of the data source class'
- `dataSourceClassPropertiesPath`:The application properties key/path of the data source class'
properties. Eg. `spring.datasource.hikari` for Hikari data sources.
- `overridingPropertiesPath`: The application properties key/path under which the JPA
- `overridingPropertiesPath`: The application properties key/path under which the JPA
properties to override for this data source are located. This allows overriding of the JPA
properties for each data source. By default, it will take the default `spring.jpa.properties`
path.
Expand All @@ -119,7 +119,7 @@ for configuring multi-data source configurations for a service. Let's break down
- It can be applied to a method (target: `ElementType.METHOD`).

- It has the following attributes:
- `dataSourceName` (or `value`): The name of the data source to use for the repository.
- `dataSourceName` (or `value`): The name of the data source to use for the repository.

Both annotations are available at the source level and are not retained at runtime. They are
intended to be used for generating code for configuring data sources during the build process.
Expand Down Expand Up @@ -246,7 +246,10 @@ intended to be used for generating code for configuring data sources during the
jpa:
# Global JPA Properties
properties:
# Hibernate properties can only be picked from here when using multiple data sources.
hibernate.generate_statistics: false
hibernate.physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
hibernate.implicit_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
```
8. Please always go through the generated code to learn more about what configs to give and what
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -233,5 +233,5 @@
</scm>

<url>http://www.github.com/dhi13man/spring-multi-data-source</url>
<version>0.3.1</version>
<version>0.3.2</version>
</project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.dhi13man.spring.datasource.config;

import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
Expand Down Expand Up @@ -61,11 +62,8 @@ LocalContainerEntityManagerFactoryBean entityManagerFactory(
/**
* Get the transaction manager to be used for the data source.
*
* @param entityManagerFactoryBean The entity manager factory bean, used to create the transaction
* manager
* @param entityManagerFactory The entity manager factory used to create the transaction manager
* @return The transaction manager.
*/
PlatformTransactionManager transactionManager(
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
);
PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ public MultiDataSourceConfigGenerator(
}

/**
* Create the {@link MethodSpec} builder for the {@link java.util.Properties} bean containing JPA
* properties to override.
* Create the {@link MethodSpec} builder for the {@link Properties} bean containing JPA properties
* to override.
*
* @param beanNameFieldSpec the {@link FieldSpec} for this bean name constant
* @param overridingJpaPropertiesPath The key under which the JPA properties to override are
Expand Down Expand Up @@ -533,7 +533,7 @@ public MultiDataSourceConfigGenerator(

// Create the method parameters (EntityManagerFactory dependency)
final ParameterSpec entityManagerFactoryParameter = ParameterSpec
.builder(LocalContainerEntityManagerFactoryBean.class, "entityManagerFactoryBean")
.builder(EntityManagerFactory.class, "entityManagerFactory")
.addAnnotation(qualifierAnnotation)
.build();

Expand All @@ -545,7 +545,7 @@ public MultiDataSourceConfigGenerator(
.returns(PlatformTransactionManager.class)
.addParameter(entityManagerFactoryParameter)
.addStatement(
"return new $T($N.getNativeEntityManagerFactory())",
"return new $T($N)",
JpaTransactionManager.class,
entityManagerFactoryParameter
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -100,13 +101,10 @@ void generateMultiDataSourceConfigTypeElementGetEntityManagerFactory() {

@Test
void generateMultiDataSourceConfigTypeElementGetTransactionManager() {

for (final IMultiDataSourceConfig generatedConfig : generatedConfigs) {
// Arrange
final LocalContainerEntityManagerFactoryBean mockEntityManagerFactory = Mockito
.mock(LocalContainerEntityManagerFactoryBean.class);
Mockito.when(mockEntityManagerFactory.getNativeEntityManagerFactory())
.thenReturn(Mockito.mock());
final EntityManagerFactory mockEntityManagerFactory = Mockito
.mock(EntityManagerFactory.class);

// Act
final PlatformTransactionManager transactionManager = generatedConfig
Expand Down

0 comments on commit 13deed2

Please sign in to comment.