Hibernate: Automatically creating/updating the db tables based on entity classes - java

I have the following entity class (in Groovy):
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
#Entity
public class ServerNode {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id
String firstName
String lastName
}
and my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="NewPersistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/Icarus"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hbm2ddl.auto" value="create"/>
</properties>
<class>net.interaxia.icarus.data.models.ServerNode</class>
</persistence-unit>
</persistence>
and the script:
import javax.persistence.EntityManager
import javax.persistence.EntityManagerFactory
import javax.persistence.Persistence
import net.interaxia.icarus.data.models.ServerNode
def factory = Persistence.createEntityManagerFactory("NewPersistenceUnit")
def manager = factory.createEntityManager()
manager.getTransaction().begin()
manager.persist new ServerNode(firstName: "Test", lastName: "Server")
manager.getTransaction().commit()
the database Icarus exists, but currently has no tables. I would like Hibernate to automatically create and/or update the tables based on the entity classes. How would I accomplish this?

I don't know if leaving hibernate off the front makes a difference.
The reference suggests it should be hibernate.hbm2ddl.auto
A value of create will create your tables at sessionFactory creation, and leave them intact.
A value of create-drop will create your tables, and then drop them when you close the sessionFactory.
Perhaps you should set the javax.persistence.Table annotation explicitly?

You might try changing this line in your persistence.xml from
<property name="hbm2ddl.auto" value="create"/>
to:
<property name="hibernate.hbm2ddl.auto" value="update"/>
This is supposed to maintain the schema to follow any changes you make to the Model each time you run the app.
Got this from JavaRanch

Sometimes depending on how the configuration is set, the long form and the short form of the property tag can also make the difference.
e.g. if you have it like:
<property name="hibernate.hbm2ddl.auto" value="create"/>
try changing it to:
<property name="hibernate.hbm2ddl.auto">create</property>

In my case table was not created for the first time without last property listed below:
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hbm2ddl.auto" value="create-drop"/>
<!-- without below table was not created -->
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
</properties>
used Wildfly's in-memory H2 database

There is one very important detail, than can possibly stop your hibernate from generating tables (assuming You already have set the hibernate.hbm2ddl.auto). You will also need the #Table annotation!
#Entity
#Table(name = "test_entity")
public class TestEntity {
}
It has already helped in my case at least 3 times - still cannot remember it ;)
PS. Read the hibernate docs - in most cases You will probably not want to set hibernate.hbm2ddl.auto to create-drop, because it deletes Your tables after stopping the app.

TO CREATING TABLE AUTOMATIC , NO CONNECTION WITH ANNOTATIONS
FOR THAT WE NEED TO CHANGE "hibernate.cfg.xml" as like.
<property name="hbm2ddl.auto">update</property>

In applicationContext.xml file:
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- This makes /META-INF/persistence.xml is no longer necessary -->
<property name="packagesToScan" value="com.howtodoinjava.demo.model" />
<!-- JpaVendorAdapter implementation for Hibernate EntityManager.
Exposes Hibernate's persistence provider and EntityManager extension interface -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>

In support to #thorinkor's answer I would extend my answer to use not only #Table (name = "table_name") annotation for entity, but also every child variable of entity class should be annotated with #Column(name = "col_name"). This results into seamless updation to the table on the go.
For those who are looking for a Java class based hibernate config, the rule applies in java based configurations also(NewHibernateUtil). Hope it helps someone else.

Related

Is there a way to map same hibernate entity to multiple tables in different schemes

This is the situation. I have a table called customer and this table is repeating among different schemes in the same database. so the problem is when i'm going to map this customer table with hibernate entity do i need to create multiple classes for specifying the schema or can i dynamically change the schema in the entity. I'm a newbie to this hibernate framework please help.
You need to have more persistence unit. And use entity manager created via entity manager factory which used proper persistence unit.
In persistence.xml
<persistence-unit name="pu1" transaction-type="RESOURCE_LOCAL">
<property name="hibernate.connection.url" value="jdbc:database://url1"/>
<property name="hibernate.connection.username" value="username"/>
<property name="hibernate.connection.password" value="pass"/>
...
</persistence-unit>
<persistence-unit name="pu2" transaction-type="RESOURCE_LOCAL">
<property name="hibernate.connection.url" value="jdbc:database://url12"/>
<property name="hibernate.connection.username" value="username"/>
<property name="hibernate.connection.password" value="pass"/>
...
</persistence-unit>
private static EntityManagerFactory emf1;
private static EntityManagerFactory emf2;
emf1 = Persistence.createEntityManagerFactory("pu1");
emf2 = Persistence.createEntityManagerFactory("pu2");
emf1.createEntityManager();//Will store to database defined in pu1
emf2.createEntityManager();//Will store to database defined in pu2

Spring Data JPA save method does not update database entity when given id is already present

For some reason my JPA repository does not update existing database entity but creating a new one even if argument object has id that is already present in the database.
Here is my configuration:
<jpa:repositories base-package="com.someName.repository.support"
transaction-manager-ref="transactionManager_Support"
entity-manager-factory-ref="entityManagerFactory_Support"/>
<bean id="transactionManager_Support" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory_Support"/>
<property name="nestedTransactionAllowed" value="true"/>
</bean>
<bean id="entityManagerFactory_Support" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceSupport"/>
<property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
<property name="persistenceUnitName" value="persistenceUnit_SUPPORT"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
</props>
</property>
</bean>
<persistence-unit name="persistenceUnit_SUPPORT" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- List of all entity classes here -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" />
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.connection.charSet" value="UTF-8" />
</properties>
</persistence-unit>
I have a wrapper method in service defined like this:
#Transactional("transactionManager_Support")
public TestingResult save(TestingResult testingResult) {
try {
testingResult = testingResultRepository.saveAndFlush(testingResult);
LOGGER.info(String.format("Testing Result with id [%d] was successfully persisted", testingResult.getId()));
} catch (Exception e) {
LOGGER.error("Error persisting Testing Result");
}
return testingResult;
}
This method is called several times. The first time testingResult has null id, so it is saved with new id as expected. After that the same object with some new properties set is again saved, as i need to update existing entity in DB. But instead a new record in DB is created with id incremented by one.
Can anyone clarify why does such behavior occur?

How to Enable query cache in JBoss 7.1.1

I have tried to enable query cache without luck in JBoss 7.1.1
I have added this in the code:
TypedQuery<Currency> query = entityManager.createNamedQuery("getCurrency",Currency.class);
query.setParameter("code", code);
query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
query.setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.USE);
query.setHint("org.hibernate.cacheable", true);
The namedQuery looks like this:
#Cacheable
#Entity
#Table(name = "currency")
#NamedQuery(
name = "getCurrency",
query = "FROM Currency c WHERE c.iso4217code = :code"
)
I have in my persistence.xml the following:
<persistence-unit name="cache_persistence">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/cache</jta-data-source>
<class>com.unwire.cache.model.CacheTest</class>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.generate_statistics" value="true"/>
</properties>
</persistence-unit>
When I run the war file on the server
The entity gets cached but the query cache is never used
I have uploaded the file here: http://www.filedropper.com/cachetest
In my code (ear archive, but this should not make a difference) I simply have:
query.setHint("org.hibernate.cacheable", true);
query.setHint("org.hibernate.cacheMode", "NORMAL");
and
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.generate_statistics" value="true" />
</properties>
and without any additional things (like you have) and it works. Of course you must test the caching against the same parameters for the query.

Spring Hibernate integration using java persistence API?

I am using Spring3 and Hibernate4. I have below the configuration to work with spring and hibernate.
pom dependency
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.8.Final</version>
</dependency>
<dependency>
<groupId>oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
applicationContext.xml
<bean name="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>com.rsat.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.jdbc.batch_size">50</prop>
<!-- Added to mask bean relational constraint validation error -->
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- Hibernate Transaction manager for US data source -->
<tx:annotation-driven transaction-manager="transactionManager" />
SomeDao.java
#Repository
public class SomeDao implements ISomeDao{
#Autowired
SessionFactory sessionFactory;
//DAO methods here
}
Employee.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity(name = "EMPLOYEE")
public class Employee{
#Id
Long id;
#Column(name = "NAME")
String userName;
//setter and getters
}
Above configuration is working fine without any issues.
But now i am asked to use Hibernate JPA and use persistence.xml.
Could you please tell me which approach is recommended? Also how can i use Hibernate JPA ?
Thanks!
JPA isn't realliy a substitute of Hibernate. JPA is a generic specification of ORM (Object Relational Mapping). As with the case with other sub-technologies in Java, once many vendors started to invent similar thing, the Java community tried to create a spec to standardize it. Latest version of Hibernate does implement the JPA spec (as well as EclipseLink / DataNucleus / .. to name the others).
The benefit of using Hibernate-over-JPA is your code complies with the standard. Hence if later down the track for whatever reason you decide to change the ORM vendor you can do so with minimal code refactoring (because other vendor would (should) comply to the standards too)
There are many tutorials out there on the net on how to use JPA/Hibernate with Spring. One helpful way when I first get started is to checkout the Spring Roo project -- which is a code generator tool which can built a ready-to-use Spring MVC / JPA / Hibernate code project. From there you can inspect the configuration and setups.
Hibernate is a JPA implementation of JPA.
So as long as you stick you the JPA standard and avoid hibernate specific you will be fine.
Start with replacing session factory definition with the JPA equivalent EntityManagerFactory
<bean id="emf"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="puName" />
</bean>
If you will place the persistence.xml under /META-INF/ it should start working out of the box.
Your transactionManager should be adjust as well. Look at the documentation here
#Enttity is already jpa compliant
Hibernate is one of the first ORM framework became the market leader. There is no JPA specification defined for the ORM solutions when Hibernate was introduced in the market. After seeing the advantage of Hibernate APIs, Java community has created a common specifications known as JPA for all the problems in the persistence mechanism.
Hibernate provides JPA implementation that is known as Hibernate JPA. What is different is that JPA implementations must compliant with the specifications but vendor solutions would have their own APIs (some times that would provide added valued to your application). It is always recommended to use the standard API like JPA for the future good.
If you are looking for the integration approach, this article about Hibernate and Spring Integration may help.
Could you please tell me which approach is recommended? Also how can i use Hibernate JPA ?
Because Hibernate is an implementation of JPA specification, if you want to use it you should only take care about configuration. You should not use it directly in DAO classes. In DAO classes you should use JPA only.
Following are steps to configure Hibernate:
1. persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
<property name="hibernate.hbm2ddl.auto" value="none"/>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<!-- Uncomment the following two properties for JBoss only -->
<!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
<!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
</properties>
</persistence-unit>
</persistence>
2. applicationContext.xml
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
Now in DAO class:
#Repository
public class OrderDetailsNativeDaoImpl implements OrderDetailsDao {
#PersistenceContext
private EntityManager entityManager;
#SuppressWarnings("unchecked")
#Override
public List<OrderDetailsResult> getOrderDetails(int orderId) {
String queryString = "SELECT dt.id, 1 as version, dt.orderid as orderId, od.orderdate as orderDate, pd.name as productName, dt.unitprice as unitPrice, dt.quantity as quantity"
+ " FROM orders od INNER JOIN orderdetails dt ON od.id = dt.orderid"
+ " INNER JOIN products pd ON dt.productid = pd.id WHERE dt.orderid = :orderId";
Query query = entityManager.createNativeQuery(queryString, OrderDetailsResult.class);
query.setParameter("orderId", orderId);
List<OrderDetailsResult> beanList = query.getResultList();
return beanList;
}
}

How to set up default schema name in JPA configuration?

I found that in hibernate config file we could set up parameter hibernate.default_schema:
<hibernate-configuration>
<session-factory>
...
<property name="hibernate.default_schema">myschema</property>
...
</session-factory>
</hibernate-configuration>
Now I'm using JPA and I want to do the same. Otherwise I have to add parameter schema to each #Table annotation like:
#Entity
#Table (name = "projectcategory", schema = "SCHEMANAME")
public class Category implements Serializable { ... }
As I understand this parameter should be somewhere in this part of configuration:
<bean id="domainEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JiraManager"/>
<property name="dataSource" ref="domainDataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="showSql" value="false"/>
<property name="databasePlatform" value="${hibernate.dialect}"/>
</bean>
</property>
</bean>
<bean id="domainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driver}" />
<property name="jdbcUrl" value="${datasource.url}" />
<property name="user" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
<property name="initialPoolSize" value="5"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="15"/>
<property name="checkoutTimeout" value="10000"/>
<property name="maxStatements" value="150"/>
<property name="testConnectionOnCheckin" value="true"/>
<property name="idleConnectionTestPeriod" value="50"/>
</bean>
... but I can't find its name in google. Any ideas?
Don't know of JPA property for this either. But you could just add the Hibernate property (assuming you use Hibernate as provider) as
...
<property name="hibernate.default_schema" value="myschema"/>
...
Hibernate should pick that up
Just to save time of people who come to the post (like me, who looking for Spring config type and want you schema name be set by an external source (property file)). The configuration will work for you is
<bean id="domainEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JiraManager"/>
<property name="dataSource" ref="domainDataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="showSql" value="false"/>
<property name="databasePlatform" value="${hibernate.dialect}"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.default_schema">${yourSchema}</prop>
</props>
</property>
</bean>
Ps :
For the hibernate.hdm2ddl.auto, you could look in the post Hibernate hbm2ddl.auto possible values and what they do?
I have used to set create-update,because it is convenient. However, in production, I think it is better to take control of the ddl, so I take whatever ddl generate first time, save it, rather than let it automatically create and update.
For others who use spring-boot, java based configuration,
I set the schema value in application.properties
spring.jpa.properties.hibernate.dialect=...
spring.jpa.properties.hibernate.default_schema=...
In order to avoid hardcoding schema in JPA Entity Java Classes we used orm.xml mapping file in Java EE application deployed in OracleApplicationServer10 (OC4J,Orion).
It lays in model.jar/META-INF/ as well as persistence.xml. Mapping file orm.xml is referenced from peresistence.xml with tag
...
<persistence-unit name="MySchemaPU" transaction-type="JTA">
<provider>...</provider>
<mapping-file>META-INF/orm.xml</mapping-file>
...
File orm.xml content is cited below:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>myschema</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>
For those who uses last versions of spring boot will help this:
.properties:
spring.jpa.properties.hibernate.default_schema=<name of your schema>
.yml:
spring:
jpa:
properties:
hibernate:
default_schema: <name of your schema>
I had to set the value in '' and ""
spring:
jpa:
properties:
hibernate:
default_schema: '"schema"'
Use this
#Table (name = "Test", schema = "\"schema\"")
insteade of #Table (name = "Test", schema = "schema")
If you are on postgresql the request is :
SELECT * FROM "schema".test
not :
SELECT * FROM schema.test
PS: Test is a table
If you are using (org.springframework.jdbc.datasource.DriverManagerDataSource) in ApplicationContext.xml to specify Database details then use below simple property to specify the schema.
<property name="schema" value="schemaName" />

Categories

Resources