I am using "Spring-boot + Hibernate4 + mysql" for my application. As part of which I have a requirement where my sprint-boot app should be able to start even when database is down. Currently it gives the below exception when I try to start my spring boot app without DB being up.
I researched a lot and found out that this exception has to do with hibernate.temp.use_jdbc_metadata_defaults property.
I tried setting this in "application.yml" of spring boot but this property's value is not being reflected at runtime.
Exception Stack Trace:
2014-05-25 04:09:43.193 INFO 59755 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {4.0.4.Final}
2014-05-25 04:09:43.250 WARN 59755 --- [ main] o.h.e.jdbc.internal.JdbcServicesImpl : HHH000342: Could not obtain connection to query metadata : Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
2014-05-25 04:09:43.263 INFO 59755 --- [ main] o.apache.catalina.core.StandardService : Stopping service Tomcat
Error starting ApplicationContext. To display the auto-configuration report enabled debug logging (start with --debug)
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:973)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:750)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
at admin.Application.main(Application.java:36)
Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:104)
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:71)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:205)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:89)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:206)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:178)
at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1885)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1843)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:399)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:150)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
... 15 more
application.yml:
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: none
naming_strategy: org.hibernate.cfg.DefaultNamingStrategy
temp:
use_jdbc_metadata_defaults: false
It was indeed a tough nut to crack.
After lot and lot of research and actually debugging the spring-boot, spring, hibernate, tomcat pool, etc to get it done.
I do think that it will save lot of time for people trying to achieve this type of requirement.
Below are the settings required to achieve the following requirement
Spring boot apps will start fine even if DB is down or there is no DB.
Apps will pick up the connections on the fly as DB comes up which means there is no need to restart the web server or redeploy the apps.
There is no need to start the tomcat or redeploy the apps, if DB goes down from running state and comes up again.
application.yml :
spring:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/schema
username: root
password: root
continueOnError: true
initialize: false
initialSize: 0
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 5000
minIdle: 0
jpa:
show-sql: true
hibernate:
ddl-auto: none
naming_strategy: org.hibernate.cfg.DefaultNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
hbm2ddl:
auto: none
temp:
use_jdbc_metadata_defaults: false
I am answering here and will close the issue that you have cross-posted
Any "native" property of the JPA implementation (Hibernate) can be set using the spring.jpa.properties prefix as explained here
I haven't looked much further in the actual issue here but to answer this particular question, you can set that hibernate key as follows
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults
Adding this alone worked for me:
spring.jpa.properties.hibernate.dialect: org.hibernate.dialect.Oracle10gDialect
Just replace the last part with your database dialect.
The solution is really useful for me. Thanks
i used file "application.properties" includes following lines:
app.sqlhost=192.168.10.11
app.sqlport=3306
app.sqldatabase=logs
spring.main.web-application-type=none
# Datasource
spring.datasource.url=jdbc:mysql://${app.sqlhost}:${app.sqlport}/${app.sqldatabase}
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.hbm2dll.auto = none
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
spring.datasource.continue-on-error=true
spring.datasource.initialization-mode=never
spring.datasource.hikari.connection-timeout=5000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.initialization-fail-timeout= -1
spring.jpa.hibernate.use-new-id-generator-mappings=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.output.ansi.enabled=always
But, you can not use #Transactional annotation at class level
#Service
//#Transactional //do not use to touch the Repository
#EnableAsync
#Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class LogService {
.... }
#Async
#Transactional // you can use at function level
public void deleteLogs(){
logRepository.deleteAllBy ...
}
Add following config should be work:
spring.jpa.database-platform: org.hibernate.dialect.MySQL5Dialect
Related
I have followed multiple articles on creating multiple data sources and tried the same in my code. But strangely spring boot in only initializing one data source and not the other. When I remove any one of them from the code, the other is created without any issues. Any idea.
Bean Configuration -
#Configuration
public class DBConfiguration {
#Bean("dataSource")
#ConfigurationProperties(prefix = "p.datasource")
public DataSource pDataSource() {
System.out.println("**************************> dataSource");
return DataSourceBuilder.create().build();
}
#Bean("storeFrontDataSource")
#ConfigurationProperties(prefix = "c.datasource")
public DataSource cDataSource() {
System.out.println("**************************> storeFrontDataSource");
return DataSourceBuilder.create().build();
}
}
YML File (removed some data for confidentiality) -
p:
datasource:
url: {some-url}
driver-class-name: com.ibm.db2.jcc.DB2Driver
username: abc
password: xyz
type: com.zaxxer.hikari.HikariDataSource
hikari:
schema:
connection-init-sql: select 1 from dual
minimum-idle: 25
maximum-pool-size: 100
idle-timeout: 10_000
max-lifetime: 20_000
connection-timeout: 1_000
validation-timeout: 500
c:
datasource:
url: {some-url}
driver-class-name: com.ibm.db2.jcc.DB2Driver
username: abc
password: xyz
type: com.zaxxer.hikari.HikariDataSource
hikari:
schema:
pool-name: uspo-cis-sf-pool
connection-init-sql: select 1 from dual
minimum-idle: 1
maximum-pool-size: 5
idle-timeout: 10_000
max-lifetime: 50_000
connection-timeout: 2_000
validation-timeout: 500
Error thrown -
Only the "datasource" bean is found and not the "storeFrontDataSource" bean. Even on the console only one of System.out.println() is called (i.e. for "datasource") while other is not printed. SpringBoot is not even initializing the other bean definition.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zaxxer.hikari.HikariDataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value=storeFrontDataSource)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.3.jar:5.3.3]
... 38 common frames omitted
Note - Even defining #Primary doesn't helps. Both System.out.println() should be printed to console regardless.
As per the advise #tgdavies, I found some of the classes from the dependent libraries were injecting 'HikariDataSource' instead of 'DataSource'. After fixing them the issue got resolved.
You need to create customer configuration class for create multiple datosource and you define primary datasource.
Check this example from baeldung
I am trying to integrate the Elastic Driver "org.elasticsearch.xpack.sql.jdbc.EsDriver" from
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>x-pack-sql-jdbc</artifactId>
<version>7.10.0</version>
</dependency>
into my spring boot app using Hibernate.
In my spring configuration bean I have the following:
#Bean
#ConfigurationProperties(prefix = "db.elastic")
#Qualifier("elasticDataSource")
#Primary
public DataSource elasticDataSource() {
return DataSourceBuilder.create()
.build();
}
public LocalContainerEntityManagerFactoryBean elasticEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Map<String, Object> properties = new HashMap<>();
properties.put(AvailableSettings.HBM2DDL_AUTO, "none");
properties.put(AvailableSettings.HBM2DLL_CREATE_SCHEMAS, "false");
properties.put(AvailableSettings.DIALECT, org.elasticsearch.xpack.sql.jdbc.EsDriver.class.getName());
return builder
.dataSource(elasticDataSource())
.packages(Issuer.class)
.persistenceUnit("elastic")
.properties(properties)
.build();
}
However, when I run this code I get the following exception:
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:275)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:179)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:119)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
... 16 common frames omitted
Caused by: org.hibernate.HibernateException: Unable to construct requested dialect [org.elasticsearch.xpack.sql.jdbc.EsDriver]
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.constructDialect(DialectFactoryImpl.java:84)
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:51)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:137)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:94)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
... 33 common frames omitted
Caused by: java.lang.ClassCastException: org.elasticsearch.xpack.sql.jdbc.EsDriver cannot be cast to org.hibernate.dialect.Dialect
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.constructDialect(DialectFactoryImpl.java:74)
... 38 common frames omitted
I assume this is because the driver isn't compatible with hibernate. Am I correct or is there some other configuration that must be done to work around the problem?
There is also a commercially available JDBC driver here: https://www.cdata.com/drivers/elasticsearch/jdbc/
Has anyone got any experience with this driver and it's compatibility with Hibernate?
I have no knowledge of ElasticSearch driver, however I will tell you why you are getting the error.
Your error is:Caused by: java.lang.ClassCastException: org.elasticsearch.xpack.sql.jdbc.EsDriver cannot be cast to org.hibernate.dialect.Dialect
This is because you have a problem in your properties:
properties.put(AvailableSettings.DIALECT, org.elasticsearch.xpack.sql.jdbc.EsDriver.class.getName());
EsDrver.class.getName() is not a Hibernate Dialect.
An example hibernate dialect is: org.hibernate.dialect.MySQL5Dialect
Kindly read https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-jdbc.html
Seeing that you are using Springboot, you might not even have to manually configure the datasource/entitymanager. Simply adding the dependency will autoconfigure it.
There is no dialect for the ElasticSearch SQL dialect, but you can try using org.hibernate.dialect.SQLServerDialect like suggested in https://www.cdata.com/kb/tech/elasticsearch-jdbc-hibernate.rst
In the end, you will probably have to override a few configs in the dialect to fit the SQL dialect that is supported by ES.
So I've found that org.hibernate.dialect.H2Dialect or org.hibernate.dialect.PostgreSQL9Dialect work, but only up to a point.
Firstly you must also include double quotes in entity names:
#Data
#Table(name = "\"mytable\"")
#Entity
public class MyTable {
}
Furthermore I've found that setting maxRows doesn't work. For some reason this value isn't bound to limit in the generated Sql:
18:14:29.320 [http-nio-8081-exec-1] DEBUG org.hibernate.SQL -
select
mytabl_.NAME as col_0_0_
from
"mytable" mytabl_
order by
mytabl_.NAME asc limit ?
18:14:29.651 [http-nio-8081-exec-1] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 0, SQLState: null
18:14:29.651 [http-nio-8081-exec-1] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - line 1:108: mismatched input '?' expecting {'ALL', INTEGER_VALUE}
18:14:29.658 [http-nio-8081-exec-1] WARN g.e.SimpleDataFetcherExceptionHandler - Exception while fetching data (/Issuers) : line 1:108: mismatched input '?' expecting {'ALL', INTEGER_VALUE}
org.hibernate.JDBCException: line 1:108: mismatched input '?' expecting {'ALL', INTEGER_VALUE}
Anyone have any ideas as to why this might be?
I need some help trying to debug why the transaction management of my spring boot app is not working.
The basic idea is that I have 2 tables I would like to write something in. When anything goes wrong in one of the 2 tables, the transaction should be rolled back and nothing should be written to the database.
Here is a simplified version of the code:
#Transactional
public void archiveTask(String taskId) {
OffloadedRun run = new OffloadedRun();
run.setStartDateTime(LocalDateTime.now());
calculationRunRepository.save(run);
List<SingleContractCalculationResults> activeResults = contractCalculationResultAccessService.get(taskId);
for (SingleContractCalculationResults result : example) {
for (Map.Entry<String, ContractResults> entry : result.getResultsPerScenario().entrySet()) {
String scenario = entry.getKey();
ContractResults results = entry.getValue();
OffloadedCalculationResult offloadedCalculationResult = new OffloadedCalculationResult();
// offloadedCalculationResult.setOffloadedRun(run);
offloadedCalculationResult.setContractId(result.getContractId());
calculationResultRepository.save(offloadedCalculationResult);
}
}
}
The classes that I execute the save methods on are Spring Data JPA repositories that are defined like this:
public interface CalculationRunRepository extends JpaRepository<OffloadedRun, String> {
}
the line I commented out is a mandatory column. I do this to enforce a ConstraintViolationException to test what happens on an exception when saving something in the second table.
What happens is that the first entity is saved successfully, which should not have happened. I'm trying to figure out why this is.
My spring boot application is configured with #EnableTransactionManagement to enable the #Transactional annotations in my own services (like this one).
I changed the logging level for org.springframework.transaction.interceptor to TRACE to see what's going on:
o.s.t.i.TransactionInterceptor : Getting transaction for [be.sodemo.calculator.offloading.TaskArchiverImpl.archiveTask]
o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
o.s.t.i.TransactionInterceptor : Completing transaction for [be.sodemo.calculator.offloading.TaskArchiverImpl.archiveTask]
o.h.e.j.s.SqlExceptionHelper : SQL Error: 1048, SQLState: 23000
o.h.e.j.s.SqlExceptionHelper : Column 'run_id' cannot be null
o.h.e.j.b.i.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'run_id' cannot be null
at sun.reflect.GeneratedConstructorAccessor2599.newInstance(Unknown Source) ~[?:?]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java) ~[?:1.8.0_102]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[?:1.8.0_102]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.40.jar:5.1.40]
After this
I'm not sure what the logging would look like if transaction management works properly but it looks like it's completing every transaction.
Does anyone have an idea what I can try next to see what's going wrong?
Edit: Until now I have been using a MySQL database. I noticed that when I tested this exact same code on a H2 database, it seems like the rollback works as intended. The only difference I see with that is that it throws another vendor-specific exception.
I've tried explicitly setting the rollbackFor attribute on the #Transactional annotation like so:
#Transactional(rollbackFor = {Exception.class, MySQLIntegrityConstraintViolationException.class})
But even that didn't cause a rollback.
Edit:
These are my spring boot settings related to JPA/Hibernate:
spring:
jpa:
hibernate:
ddl-auto: none
dialect: org.hibernate.dialect.MySQL5Dialect
database: mysql
properties:
hibernate:
order_inserts: true
jdbc:
batch_size: 50
datasource:
url: jdbc:mysql://localhost/local-test-db
driver-class-name: com.mysql.jdbc.Driver
I am not sure why you are using String for your id type in repository <OffloadedRun, String>. Your OffloadedRun domain has id with String type? It should match with type of your id field in OffloadedRun domain. Make sure for the case. To confirm,
Could you please post your OffloadedRun domain code also?
You have to use org.springframework.orm.hibernate4.HibernateTransactionManager.
You might be using org.springframework.orm.jpa.JpaTransactionManager.
Please verify whether you are using single dataSource or multiple dataSources in your application.
If you are using single dataSource then #Transactional will pick that single dataSource by default else it will pick any one from multiple dataSources and this kind of untraceable issue occurs.
Please have a look at
#Transaction annotation with different data sources
I have resolved the issue using
/* This code is present in #Configuration class */
#Bean(name = "postgresDataSource")
DataSource postgresDataSource(){
// DataSource configuration code
}
#Bean(name = "postgresTransactionManager")
public PlatformTransactionManager transactionManager(#Qualifier("postgresDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/* This code is present in #Service class */
#Override
#Transactional("postgresTransactionManager")
public void save(Map queueMsg) {
// Transaction specific code
}
I want to use Envers in my project. The hardest part is to create audit tables. The database structure is created by flyway migrations. Therefore hibernate.hbm2ddl.auto = validate. According to the documentation I should use org.hibernate.envers.tools.hbm2ddl.EnversSchemaGenerator to create schema programmatically. But I didn't find any examples how to do it.
I created flyway migrations for audit tables. However seems like envers can't find them during the start for dev conf. Test conf works just fine. Here is my application.yml for dev:
spring.datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/server?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&connectionCollation=utf8&characterSetResults=UTF-8
username: root
spring.jpa:
database: MYSQL
show-sql: true
hibernate:
ddl-auto: validate
dialect: org.hibernate.dialect.MySQL5Dialect
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties.org.hibernate.envers:
default_schema: server_audit
audit_table_suffix: _history
and Test:
spring:
profiles: test
spring.datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:test;MODE=MySQL;INIT=CREATE SCHEMA IF NOT EXISTS \"public\"\;CREATE SCHEMA IF NOT EXISTS \"SERVER_AUDIT\"
spring.jpa:
database: H2
show-sql: true
hibernate:
ddl-auto: validate
dialect: org.hibernate.dialect.H2Dialect
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
During the start there is an exception:
java.sql.DatabaseMetaData : HHH000262: Table not found: accounts_history
[lication.main()] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Missing table: accounts_history
Then I changed hbm2ddl.auto = update the output is weird:
java.sql.DatabaseMetaData : HHH000262: Table not found: accounts_history
org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000388: Unsuccessful: create table server_audit.accounts_history
org.hibernate.tool.hbm2ddl.SchemaUpdate : Table 'accounts_history' already exists
and it starts.
UPDATE
Can anyone provide example how to create audit tables using
org.hibernate.envers.tools.hbm2ddl.EnversSchemaGenerator
?
I am tired of banging my head around this problem So if anyone could suggest me where I am wrong I'll be grateful.
The problem is I am using Spring-Batch and Hibernate Full-Text Search in my Spring MVC project.So from the batch job Tasklet I am calling following code:
A a=aDao.merge(a);
b.setA(a);
bDao.save(b);
While doing the save update on these entites I am getting an exception and the stacktrace is as follows:
org.springframework.orm.hibernate3.HibernateSystemException: Error while indexing in Hibernate Search (before transaction completion); nested exception is org.hibernate.HibernateException: Error while indexing in Hibernate Search (before transaction completion)
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:690)
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:147)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.hibernate.HibernateException: Error while indexing in Hibernate Search (before transaction completion)
at org.hibernate.search.backend.impl.EventSourceTransactionContext$DelegateToSynchronizationOnBeforeTx.doBeforeTransactionCompletion(EventSourceTransactionContext.java:175)
at org.hibernate.engine.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:543)
at org.hibernate.engine.ActionQueue.beforeTransactionCompletion(ActionQueue.java:216)
at org.hibernate.impl.SessionImpl.beforeTransactionCompletion(SessionImpl.java:571)
at org.hibernate.jdbc.JDBCContext.beforeTransactionCompletion(JDBCContext.java:250)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:138)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
... 21 more
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.search.util.HibernateHelper.unproxy(HibernateHelper.java:62)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.buildDocumentFields(DocumentBuilderIndexedEntity.java:394)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.buildDocumentFields(DocumentBuilderIndexedEntity.java:481)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.buildDocumentFields(DocumentBuilderIndexedEntity.java:481)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.getDocument(DocumentBuilderIndexedEntity.java:379)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.createAddWork(DocumentBuilderIndexedEntity.java:317)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.addWorkToQueue(DocumentBuilderIndexedEntity.java:295)
at org.hibernate.search.engine.WorkPlan$PerEntityWork.enqueueLuceneWork(WorkPlan.java:445)
at org.hibernate.search.engine.WorkPlan$PerClassWork.enqueueLuceneWork(WorkPlan.java:246)
at org.hibernate.search.engine.WorkPlan.getPlannedLuceneWork(WorkPlan.java:150)
at org.hibernate.search.backend.WorkQueue.prepareWorkPlan(WorkQueue.java:134)
at org.hibernate.search.backend.impl.BatchedQueueingProcessor.prepareWorks(BatchedQueueingProcessor.java:124)
at org.hibernate.search.backend.impl.PostTransactionWorkQueueSynchronization.beforeCompletion(PostTransactionWorkQueueSynchronization.java:89)
at org.hibernate.search.backend.impl.EventSourceTransactionContext$DelegateToSynchronizationOnBeforeTx.doBeforeTransactionCompletion(EventSourceTransactionContext.java:172)
... 27 more
I am not getting whats gone wrong.I am using org.springframework.orm.hibernate3.HibernateTransactionManager and my Spring version is 3.2 Hibernate core version is 3.6 final.
Note :This exception occurs often but When I create a new tables or use fresh db it works like charm and all modification/insertion are getting reflected properly in database.Can somebody explain me this behavior or Have i done something fishy.
Tell me if you need more details.
Thank you.
Code Update:
<batch:job-repository id="jobRepository"
data-source="myJNDI"
transaction-manager="transactionManager"
isolation-level-for-create="READ_COMMITTED"
max-varchar-length="2500"
lob-handler="defaultLobHandler"
/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="safeSessionFactory" />
</bean>
Like this I am configuring transaction manager in applicationContext.xml for Spring-Batch.And I have tried doing this with manually opening and closing session with manual commit of transaction but the exception remains same.And yes I have annotated my method as #Transactional.
I found the root cause of problem is Spring's Declarative Transaction Management.
Spring Batch in Action Reference:
Disable Spring’s declarative transactions for your batch application—Don’t use the tx:annotation-driven element or any XML
configuration related to declara- tive transaction management.
Be careful using propagation levels if declarative transactions are on—If you call trans- actional classes from a Spring Batch job,
Spring’s transaction propagation can interfere with the Spring Batch
transaction because of the propagation level. The REQUIRES_NEW
propagation level could typically cause problems because the
application code runs in its own transaction, independent of the
Spring Batch transaction.
The following are guidelines to avoid conflict between Spring Batch–managed and
Spring-managed transactions: