I face the following error after adding a second datasource in my project:
Table 'portal-titan.hibernate_sequence' doesn't exist; error performing isolated work; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: error performing isolated work
It appears when I try to INSERT an object with type, including GenerationType.AUTO. I am a bit confused because there are a lot of questions and discussions for this topic and I tried a lot, but I do not get the desired result. It starts working when I change the GenerationType to IDENTITY, but I read that this can lead to performance issues, which is not the desired result. Something more, I have use-new-id-generator-mappings: false in my hibernate properties in yml file, but this does not help solving the problem, too.
Here it is my yml file:
management:
security:
roles: ADMIN
context-path: /management
spring:
messages:
basename: i18n/messages
mvc:
favicon:
enabled: false
thymeleaf:
mode: XHTML
jpa:
hibernate:
ddl-auto: validate
use-new-id-generator-mappings: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
format-sql: true
physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
caching:
specs:
products:
timeout: 60
orders:
timeout: 60
max: 500
deliveries:
timeout: 120
tracking:
timeout: 1
admins:
timeout: 120
balance:
timeout: 120
application:
async:
core-pool-size: 2
max-pool-size: 50
queue-capacity: 1000
jwt:
token-secret: secret-key
token-validity: PT6H
token-remember-me-validity: P7D
default-language-tag: bg
upload:
allowed-content-types:
- image/jpg
- image/jpeg
- image/png
static-resource:
path: /static/
jobs:
batch-size: 20
activity:
purge:
ttl-value: 90
ttl-unit: days
job-run-interval-value: 1
job-run-interval-unit: days
Here it is how the entity which does now want to insert looks:
#Getter
#Setter
#Entity
#Table(name = "comments")
public class Comment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(nullable = false, unique = true)
private String uuid;
#Column(nullable = false)
private String content;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "delivery_id")
private Delivery delivery;
#CreatedDate
#Column(name = "created_at", nullable = false)
private Instant createdAt = Instant.now();
#LastModifiedDate
#Column(name = "updated_at", nullable = false)
private Instant updatedAt = Instant.now();
}
And this is the method for inserting in the controller part:
#PostMapping("/{deliveryUuid}")
#ApiOperation(value = "Submit a comment")
#ApiResponses(
value = {
#ApiResponse(code = 201, message = "Comment created"),
#ApiResponse(code = 400, message = "Validation failed")
})
#PreAuthorize("hasRole('ROLE_CUSTOMER')")
#ResponseStatus(value = HttpStatus.CREATED)
public void submitComment(
#PathVariable("deliveryUuid") String deliveryUuid,
#Valid #RequestBody CommentDto commentDto,
#CurrentUser AuthUser principal) {
commentService.submitComment(commentDto, deliveryUuid, principal);
}
Because the error starter to appear after I configured second database, I am adding their code too. Comment entity is in the primary database.
Primary:
#Configuration
#EnableTransactionManagement
#EnableJpaAuditing
#EntityScan(basePackageClasses = {TitanClientApp.class})
#EnableJpaRepositories(
entityManagerFactoryRef = "clientEntityManagerFactory",
transactionManagerRef = "clientTransactionManager",
basePackages = { "titan.client" }
)
public class DbConfiguration {
#Primary
#Bean(name="clientDataSource")
#ConfigurationProperties(prefix="spring.datasource.primary")
public DataSource clientDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "clientEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean clientEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("clientDataSource") DataSource clientDataSource) {
return builder
.dataSource(clientDataSource)
.packages("titan.client")
.build();
}
#Primary
#Bean(name = "clientTransactionManager")
public PlatformTransactionManager clientTransactionManager(
#Qualifier("clientEntityManagerFactory") EntityManagerFactory clientEntityManagerFactory) {
return new JpaTransactionManager(clientEntityManagerFactory);
}
}
Secondary:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "gpsEntityManagerFactory",
transactionManagerRef = "gpsTransactionManager",
basePackages = {"titan.gps"}
)
public class SecondaryDbConfiguration {
#Bean(name = "gpsDataSource")
#ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource gpsDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "gpsEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean gpsEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("gpsDataSource") DataSource gpsDataSource) {
return builder
.dataSource(gpsDataSource)
.packages("titan.gps")
.build();
}
#Bean(name = "gpsTransactionManager")
public PlatformTransactionManager gpsTransactionManager(
#Qualifier("gpsEntityManagerFactory") EntityManagerFactory gpsEntityManagerFactory) {
return new JpaTransactionManager(gpsEntityManagerFactory);
}
}
Your second database is simply lacking a table that Hibernate needs to work correctly. You have to create that table if you want to use table based sequences, which is kind of the default.
Using IDENTITY is totally fine though as long as you don't insert thousands of records per second.
Related
I am using Springboot for an app that uses some classes that are managed in another application and stored in another database. My Flight class, which is managed in the current application in a local database, has an attribute of type Aircraft, which is also defined in the current application but is managed in the other application and stored in another database.
The Flight class:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(schema = "app1")
public class Flight implements Serializable {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "flight_sequence"
)
#SequenceGenerator(
name = "flight_sequence",
allocationSize = 1
)
#Column(nullable = false, updatable = false)
private Long id;
private String callsign;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="aircraft_id", nullable=false)
private Aircraft aircraft;
private Date date;
private Operator operator;
private String origin;
private String destination;
}
My Aircraft class:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(schema = "app2")
public class Aircraft implements Serializable {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "aircraft_sequence"
)
#SequenceGenerator(
name = "aircraft_sequence",
allocationSize = 1
)
#Column(nullable = false, updatable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="operator_id", nullable=false)
private Operator operator;
private String registration;
private String acType;
}
I wrote a Jpa query in a FlightRepository which uses as a parameter the registration attribute from the Aircraft attribute of the Flight class:
public interface FlightRepository extends JpaRepository<Flight, Long> {
Flight findFirstByDestinationAndAircraftRegistrationOrderByDateDesc(String destination, String registration);
}
but this results in the following exception:
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne on com.student.application.domain.app1.Flight.aircraft references an unknown entity: com.student.application.domain.app2.Aircraft
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:100)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1750)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1694)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1460)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1494)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 86 more
If I add a #OneToMany annotation to the Aircraft class the problem remains the same. If I remove both the #OneToMany and #ManyToOne annotations, I get a Cannot join to attribute of basic type exception.
These are the configuration classes for the two databases:
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = "com.student.application.repository.app1",
entityManagerFactoryRef = "app1EntityManager",
transactionManagerRef = "app1TransactionManager")
public class App1DBConfiguration {
#Autowired
private Environment env;
#Primary
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource app1DataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean app1EntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(app1DataSource());
em.setPackagesToScan(
"com.student.application.domain.app1");
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("spring.jpa.hibernate.ddl-auto"));
properties.put("hibernate.dialect",
env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.dialect.storage_engine",
env.getProperty("spring.jpa.properties.hibernate.dialect.storage_engine"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public PlatformTransactionManager app1TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
app1EntityManager().getObject());
return transactionManager;
}
}
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = "com.student.application.repository.app2",
entityManagerFactoryRef = "app2EntityManager",
transactionManagerRef = "app2TransactionManager")
public class App2DBConfiguration {
#Autowired
private Environment env;
#Bean
#ConfigurationProperties(prefix = "spring.app2")
public DataSource app2DataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public LocalContainerEntityManagerFactoryBean app2EntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(app2DataSource());
em.setPackagesToScan(
"com.student.application.domain.app2");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
"none");
properties.put("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
properties.put("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public PlatformTransactionManager app2TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
app2EntityManager().getObject());
return transactionManager;
}
}
One flight can have just one Aircraft but one aircraft can have more than one flight... so on aircraft you should have
#OneToMany(mappedBy = "Flight") Join column is not needed here
Im assuming you want it to be mapped by flight and have all the info stored in flight table. you could allso join tables and make flight_aircraft table.
annotations On Flight ->
#ManyToOne
#JoinColumn(name="aircraft_id")
How can I filter my list of OneToMany relationships when fetching the parent entity?
Here's my usecase - I have an H2 database in which I'm tracking Products and their Shipment Options. One Product can have many shipment options. Most consumers care only only about the "best" shipment option per country (chosen by some convoluted business logic), while others want to see the best shipment option per country AND per model-number.
I've solved similar scenarios before using the Spring JPA #Where(clause = "childProperty='staticValue'"), however there are many dynamic models and the where clause seems to only support a single static filter.
Any advice / help would be appreciated, everything I've tried so far has failed.
Here are my domain models:
// In file com.my.company.entity.h2.model.Product.java
#Entity
#Table(name = "Product")
public class Product {
#Id
#Column(length = 10)
private int productId;
#LazyCollection(FALSE)
#OneToMany(cascade = REMOVE)
#NotFound(action = IGNORE)
#JoinColumn(name = "productId", referencedColumnName = "productId", insertable = false, updatable = false)
private List<ProductToPrimaryShipmentOption> primaryShipmentOptions = new ArrayList<>();
}
// In file com.my.company.entity.h2.model.relationships.ProductToPrimaryShipmentOption.java:
#Entity
#Table(name = "ProductToPrimaryShipmentOption")
public class ProductToPrimaryShipmentOption {
#EmbeddedId
private ProductAndShipmentOptionIds id;
#Column(columnDefinition = "CHAR", length = 3)
private String country;
#Column(columnDefinition = "CHAR", length = 80)
private String model;
// This flag indicates this is the best shipment option across all the Product's models.
#Column
private boolean best;
#ManyToOne
#JoinColumn(name = "shipmentOptionId", referencedColumnName = "shipmentOptionId", insertable = false, updatable = false)
private ShipmentOption shipmentOption;
}
// In file com.my.company.entity.h2.model.ShipmentOption.java:
#Entity
#Table(name = "ShipmentOption")
public class ShipmentOption {
#Id
#Column(columnDefinition = "CHAR", length = 29)
private String id; // <= concatenated barcode and country
#Column(columnDefinition = "CHAR", length = 80)
private String model;
// Additional Details...
}
I tried using Hibernate filters, but that didn't work - even when activating them in my current session, any repository queries for Products would give me back every Shipment Option, unfiltered.
// In file com.my.company.entity.h2.model.package-info.java:
#FilterDef(
name = "bestFilter",
parameters = #ParamDef(name = "best", type = "boolean")
)
#FilterDef(
name = "modelFilter",
parameters = #ParamDef(name = "model", type = "string")
)
package com.my.company.entity.h2.model;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;
// In file com.my.company.entity.h2.model.relationships.ProductToPrimaryShipmentOption.java:
#Entity
#Table(name = "ProductToPrimaryShipmentOption")
#Filter(
name = "modelFilter",
condition = "model = :model"
)
#Filter(
name = "bestFilter",
condition = "best = :best"
)
public class ProductToPrimaryShipmentOption {...}
// In class com.my.company.infrastructure.repository.config.H2Config.java:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "h2EntityManagerFactory",
transactionManagerRef = "h2TransactionManager",
basePackages = {"com.my.company.infrastructure.repository.h2"})
public class H2Config {
#Bean(name = "h2DataSource")
#ConfigurationProperties(prefix = "spring.h2-datasource")
public DataSource h2DataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "h2EntityManagerFactory")
public EntityManagerFactory h2EntityManagerFactory(
#Qualifier("h2DataSource") DataSource h2DataSource,
#Value("${h2.hibernate.ddl-auto:create}") String ddlAuto,
#Value("${h2.hibernate.dialect:org.hibernate.dialect.H2Dialect}") String dialect,
#Value("${h2.show-sql:false}") boolean showSql,
#Value("${h2.hibernate.generate-statistics:false}") boolean generateStatistics) {
LocalContainerEntityManagerFactoryBean h2EntityManager = new LocalContainerEntityManagerFactoryBean();
h2EntityManager.setDataSource(h2DataSource);
h2EntityManager.setPersistenceUnitName("h2Unit");
h2EntityManager.setPackagesToScan("com.my.company.entity.h2.model");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(showSql);
h2EntityManager.setJpaVendorAdapter(vendorAdapter);
h2EntityManager.setJpaPropertyMap(new HashMap<>() {{
put("hibernate.ddl-auto", ddlAuto);
put("hibernate.dialect", dialect);
put("hibernate.generate_statistics", generateStatistics);
}});
h2EntityManager.afterPropertiesSet();
return h2EntityManager.getObject();
}
#Bean(name = "h2TransactionManager")
public PlatformTransactionManager h2TransactionManager(#Qualifier("h2EntityManagerFactory") EntityManagerFactory h2EntityManagerFactory) {
JpaTransactionManager h2TransactionManager = new JpaTransactionManager();
h2TransactionManager.setEntityManagerFactory(h2EntityManagerFactory);
return h2TransactionManager;
}
}
// In class com.my.company.infrastructure.repository.service.ProductRepositoryService.java:
#Slf4j
#Repository
public class ProductRepositoryService {
#PersistenceContext(unitName = "h2Unit")
private EntityManager entityManager;
public Flux<Product> findAllProducts() {
return Flux.fromIterable(new JpaTableIterable<>((lastProduct, requestSize) -> {
int id = lastProduct == null ? 0 : lastProduct.getId();
return findNextProducts(id, requestSize);
}, productRepository::count));
}
#Transactional(transactionManager = "h2TransactionManager")
protected List<Product> findNextProducts(int id, int requestSize) {
Session session = entityManager.unwrap(Session.class);
Filter filter = session.enableFilter("bestFilter");
filter.setParameter("best", true);
List<Product> products = productRepository
.findAllByIdGreaterThanOrderByIdAsc(id, PageRequest.of(0, requestSize));
session.disableFilter("bestFilter");
return products;
}
}
I tried using Spring Specifications, but again, I'm simply getting back every relationship, unfiltered :(
// In file com.my.company.infrastructure.repository.h2.ProductRepository.java:
#Repository
#Transactional(transactionManager = "h2TransactionManager")
public interface ProductRepository extends JpaRepository<Product, Integer>, JpaSpecificationExecutor<Product> {
//...
}
// In file com.my.company.entity.h2.model.Product_.java:
#StaticMetamodel(Product.class)
public class Product_ {
public static volatile SingularAttribute<Product, Integer> productId;
public static volatile ListAttribute<Product, ProductToPrimaryShipmentOption> primaryShipmentOptions;
}
// In file com.my.company.entity.h2.model.specification.Specifications.java:
public class Specifications {
public static Specification<Product> nextProducts(int lastId) {
return (root, query, builder) -> {
Join<Product, ProductToPrimaryShipmentOption> join = root.join(Product_.primaryPackages, JoinType.LEFT);
return builder.and(
builder.greaterThan(root.get(Product_.id), lastId),
builder.equal(join.get("best"), true);
};
}
}
// In file com.my.company.infrastructure.repository.service.ProductRepositoryService.java:
#Slf4j
#Repository
public class ProductRepositoryService {
#Transactional(transactionManager = "h2TransactionManager")
protected List<Product> findNextProducts(int id, int requestSize) {
return productRepository
.findAll(nextProducts(id), PageRequest.of(0, requestSize))
.getContent();
}
}
UPDATE:
Yet another attempt that failed was using the Hibernate #FilterJoinTable annotation. Still, I see the HQL queries printing in the logs without the filter clause and the collection contains all the unfiltered results.
Here's what I tried:
// In file com.my.company.entity.h2.model.Product.java
#Entity
#Table(name = "Product")
public class Product {
#Id
#Column(length = 10)
private int productId;
#LazyCollection(FALSE)
#ManyToMany(cascade = REMOVE)
#NotFound(action = IGNORE)
#JoinTable(name = "ProductToPrimaryShipmentOption",
joinColumns = #JoinColumn(name = "productId", insertable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "shipmentOptionId", insertable = false, updatable = false)
)
#FilterJoinTable(
name = "bestFilter",
condition = "best = :best"
)
private List<ShipmentOption> filteredShipmentOptions = new ArrayList<>();
}
My table(tbl_branch_type) exists in my database. Every other column is there, but I receive this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/example/local/config/LocalDbConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unable to create unique key constraint (code, bank_type_id) on table tbl_branch_type: database column 'bank_type_id' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
My BranchType entity is:
#Entity
#Table(
name = "tbl_branch_type",
uniqueConstraints = {
#UniqueConstraint(
name = "uc_branch_type_bank_id_branch_code",
columnNames = {"code", "bank_type_id"})
})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Getter
#Setter
#EqualsAndHashCode(
callSuper = true,
exclude = {"bankType"})
#ToString(exclude = {"bankType"})
public class BranchType extends Auditing implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_branch_type")
#SequenceGenerator(sequenceName = "seq_branch_type", allocationSize = 1, name = "seq_branch_type")
private Long id;
#NotNull
#Size(min = 1, max = 20)
#Column(name = "code", length = 20, nullable = false)
private String code;
#NotNull
#Size(min = 1, max = 100)
#Column(name = "name", length = 100, nullable = false)
private String name;
#JsonIgnore
#ManyToOne
#JsonIgnoreProperties("")
private BankType bankType;
}
My LocalDbConfiguration class is:
#Configuration
#PropertySource({"classpath:application.yml"})
#EnableJpaRepositories(
basePackages = {"com.example.local.model.dao", "com.example.local.core.auth.repository"})
#EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class LocalDbConfiguration {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("dataSource") DataSource dataSource) {
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("database.platform", "org.hibernate.dialect.Oracle10gDialect");
return builder
.dataSource(dataSource)
.packages(
"com.example.local.model.entity",
"com.example.local.model.mapper",
"com.example.local.core.auth.domain")
.persistenceUnit("localPU")
.properties(properties)
.build();
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.hikari")
public HikariConfig defaultHikariConfig() {
return new HikariConfig();
}
#Bean
AuditorAware<Long> auditorProvider() {
return new AuditorProviderAware();
}
}
I believe this is the root cause of your problem: database column 'bank_type_id' not found. Try to create that column
I have solved my problem by adding this codes for entityManagerFactory in LocalDbConfiguration.class
properties.put(
"hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
properties.put(
"hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
I am using hibernate, spring boot, jpa
First DB is MS SQL. New requirement is to connect Oracle JDBC
It is multi module application. In main module i have application-remote.yml file with DB credentials. Here it is
spring:
datasource:
driver-class-name:com.microsoft.sqlserver.jdbc.SQLServerDriver
url: ************
username: *****
password: *****
secondDatasource:
driver-class-name: oracle.jdbc.OracleDriver
url: ***********
username: ******
password: ******
jpa:
hibernate:
ddl-auto: none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
show-sql: true
properties:
dialect: org.hibernate.dialect.SQLServer2012Dialect
jackson:
date-format: com.fasterxml.jackson.databind.util.StdDateFormat
logging:
config: classpath:logback-remote.xml
file: /usr/share/tomcat/pqa.log
My Application config in module app, com.my.project
#Configuration
#Import({
ControllerConfig.class,
PersistenceConfig.class
})
public class ApplicationConfig {
}
My persistenceConfig in module persistence com.my.project
#Configuration
public class PersistenceConfig {
#Bean
#Primary
#ConfigurationProperties(prefix="spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#ConfigurationProperties(prefix="spring.secondDatasource")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
I have many entities in persistence com.my.project.entity
One of them is
#Data
#Entity
#Builder
#Table(name = "locationSelection", schema = "dbo")
public class Location {
#Id
#Column(name = "timerName")
private String timerName;
#Column(name = "center")
private String center;
#Column(name = "station")
private String station;
#Column(name = "cell")
private String cell;
#Column(name = "place")
private String place;
}
Repository for it in Persistence, com.my.project.repository
#Repository
public interface LocationRepository extends JpaRepository<Location, String> {}
And for 2nd databe in Persistence com.my.project.entityForIntegration
#Data
#Builder
#Entity
#Table(name = "PQA_IN")
public class Pqa_In {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
#Column(name = "STATUS")
private String status;
#Column(name = "UPD_USER")
private String upd_user;
#Column(name = "UPD_DATE")
private Timestamp upd_date;
#Column(name = "INS_USER")
private String ins_user;
#Column(name = "INS_DATE")
private Timestamp ins_date;
}
And repository in com.my.project.repositoryForIntegration
public interface Pqa_In_repository extends JpaRepository<Pqa_In, Long> {
}
Now this is doesnt work. I have a lot of erros, with the classes and configs above the error is
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.my.project.services.impl.AnomaliesServiceImpl required a bean of type 'com.my.project.repository.AnomaliesRepository' that could not be found.
Action:
Consider defining a bean of type 'com.my.project.repository.AnomaliesRepository' in your configuration.
I have read Spring documentation, baeldung, stackoverflow and other sites with guides and questions about multiple datasources, but i cant do nothing.
Please, provide me the correct solution to connect 2 DBs.
AnomaliesServiceImpl
#Service
#Slf4j
public class AnomaliesServiceImpl implements AnomaliesService {
private AnomaliesRepository anomaliesRepository;
#Autowired
public AnomaliesServiceImpl(AnomaliesRepository anomaliesRepository) {
//
this.anomaliesRepository = anomaliesRepository;
}
#Override
public ResponseEntityDTO getAllAnomalies(int currentPageNumber, int pageSize) {
Page<WeldMeasureProt> page = anomaliesRepository.findAllAnomalies(pageable);
return convertToWeldMeasureProtDTO(page, currentPageNumber);
}
AnomaliesRepository
#Repository
public interface AnomaliesRepository extends PagingAndSortingRepository<WeldMeasureProt, WeldMeasurePointPrimaryKey> {
#Query("from WeldMeasureProt wm where wm.detection<>0 " +
"and wm.uirQStoppActCntValue=0 " +
"and wm.monitorState=0 ")
Page<WeldMeasureProt> findAllAnomalies(Pageable pageable);
}
I am having some difficulties trying to use a secondary data source in my Spring Boot application.
In my application class, I define both data sources:
#Bean #Primary #ConfigurationProperties(prefix = "spring.datasource")
public DataSource defaultDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "db2") #ConfigurationProperties(prefix = "myapp.db2")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
Setting the default data source this way works, and all entities are associated to the default database with no extra configuration. The problem comes when trying to consume entities that should be associated with the second data source, as Spring thinks these belong as well to the default data source.
I am trying to use the #Table/schema attribute with the same value as the #Bean/name defined in the application class, but it doesn't work. The error I keep getting is Table 'db1.mytable' doesn't exist, which is wrong since mytable belongs to the database db2.
Here is a brief example of such entity:
#Data #Entity #Table(name = "mytable", schema = "db2")
public class MyTable {
#Id #Column(name = "id", nullable = false, unique = true)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "foo", nullable = false)
private String foo;
}
What am I missing?