Prevent Hibernate schema changes - java

I am new to Hibernate and am having some issue with its configuration. I am trying to setup a read-only connection to a preexisting Oracle database. I do not want Hibernate to execute any DML/DDL and alter the database schema, yet every time I try deploying my project, this is the message I see:
INFO: updating schema
SEVERE: Unsuccessful: create table WILLOEM.SAMPLE_INFO (SAMPLE_ID varchar2(255) not null, CELL_LINE varchar2(255), STUDY_ID varchar2(255), primary key (SAMPLE_ID))
SEVERE: ORA-00955: name is already used by an existing object
No damage is being done here, since the table creation failed, but I don't want to create a situation where data can be lost. How can I configure Hibernate to act in a read-only manner? Can I prevent statement execution completely, without adding a new Oracle user that lacks the privileges?
Here is my current Hibernate configuration:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>oracle.jdbc.OracleDriver</value></property>
<property name="url"><value>jdbc:oracle:thin:#source.db.somewhere.com:1524:WILLOEM</value></property>
<property name="username"><value>username</value></property>
<property name="password"><value>password</value></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="packagesToScan" value="com.willoem.project.hibernate" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

you could change
<prop key="hibernate.hbm2ddl.auto">update</prop>
to
<prop key="hibernate.hbm2ddl.auto">validate</prop>
this validates the schema, but it will not make any no changes to it.

Related

I can't create table with hibernate

I created a jpa xml EntityManagerFactory. After running tomcat, and Hibernate create table in console, but when I checked the database , I didn't see the table. What's the problem ?
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
<property name="packagesToScan" value="com.example.hospitalmanage.model"></property>
</bean>
Ensure all models are in package com.example.hospitalmanage.model
User
user_diagnosis
user_treatments
user_videos
All should be inside the same package.

Spring Data JPA Additional EntityManagerFactory Optimized for Cache and Bulk Operations Only

I have a legacy Spring Data JPA application that has a large number of Entities and CrudRepositories. JPA is configured using the XML below. We have a new requirement that requires us to insert 10,000 - 50,000 entities into the database at once via a FileUpload. With the existing configuration the database CPU spikes. After enabling hibernate statistics, its was apparent that these 10,000 insert operations were generating over 200,000 DB queries due to all the validation logic required with a single insert in the InvoiceService.
Original Configuration
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.jdbcurl}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="maxTotal" value="${db.maxTotal}"/>
<property name="maxIdle" value="${db.maxIdle}"/>
<property name="minIdle" value="${db.minIdle}"/>
<property name="initialSize" value="${db.initialSize}"/>
<property name="maxWaitMillis" value="${db.maxWaitMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>
<property name="timeBetweenEvictionRunsMillis" value="${db.timeBetweenEvictionRunsMillis}"/>
<property name="testOnBorrow" value="${db.testOnBorrow}"/>
<property name="testOnReturn" value="${db.testOnReturn}"/>
<property name="testWhileIdle" value="${db.testWhileIdle}"/>
<property name="removeAbandonedOnBorrow" value="${db.removeAbandonedOnBorrow}"/>
<property name="removeAbandonedOnMaintenance" value="${db.removeAbandonedOnMaintenance}"/>
<property name="removeAbandonedTimeout" value="${db.removeAbandonedTimeout}"/>
<property name="logAbandoned" value="${db.logAbandoned}"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="flyway">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="my.package.domain" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto:validate}</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
</props>
</property>
<property name="persistenceUnitName" value="entityManagerFactory" />
</bean>
<bean id="persistenceAnnotationBeanPostProcessor" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="defaultPersistenceUnitName" value="entityManagerFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven proxy-target-class="true" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<jpa:repositories base-package="my.package.repository" entity-manager-factory-ref="entityManagerFactory"/>
The FileUploadService snippet looks like this...
EntityManager batchEntityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = batchEntityManager.getTransaction();
transaction.begin();
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
buffer.lines()
.filter(StringUtils::isNotBlank)
.forEach(csvLine -> {
invoiceService.createInvoice(csvLine);
if (counter.incrementAndGet() % (updateFrequency.equals(0) ? 1 : updateFrequency) == 0) {
FileUpload fileUpload1 = fileUploadRepository.findOne(fileUpload.getId());
fileUpload1.setNumberOfSentRecords(sentCount.get());
fileUploadRepository.save(fileUpload1);
transaction.commit();
transaction.begin();
batchEntityManager.clear();
}
});
transaction.commit();
} catch (IOException ex) {
systemException.incrementAndGet();
log.error("Unexpected error while performing send task.", ex);
transaction.rollback();
}
// Update FileUpload status.
FileUpload fileUpload1 = fileUploadRepository.findOne(fileUpload.getId());
fileUpload1.setNumberOfSentRecords(sentCount.get());
if (systemException.get() != 0) {
fileUpload1.setStatus(FileUploadStatus.SYSTEM_ERROR);
} else {
fileUpload1.setStatus(FileUploadStatus.SENT);
}
fileUploadRepository.save(fileUpload1);
batchEntityManager.close();
Most of the DB queries were select statements that return the same results for each record being inserted. It was obvious that enabling EhCache as a Second-Level cache would have a significant performance improvement. However, this application has been running flawlessly in production for several years without ehcache enabled. I am hesitant to turn this on globally as I do not know how this will affect the large number of other repositories/queries.
Question 1
Is there a way to configure a "alternate" EntityManagerFactory that uses the second level cache for this batch process only? How can I choose to use this factory instead of the primary for this batch process only?
I experimented adding something like below to my spring config. I can easily inject this additional EntityManager into my class and use it. However, the existing Repositories (such as FileUploadRepository) don't seem to use it - they just return null. I am not sure if this approach is possible. The documentation for JpaTransactionManager says
This transaction manager is appropriate for applications that use a single JPA EntityManagerFactory for transactional data access
which is exactly what I am not doing. So what other options are there?
<bean id="batchEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="flyway">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="my.package.domain" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto:validate}</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics:false}</prop>
<prop key="hibernate.ejb.interceptor">my.package.HibernateStatistics</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.jdbc.batch_size">100</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.order_updates">true</prop>
</props>
</property>
<property name="persistenceUnitName" value="entityManagerFactory" />
</bean>
Question 2
Assuming there is no other option to "selectively" use EhCache, I tried enabling it on the primary EntityManagerFactory only. We can certainly do regression testing to make sure we don't introduce new issues. I assume this is fairly safe to do? However, another issue came up. I am trying to commit inserts in batches as described in this post and shown in my code above. I am getting an RollbackException when trying to commit the batch due to Connection org.postgresql.jdbc.PgConnection#1e7eb804 is closed.. I presume this is due to the maxWaitMillis property on the dataSource.
I don't want to change this property for every other existing spring Service/Repository/query in the application. If I could use the "custom" EntityManagerFactory I could easily provide a different DataSource Bean with the properties I want. Again, is this possible?
Maybe I looking at this problem all wrong. Are there any other suggestions?
You can have another EntityManagerFactory bean with a different qualifier, so that's one option. I would still recommend you look into these select queries. I bet the problem is just a missing index which causes the database to do full table scans. If you add the proper indexes, you probably don't need to change a thing in your application.

Do I need to register all the model class in hibernate config file

Suppose I have number of model classes(Entity class). Do I need to register all the model class in hibernate config file one after another like
...
<mapping class="com.java.ent.Table"/>
...
or any annotation is there which marks as entity? For medium app there would be huge amount of table and its corresponding model entity. how to manage it?
There another way to configure hibernate sessionFactory where you can actually give only packageToScan.
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.connection.useUnicode">true</prop><!-- added -->
<prop key="hibernate.connection.characterEncoding">UTF-8</prop><!-- added -->
<prop key="hibernate.connection.charSet">UTF-8</prop><!-- added -->
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.web.entities</value>
</list>
</property>
</bean>
You can write your own set package in AnnotationConfiguration as described in the dicumentation.
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/ch01.html
Or
Another option is to write custom AnnotationConfigurationWithWildcard which extends the org.hibernate.cfg.AnnotationConfiguration and inject as spring dependency.
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfigurationWithWildcard"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>
You can use which ever suits you better.

hibernate create schema if not exists mysql

I'm using Spring 3 and hibernate 4.
Here is my root-context.xml
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/musicstore"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="sessionFactory" name="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="packagesToScan" value="domain" /><!--
entity -->
</bean>
And I've got this :
WARN : org.hibernate.engine.jdbc.internal.JdbcServicesImpl - HHH000342: Could not obtain connection to query metadata : Unknown database 'musicstore'
When I deploy my project in tomcat, I want hibernate will create the schema if it's not exist. I have tried hibernate.hbm2ddl.auto= create but it's not working
Are there any ways to do create the schema automatically at run time ? Any suggestions would be helpful :D
Thanks in advance.
I don't know how to solve your problem in a hibernate specific way, but a cool thing about MySQL is that you can (at the very least under certain conditions) specify for the Database itself to be created if it doesn't already exist via the connection string by appending "?createDatabaseIfNotExist=true" to the end.
So, by changing your Spring config to the following you should get the results you need.
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/musicstore?createDatabaseIfNotExist=true"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="sessionFactory" name="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="packagesToScan" value="domain" /><!--
entity -->
</bean>
It's worth noting that I don't know anything more about this than that it works, so it may very well have limitations of which I am unaware.
Hibernate requires the database to exist: it cannot help you create the database. If you need to create the database the you will need to implement another solution that executes before Hibernate is initialized.
As you are using Spring the following may be useful for executing the initial 'CREATE DATABASE X' statement.
http://docs.spring.io/spring-framework/docs/3.0.0.RC3/reference/html/ch12s09.html
You obviously need to ensure the initailization executes before the sessionFactory bean is initialized.
You would also likely define 2 datasources, one configured as outlined at the link provided by mretierer (Create MySQL database from Java) i.e. with no database defined and which is used by the Spring db initializer bean and one for use by Hibernate which references the database created during initialization.
No idea if any of this will work but looks feasible...
First the answer to your question: The property you already supplied should do what you were asking for.
<prop key="hibernate.hbm2ddl.auto">update</prop>
The exception your are getting refers to a different problem. Hibernate can't connect to the database you specified.
Pls check your connection string
<property name="url" value="jdbc:mysql://localhost:3306/musicstore"></property>

Insert into database after spring hibernate sessionfactory is created

I want to insert some data in a table of database after the SessionFactory of spring hibernate has been created.
I have a CUSTOMER table and I want to insert a particular Customer into this table if the Customer doesn't exist.
This is the configuration of SessionFactory:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="packagesToScan" value="com.edfx.adb.persist.entity" />
<property name="entityInterceptor" ref="entityInterceptor" />
</bean>
I know that there is an option hibernate.hbm2ddl.import_files from which we can mention a sql file and the query will be executed at the time of SessionFactory initialization. But I don't want to follow this way.
Also I have found that we can use ServletContextListener for this kind of purpose, but I am not sure this is a good way to achieve what I want. Because what I understand is the listener will be initialized after deployment of war file, when the first user hit the application. So if I have a Scheduler which operates of the Customer and if the Scheduler get executed before any user hit the app, then the Scheduler wouldn't find that need-to-be-insert data.
Any pointer would be very helpful to me.
You can extend org.springframework.orm.hibernate4.LocalSessionFactoryBean and override buildSessionFactory() method to according to your requirement.

Categories

Resources