Jhipster - Configure multiple datasources - java

I have springBatch App where I was using multiple datasources which I configured as below which is pretty much straight forward. It was working fine.
How to use 2 or more databases with spring?
Now I had to integrate it to Jhipster project. I did similar kind of configuration in application.yml. I removed auto generated Datasource from application.yml and added configurations similar to above post and injected the primary Datasource in DataBaseConfiguration.java which is Jhipster generated class. With this configuration I am unable to do CRUD operation on Database entities form JHipster UI. I am not seeing any errors in logs.
I am not sure what's the right/simple way of configuring multiple datasources in Jhipster project. A sample example utilizing multiple databases would give a good start for me. I didn't find much resources on this.
Below are code sample's for changes I performed to have multiple datasources in JHipster
# ===================================================================
# Spring Boot configuration for the "dev" profile.
#
# This configuration overrides the application.yml file.
#
# More information on profiles: http://www.jhipster.tech/profiles/
# More information on configuration properties: http://www.jhipster.tech/common-application-properties/
# ===================================================================
# ===================================================================
# Standard Spring Boot properties.
# Full reference is available at:
# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
# ===================================================================
spring:
profiles:
active: dev
include: swagger
devtools:
restart:
enabled: true
livereload:
enabled: false # we use gulp + BrowserSync for livereload
jackson:
serialization.indent_output: true
jpa:
database-platform: org.hibernate.dialect.Oracle12cDialect
database: ORACLE
show-sql: true
properties:
hibernate.id.new_generator_mappings: true
hibernate.cache.use_second_level_cache: false
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: true
hibernate.default_schema: ********x
mail:
host: localhost
port: 25
username:
password:
messages:
cache-seconds: 1
thymeleaf:
cache: false
batch:
job:
enabled: false
liquibase:
contexts: dev
# ===================================================================
# To enable SSL, generate a certificate using:
# keytool -genkey -alias ********x-storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
#
# You can also use Let's Encrypt:
# https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm
#
# Then, modify the server.ssl properties so your "server" configuration looks like:
#
# server:
# port: 8443
# ssl:
# key-store: keystore.p12
# key-store-password: <your-password>
# keyStoreType: PKCS12
# keyAlias: ********x
# ===================================================================
server:
port: 8080
# ===================================================================
# JHipster specific properties
#
# Full reference is available at: http://www.jhipster.tech/common-application-properties/
# ===================================================================
jhipster:
http:
version: V_1_1 # To use HTTP/2 you will need SSL support (see above the "server.ssl" configuration)
# CORS is only enabled by default with the "dev" profile, so BrowserSync can access the API
cors:
allowed-origins: "*"
allowed-methods: "*"
allowed-headers: "*"
exposed-headers: "Authorization"
allow-credentials: true
max-age: 1800
security:
authentication:
jwt:
secret: my-secret-token-to-change-in-production
# Token is valid 24 hours
token-validity-in-seconds: 86400
token-validity-in-seconds-for-remember-me: 2592000
mail: # specific JHipster mail property, for standard properties see MailProperties
from: ********x#localhost
base-url: http://127.0.0.1:8080
metrics: # DropWizard Metrics configuration, used by MetricsConfiguration
jmx.enabled: true
graphite: # Use the "graphite" Maven profile to have the Graphite dependencies
enabled: false
host: localhost
port: 2003
prefix: ********x
prometheus: # Use the "prometheus" Maven profile to have the Prometheus dependencies
enabled: false
endpoint: /prometheusMetrics
logs: # Reports Dropwizard metrics in the logs
enabled: false
report-frequency: 60 # in seconds
logging:
logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration
enabled: false
host: localhost
port: 5000
queue-size: 512
# ===================================================================
# Application specific properties
# Add your own application properties here, see the ApplicationProperties class
# to have type-safe configuration, like in the JHipsterProperties above
#
# More documentation is available at:
# http://www.jhipster.tech/common-application-properties/
# ===================================================================
datasource.********x.type: com.zaxxer.hikari.HikariDataSource
datasource.********x.url: "jdbc:oracle:thin:#********x"
datasource.********x.username: ********x
datasource.********x.password: ********x
datasource.********xy.type: com.zaxxer.hikari.HikariDataSource
datasource.********xy.url: "jdbc:oracle:thin:#yyyyyy"
datasource.********xy.username:********x
datasource.********xy.password: "********x"
package com.********x
import io.github.jhipster.config.JHipsterConstants;
import io.github.jhipster.config.liquibase.AsyncSpringLiquibase;
import liquibase.integration.spring.SpringLiquibase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
#Configuration
#EnableJpaRepositories("com.********x")
#EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
#EnableTransactionManagement
public class DatabaseConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
private final Environment env;
public DatabaseConfiguration(Environment env) {
this.env = env;
}
#Autowired
#Qualifier("********x")
private DataSource dataSource;
#Bean
public SpringLiquibase liquibase(#Qualifier("taskExecutor") TaskExecutor taskExecutor
, LiquibaseProperties liquibaseProperties) {
// Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env);
liquibase.setDataSource(dataSource);
liquibase.setChangeLog("classpath:config/liquibase/master.xml");
liquibase.setContexts(liquibaseProperties.getContexts());
liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
liquibase.setShouldRun(false);
} else {
liquibase.setShouldRun(liquibaseProperties.isEnabled());
log.debug("Configuring Liquibase");
}
return liquibase;
}
}
So I injected primary Datasource in DatabaseConfiguration.java and using other datasource where required. Both these datasources are created similar to the above post like how spring suggests.

Here is how I make two datasource work in JHipster project :
The default datasource properties generate by JHipster:
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:h2:file:./target/h2db/db/mockpartenaire;DB_CLOSE_DELAY=-1
username: mockpartenaire
password:
Configs for the JHispter default datasource :
#Configuration
#EnableTransactionManagement
public class PrimaryDbConfig {
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSourceProperties defaultDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSource defaultDataSource() {
return defaultDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean(name = "entityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(defaultDataSource())
.packages(Input.class)
.persistenceUnit("default")
.build();
}
#Bean(name = "transactionManager")
#Primary
public JpaTransactionManager db2TransactionManager(#Qualifier("entityManagerFactory") final EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
The second datasource properties:
partner:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:postgresql://localhost:5432/partner
username: partner
password: partner
driver-class-name: org.postgresql.Driver
The second datasource configs :
#Configuration
#EnableTransactionManagement
#EntityScan(basePackages = "com.my.test.custom.domain")
#EnableJpaRepositories(transactionManagerRef = "partnerTransactionManager", entityManagerFactoryRef = "partnerEntityManagerFactory", basePackages = "com.my.test.custom.repository")
public class PartnerDbConfig {
#Bean
#ConfigurationProperties("partner.datasource")
public DataSourceProperties partnerDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("partner.datasource")
public DataSource partnerDataSource() {
return partnerDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean(name = "partnerEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
LocalContainerEntityManagerFactoryBean emf = builder
.dataSource(partnerDataSource())
.packages(TestPost.class)
.persistenceUnit("partner")
.build();
emf.setJpaProperties(properties);
return emf;
}
#Bean(name = "partnerTransactionManager")
public JpaTransactionManager db2TransactionManager(#Qualifier("partnerEntityManagerFactory") final EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
The default datasource configured by JHipster will continue to work it's entities. For your custom entities using the second datasource, here is the repository configuration :
#SuppressWarnings("unused")
#Repository
#Transactional("partnerTransactionManager")
#PersistenceContext(name = "partnerEntityManagerFactory")
public interface TestPostRepository extends JpaRepository<TestPost,Long>{
}

I found #freemanpolys answer great but it needs an extra property if you want it to work with postGres.
Add the following property to both the default and secondary datasource:
autocommit: false

Related

how to set datasource connection properties in spring boot

I have multiple datasources in spring boot application configured as below :
spring:
application:
name: myapp
main:
allow-bean-definition-overriding: true
datasource-secondary:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:oracle:thin:...
username: ...
password: ...
driver-class-name: oracle.jdbc.OracleDriver
connection-timeout: 20000
maximum-pool-size: 10
pool-name: secondary-pool
datasource-primary:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:postgresql...
username: ...
password: ...
driver-class-name: org.postgresql.Driver
connection-timeout: 20000
maximum-pool-size: 10
pool-name: primary-pool
#EnableTransactionManagement
#Configuration
public class DataSourceConfig {
#Bean
#ConfigurationProperties("spring.datasource-secondary")
public DataSource secondaryDatasource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource-primary")
public DataSource primaryDatasource() {
return DataSourceBuilder.create().build();
}
#PostConstruct
public void setUp() {
System.setProperty("oracle.jdbc.timezoneAsRegion", "false");
System.setProperty("oracle.jdbc.fanEnabled", "false");
}
}
Since I have 1 datasource as oracle , I need to disable oracle.jdbc.timezoneAsRegion properties. Hence I tried to set using postconstruct, however this is not working when I am trying to run image of my application via docker.
I know I can set those vm arguments via docker-compose.yaml, however in uat environment , applications are not run using docker, only image is run from simple java command.
How can I set those vm arguments in spring boot application so that it's image can run without any such failure?
Added here those properties , but still it's not set.

How to refresh app instances using Spring cloud bus with data which isn't controlled by config server?

I'm trying to use Spring cloud bus with Kafka in my microservices application, and indeed I could use it, but only data which is controlled by Spring cloud config server got refreshed!
I'm using jdbc back-end with my config server, and in order to simulate my need, I'm changing some value in properties file in one of my services, beside the properties table, and call the /monintor end point again (mentioned here section 4.3 https://www.baeldung.com/spring-cloud-bus); as a result, only data coming from properties table is changed.
This is the yml file for my Config server
spring:
cloud:
config:
server:
jdbc:
sql: SELECT KEY,VALUE from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
order: 1
stream:
kafka:
binder:
brokers: localhost:9092
datasource:
url: jdbc:mysql://localhost:3306/sweprofile?zeroDateTimeBehavior=convertToNull
username: 123
password: 123ertbnm
hikari:
maximum-pool-size: 10
connection-timeout: 5000
profiles:
active:
- jdbc
application:
name: configServer
These are yml files for One of my Miscroservices and its propeties file respectively
spring:
datasource:
username: 123
password: 123ertbnm
url: jdbc:mysql://localhost:3306/sweprofile?zeroDateTimeBehavior=convertToNull
jpa:
properties:
hibernate:
format_sql: true
ddl-auto: none
application:
name: auth-service
cloud:
config:
discovery:
enabled: true
service-id: configServer
bus:
refresh:
enabled: true
profiles:
active: jdbc
management:
endpoints:
web:
exposure:
include: ["health","info","refresh", "bus-refresh"]
# This line is dummy data for testing purpose
ali.man = " Ola 12333"
This is snapshot from rest controller
#RestController
#RequestMapping("/user")
#RefreshScope
public class AuthController {
private UserAuthService userAuthService;
#Value("${name}")
private String name; // changed normally
// Calling the key value mentioned in properties file after changing
#Value("${ali.man}")
private String k; // -> not changed
public AuthController(UserAuthService userAuthService) {
this.userAuthService = userAuthService;
}
#GetMapping("authTest")
public String getAuth() {
return name + k;
}
}
What did I miss? Why value from Properties file is not changed? hopefully I can use Spring cloud bus with Kafka to refresh these external data.
After some hours of investigation, I found that there is some recommended way. Cloud bus can send Refresh Event and Spring boot has RefreshEvent Listener to that event; this what I build my solution on.
So when event is sent by the bus; all instances will do the same logic ( Refreshing data ) on the loaded in memory configurations.
I used this snippet to apply this
#Configuration
public class ReloadLookupEvent implements ApplicationListener<RefreshScopeRefreshedEvent> {
#Autowired
private CacheService cacheService;
#Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
cacheService.refreshLookUp();
}
}
I could refresh all other configurations on demand, maybe it is a workaround, but acceptable.

Import spring properties from an external file located in the server filesystem

I need to import Spring properties (in Spring Boot) as spring.datasource, server.port... from a file that is located in the file system (out of the java application).
This is for a Spring Boot application that needs to connect to a database.
spring:
datasource:
url: jdbc:oracle:thin:#X.X.X.X:XXXX:XXXX
username: XX
password: XX
driver-class-name: oracle.jdbc.driver.OracleDriver
hikari:
connection-timeout: 60000
maximum-pool-size: 5
application:
name: XX
server:
port: 9000
contextPath: /
servlet:
session:
cookie:
http-only: true
secure: true
By the moment I am not able to import properties from file using #PropertySource(value = "C:/test.properties") in class.
There are multiple ways to achieve this. My preferred one is to annotate your applications main class with #PropertySource and configure it to read your property file.
Example:
#SpringBootApplication
#PropertySource({
"file:C:\test.properties"
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Spring Boot Admin uses HTTP instead of HTTPS Actuator Endpoints

After the registration at the Spring Boot Admin (SBA) Server, some actuators of the clients get adressed with http://springapplication.com/actuator instead of https://springapplication.com/actuator.
Why does it change the endpoints to HTTP and doesn´t stay at HTTPS? Is it customizable?
Here are some Logs and the Java/YML-Files.
Logs:
2018-07-02 06:13:27.683 INFO 3194 --- [-client-epoll-7] d.c.b.a.server.services.StatusUpdater : Couldn't retrieve status for Instance(id=0d47f12b0a94, version=57, registration=Registration(name=springbootapplication-Name, managementUrl=https://springbootapplication.com/actuator, healthUrl=https://springbootapplication.com/actuator/health, serviceUrl=https://springbootapplication.com, source=http-api), registered=true, statusInfo=StatusInfo(status=UP, details={}), statusTimestamp=2018-07-02T05:06:08.423Z, info=Info(values={}), endpoints=Endpoints(endpoints={httptrace=Endpoint(id=httptrace, url=http://springbootapplication.com/actuator/httptrace), flyway=Endpoint(id=flyway, url=http://springbootapplication.com/actuator/flyway), loggers=Endpoint(id=loggers, url=http://springbootapplication.com/actuator/loggers), health=Endpoint(id=health, url=https://springbootapplication.com/actuator/health), env=Endpoint(id=env, url=http://springbootapplication.com/actuator/env), heapdump=Endpoint(id=heapdump, url=http://springbootapplication.com/actuator/heapdump), scheduledtasks=Endpoint(id=scheduledtasks, url=http://springbootapplication.com/actuator/scheduledtasks), mappings=Endpoint(id=mappings, url=http://springbootapplication.com/actuator/mappings), beans=Endpoint(id=beans, url=http://springbootapplication.com/actuator/beans), configprops=Endpoint(id=configprops, url=http://springbootapplication.com/actuator/configprops), threaddump=Endpoint(id=threaddump, url=http://springbootapplication.com/actuator/threaddump), metrics=Endpoint(id=metrics, url=http://springbootapplication.com/actuator/metrics), conditions=Endpoint(id=conditions, url=http://springbootapplication.com/actuator/conditions), auditevents=Endpoint(id=auditevents, url=http://springbootapplication.com/actuator/auditevents), info=Endpoint(id=info, url=http://springbootapplication.com/actuator/info), jolokia=Endpoint(id=jolokia, url=http://springbootapplication.com/actuator/jolokia)}), buildVersion=null)
Application.yml (Server):
server:
port: 5100
spring:
security:
user:
name: admin
password: password
SecuritySecureConfig.java (Server):
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
#Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
http.authorizeRequests().antMatchers(adminContextPath + "/assets/**").permitAll()
.antMatchers(adminContextPath + "/login").permitAll().anyRequest().authenticated().and().formLogin()
.loginPage(adminContextPath + "/login").successHandler(successHandler).and().logout()
.logoutUrl(adminContextPath + "/logout").and().httpBasic().and().csrf().disable();
}
}
SpringBootAdminApplication.java (Server):
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
#EnableAutoConfiguration
#EnableWebSecurity
#EnableAdminServer
#SpringBootApplication(scanBasePackages = "administration")
#PropertySource(value = "META-INF/build-info.properties", ignoreResourceNotFound = true)
public class SpringBootAdminApplication {
private static final Logger log = LoggerFactory.getLogger(SpringBootAdminApplication.class);
public static void main(final String[] args) {
SpringApplication.run(SpringBootAdminApplication.class, args);
}
}
Application.yml (Client):
spring:
application:
name: springapplication
boot:
admin:
client:
username: ${application.security.usernameAdmin}
password: ${application.security.passwordAdmin}
url: "https://springBootAdminServerURL.com"
instance:
service-base-url: https://http://springapplication.com/
metadata:
user.name: ${application.security.usernameAdmin}
user.password: ${application.security.passwordAdmin}
management:
endpoints:
web:
exposure:
include: "*"
application:
security:
usernameAdmin: admin
passwordAdmin: password
I had the same problem. Look at your applications /actuator endpoint. Is it reporting urls as http? It did for me, even if health used https. What solved it for me was adding server.use-forward-headers=true which adds all X-Forwarded-*, including the X-Forwared-Proto that identifies scheme (http/https).
Remember if your app is behind a reverse proxy like NGINX, you'd also need to configure this. Example for NGINX
location / {
proxy_set_header X-Forwarded-Proto $scheme;
...
}
Need correction in the config file for below property which signifies as
Base url for computing the service-url to register with. The path is
inferred at runtime, and appended to the base url.
spring.boot.admin.client.instance.service-base-url
instance:
service-base-url: https://springapplication.com/
In my experience this is usually due to two issues.
Incorrect port configs
Untrusted SSL certs
To fix the first issue, you need to make sure your client application correctly informs Eureka to use the secure port:
eureka:
instance:
nonSecurePortEnable: false
securePortEnabled: true
To fix the second, you need to ensure the SSL cert is trusted by the JVM that is running Spring Boot Admin. Just install your cert into the JRE's cacert file using keytool. I would recommend enabling SSL debug logging while trying to get this to work.
-Djavax.net.debug=SSL
These two steps solved this issue for me.

How to mention persistenceUnitName when packagesToScan property

I have two datasources and two entityManagerFactory instance. I was trying to use the new feature of 3.1 (Bootstrapping JPA entityManagerFactory without persistence.xml by using packagesToScan property).
In order to use the right entity manager factory instance, i have to distinguish using Persistence unit name and defining the PU name in persistence.xml is stopping the spring package scanning feature.
How to give the PU name while using packagesToScan feature?
My question is more duplicate of Is there a way to give persistenceUnitName for Spring's LocalContainerEntityManagerFactoryBean without persistence.xml?
I couldn't find the answer or comment on the above post. So reposting as new question.
Yes you can. Here's an example that uses annotation configuration for Spring
I found it best to organise each datasource into a different package.
My package structure is:
datasource
|__ converters <-- holds any custom attribute converters for JPA
|__ default <-- for default datasource
| |__ model <-- contains entities for default datasource
| |__ repository <-- contains repositories for default datasource
|__ anotherdatasource <-- for second datasource
|__ model <-- contains entities for second datasource
|__ repository <-- contains repositories for second datasource
Pick one of the datasources as the default and create a configuration class for it along the lines of...
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", basePackages = { "com.example.datasource.default.repository" })
public class JpaDefaultDatasourceConfig {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, #Qualifier("dataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.example.datasource.default.model", "com.example.datasource.converters").persistenceUnit("mydefault").build();
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(#Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
Then for each subsequent datasource create another configuration class along the lines of... (Note: the use of packages to separate entity/repository scanning and the naming convention used throughout)
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "anotherEntityManagerFactory", transactionManagerRef = "anotherTransactionManager", basePackages = { "com.example.datasource.anotherdatasource.repository" })
public class JpaAnotherDatasourceConfig {
#Bean(name = "anotherDataSource")
#ConfigurationProperties(prefix = "another.datasource")
public DataSource anotherDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "anotherEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean anotherEntityManagerFactory(EntityManagerFactoryBuilder builder, #Qualifier("anotherDataSource") DataSource anotherDataSource) {
return builder.dataSource(anotherDataSource).packages("com.example.datasource.anotherdatasource.model", "com.example.datasource.converters").persistenceUnit("anotherName").build();
}
#Bean(name = "anotherTransactionManager")
public PlatformTransactionManager anotherTransactionManager(#Qualifier("anotherEntityManagerFactory") EntityManagerFactory anotherEntityManagerFactory) {
return new JpaTransactionManager(anotherEntityManagerFactory);
}
}
You can configure each datasource using the configuration prefix. For the two examples above you could configure them using
application.yml
## JPA configuration
# This is the configuration for default datasource created by spring
spring:
datasource:
url: jdbc:mysql://localhost/default
username: foo
password: bar
driverClassName: com.mysql.jdbc.Driver
test-on-borrow: true
test-while-idle: true
validation-query: select 1;
# maxActive: 1
# This is the configuration for an additional datasource which we will create ourselves
another:
datasource:
url: jdbc:mysql://localhost/another
username: foo
password: bar
driverClassName: com.mysql.jdbc.Driver
test-on-borrow: true
test-while-idle: true
validation-query: select 1;
You don't necessarily need to worry now about the names of the persistence units (although we did name them) because we've carefully separated entity managers to only look at their entities/repositories you can simply inject the applicable repository and use it without having to worry about it getting the wrong datasource. If you do need the persistence unit you can just ask for it by name #PersistenceUnit(name = "anotherDatasource")
If I understand your question correctly, you would like to set the name of the persistenceUnit backing an EntityManagerFactory, when defined without a persistence.xml?
When you declare the entityManagerFactory, there is a persistenceUnitName property that you can set. For example:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="yourPersistenceUnitName"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="packagesToScan">
<list>
<value>..</value>
...
</list>
</property>
</bean>

Categories