I am facing a problem with Spring Transaction management. I am using hibernate as ORM framework. And below is my spring for transaction management.
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="abstractDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true" lazy-init="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
<property name="postInterceptors">
<list>
<ref bean="finderIntroductionAdvisor"/>
</list>
</property>
</bean>
<bean id="abstractService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true" lazy-init="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>
I am basically following genericDao approach as mentioned here so My DaoObject are used to fetch the Domain objects and service classes have DAO objects to maipulate them.
issue i am facing : i am querying a large dataset and loading the result in a list inside the service class. i have marked service class as #transactional(readonly ="true").
to handle some reuirement i have changed all the getters of boxed primitive to
#Column(name = "students")
public Long getStudents() {
if(students== null){
return 0l;
}
return this.students;
}
whenever i load all the dataset via a named query. multiple update queries are fired subsequently to update the dataset.
I debugged that and came to know that this is occuring because of transaction.commit. as hibernate is treating my entities as dirty.
is there a way i can avoid this . i know Flushmode.never could be of help but in my application seesion object is not exposed so i do not have access to it. is there any other way or some mapping change which can help me ?
In addition to Xavi López's answer, another option is to separate persistent property handled by Hibernate from the transient property that conform to your requirement. For example, as follows:
#Column(name = "students")
public Long getStudentsInternal() {
return students;
}
#Transient
public Long getStudents() {
if (students == null) {
return 0l;
}
return students;
}
You can also configure Hibernate to use fields instead of properties by moving annotations to them, it will solve your problem as well (note that the placement of annotations should be consitent for all fields of the entity, or you can use #Access to configure an exclusion):
#Column(name = "students")
private Long students;
public Long getStudents() {
if (students == null) {
return 0l;
}
return students;
}
The issue is with
if(students== null){
return 0l;
}
When Hibernate fetches your entities, they all have null value on the studentsfield. At commit time, when checking if they are dirty, getStudents() returns 0, which is different from the value stored in the database. So, Hibernate sees them as dirty, and proceeds to the update.
If it is suitable to your requirement, changing the type of the studentfield to the primitive type long instead of Long would probably help. Note that this would lead to updating all null's in that column to 0 in the long term.
Maybe you should handle that requirement somewhere else, and free the getter from that concern.
Related
I have been trying to execute an Oracle Stored Procedure using Hibernate. This is not for production - but for a Java source parsing project, that I'm pursuing. To put it in simple terms, I'm not able to return a value from an Oracle Stored Proc.
I have searched and read all relevant links from SO, Hibernate community/documentation(Native SQL chapter) links and tried out the suggestions, but somehow couldn't get them to work. Below are my sources - I'm including only the relevant parts.
My Entity Class. I have reserved the first parameter for a PL/SQL OUT parameter.
Login.java
#NamedNativeQuery(
name = "getLoginDet",
query = "call GET_LOGIN_DET(?,:userId)",
resultClass = Login.class)
#Entity
#Table(name = "T_LOGIN_DET")
public class Login {
Oracle Stored Proc : GET_LOGIN_DET.sql. The first parameter is OUT REFCURSOR as per Hibernate Spec
create or replace PROCEDURE GET_LOGIN_DET(listLogin OUT SYS_REFCURSOR,userId IN VARCHAR2)
AS
BEGIN
OPEN listLogin FOR
SELECT *
FROM T_LOGIN_DET
WHERE USER_ID = userId;
END GET_LOGIN_DET;
My DAO Class : I'm binding only the named parameter, ignoring the first ? in the named Query.
Session session = sessionFactory.openSession();
List results = session.getNamedQuery("getLoginDet").setParameter("userId", u.getUserId()).list();
My Hibernate Config
<bean id="mysessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.cogn.gto.sea.employee.entity.Employee</value>
<value>com.cogn.gto.sea.employee.entity.Department</value>
<value>com.cogn.gto.sea.login.entity.User</value>
<value>com.cogn.gto.sea.login.entity.Login</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
However, I always end up with Hibernate QueryException / Java SQLException
Expected positional parameter count: 1, actual parameters: [] [{call GET_LOGIN_DET(?,:userId)}]
I have tried variations of {? = call GET_LOGIN_DET(:userId)} , call GET_LOGIN_DET(?,:userId) to no avail. My requirement is to call the procedure that I have listed and get the result back in the DAO class. Can someone lead me to what exactly I'm missing here ?
I believe you have incorrectly declared call to stored procedure (curly brackets missing), try this:
#NamedNativeQuery(
name = "getLoginDet",
query = "{call GET_LOGIN_DET(?,:userId)}",
resultClass = Login.class
hints = {#QueryHint(name = "org.hibernate.callable", value = "true")})
#Entity
#Table(name = "T_LOGIN_DET")
public class Login {
I have hibernated annotated classes in my program. Since I'm running a Spring project, I have included them in the servlet.xml file(com.student.dto is the actual package name) and added #Component on the Contacts Entity..Is there a way to automate adding #Component on all the hibernate classes..Each time I create a model, I end up doing this and feel there should be a better to do this.
<context:component-scan base-package="com.student.dto" />
#Component
#Entity
#Table(name = "Contacts", catalog = "javadb")
public class ContactsDTO implements java.io.Serializable {
private int idContacts;
private StudentDTO StudentDTO;
private String addr1;
private String addr2;
private String city;
private String state;
private String pinCode;
private String country;
private String phone;
private String mobile;
private String email;
private String contactscol;
public ContactsDTO() {
}
public ContactsDTO(int idContacts) {
this.idContacts = idContacts;
}
public ContactsDTO(int idContacts, StudentDTO StudentDTO, String addr1,
String addr2, String city, String state, String pinCode,
String country, String phone, String mobile, String email,
String contactscol) {
this.idContacts = idContacts;
this.StudentDTO = StudentDTO;
this.addr1 = addr1;
this.addr2 = addr2;
this.city = city;
this.state = state;
this.pinCode = pinCode;
this.country = country;
this.phone = phone;
this.mobile = mobile;
this.email = email;
this.contactscol = contactscol;
}
getters & setters
You are doing it all wrong. Spring Beans are singleton by default and your entities are not thread safe and neither they should ever be.
Entities should be local variables bound to a Persistent Context. They are not meant to be accessed in a multi-threaded environment.
Concurrency control is handled by the database and your application logic should mostly be concern about preventing lost updates through application-level repeatable reads.
Your DAO and Services should be Spring singleton components. Your Entities and request bound DTOs should never be singleton. These objects are short-lived and scoped to the request that generated them.
Check the Spring Data JPA docs for a solid data access layer design.
The #Component javadocs says this.
Indicates that an annotated class is a "component". Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning.
The #Component, #Repository etc are Typically used for Auto scanning (during application bootstrap)and for the dependency injection. I dont see a point in making your entity as a Spring Component. The typical use of an entity is that it represents your Relational database Table. Entity (Java)= Table (RDBMS). Here is the definition of an Entity
An entity is a lightweight persistence domain object. Typically, an entity represents a table in a relational database, and each entity instance corresponds to a row in that table. The primary programming artifact of an entity is the entity class, although entities can use helper classes.
The way to include your entities should be something like this:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<!-- Here are your Entities annotated with #Entity -->
</list>
</bean>
Note that you can also define a property called "annotatedPackages" and define your packages
Personally, i havent tested "annotatedPackages". But, "annotatedClasses" work perfectly.
As suggested by #Vlad Mihalcea, Entities are not meant to be Singleton. They are more of "Local" scope, and are to be intialized per "request".
You can configure this by convention. In the servlet.xml you can add a bean that does class path scanning and can automatically add the #Component using a regex and a common naming approach. See here for details:
http://www.mkyong.com/spring/spring-filtering-components-in-auto-scanning/
I have a small hibernate application as above:
BankAccount class is as follows:
package in.co.way2learn;
import java.util.Set;
public class BankAccount {
private int accountNumber;
private String accountHoldersName;
private int balance;
private Address address;
private Set<String> emails;
//setters and getters
}
Address class is as below:
package in.co.way2learn;
public class Address {
private String addressLine1;
private String addressLine2;
private String city;
private String country;
private int pinCode;
//setters and getters
}
BankAccount.hbm.xml file is as below:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jul 2, 2014 3:59:34 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="in.co.way2learn">
<class name="BankAccount">
<id name="accountNumber" type="integer">
<generator class="assigned"/>
</id>
<property name="accountHoldersName" type="string"/>
<property name="balance" type="integer"/>
<component name="address" class="Address" lazy="true">
<property name="addressLine1"/>
<property name="addressLine2"/>
<property name="city"/>
<property name="country"/>
<property name="pinCode"/>
</component>
<set name="emails" order-by="email asc" table="bankaccount_emails">
<key column="SNo"/>
<element column="email" type="string"/>
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml file is as below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
org.gjt.mm.mysql.Driver
</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/way2learnDB
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="in/co/way2learn/BankAccount.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Now my question is in BankAccount.hbm.xml file in the component tag I am using using lazy="true", when ever I am firing select query on BankAccount class using session.get(BankAccount.class, 1235); It is loading address details also from database, the code I used to fire select query is below:
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
BankAccount bankAccount=(BankAccount)session.get(BankAccount.class, 1235);
transaction.commit();
session.close();
The query fired is
Hibernate:
select
bankaccoun0_.accountNumber as accountN1_0_0_,
bankaccoun0_.accountHoldersName as accountH2_0_0_,
bankaccoun0_.balance as balance3_0_0_,
bankaccoun0_.addressLine1 as addressL4_0_0_,
bankaccoun0_.addressLine2 as addressL5_0_0_,
bankaccoun0_.city as city6_0_0_,
bankaccoun0_.country as country7_0_0_,
bankaccoun0_.pinCode as pinCode8_0_0_
from
BankAccount bankaccoun0_
where
bankaccoun0_.accountNumber=?
But I am expecting address details will be loaded lazily from database when ever I used bankAccount.getAddress() method only?
Now can any one please explain why hibernate is loading address details eagerly, and how to load then lazily?
Take an example from below code:-
class B {
private C cee;
public C getCee() {
return cee;
}
public void setCee(C cee) {
this.cee = cee;
}
}
class C {
// Not important really
}
Right after loading B, you may call getCee() to obtain C. But look, getCee() is a method of your class and Hibernate has no control over it. Hibernate does not know when someone is going to call getCee(). That means Hibernate must put an appropriate value into "cee" property at the moment it loads B from database.
If proxy is enabled for C, Hibernate can put a C-proxy object which is not loaded yet, but will be loaded when someone uses it. This gives lazy loading for one-to-one.
But now imagine your B object may or may not have associated C (constrained="false"). What should getCee() return when specific B does not have C? Null. But remember, Hibernate must set correct value of "cee" at the moment it set B (because it does no know when someone will call getCee()). Proxy does not help here because proxy itself in already non-null object.
If your B->C mapping is mandatory (constrained=true), Hibernate will use proxy for C resulting in lazy initialization. But if you allow B without C, Hibernate just HAS TO check presence of C at the moment it loads B. But a SELECT to check presence is just inefficient because the same SELECT may not just check presence, but load entire object. So lazy loading goes away.
Workaround1 : - Just add annotation or entry in hdm file for #JoinColumn for reference private Address address;.
Workaround2 :- add optional=false in OneToOne relationship
Other solutions for this problem:
The simplest one is to fake one-to-many relationship. This will work because lazy loading of collection is much easier then lazy loading of single nullable property but generally this solution is very inconvenient if you use complex JPQL/HQL queries.
The other one is to use build time bytecode instrumentation. For more details please read Hibernate documentation: 19.1.7. Using lazy property fetching. Remember that in this case you have to add #LazyToOne(LazyToOneOption.NO_PROXY) annotation to one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough.
The last solution is to use runtime bytecode instrumentation but it will work only for those who use Hibernate as JPA provider in full-blown Java EE environment (in such case setting "hibernate.ejb.use_class_enhancer" to true should do the trick: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this might be hard to achieve on some older application servers). In this case #LazyToOne(LazyToOneOption.NO_PROXY) annotation is also required.
This will work for you.
Hibernate does not create proxies for components, that's why lazy loading does not work for them.
Solutions:
Use bytecode instrumentation to enable lazy loading of non-entity fields. It has its own pitfalls and is not widely adopted.
Use two different classes for BankAccount, one containing the Address component (as it is now), and one without it, and map them to the same table. Then, use the one without address in contexts in which you don't need addresses.
Use fake one-to-one association between BankAccount and Address by making Address component an entity and mapping it to the same table. The drawback here is that you must not insert the Address instances (because you'll end up trying to insert a separate row in the table), but rather you have to read and update it after you insert the corresponding BankAccount entity instance.
Change the db schema and move the component to its own separate table. Then simply promote the component to an entity and map it to the new table.
For my desktop application I use JavaFX, Spring, JPA + Hibernate and PostgreSQL. Currently I have faced several issues.
Issue one: Violation of PRIMARY KEY constraint SQL Error
When I create Entity classes according to following manner (GenerationType as AUTO) it works fine. But when I create a new data base and add some Test data with sql script (as showing following picture) and try to insert some data with my application I have got 'Violation of PRIMARY KEY constraint' SQL Error. That mean it seems Hibernate try to generated PK values which are already available (allocated with my test data ex 1, 2, 3 etc). But after 5 attempts (exceed the test data maximum pk value) it was fine and start the data inserting with PK key value with 6.
Entity Class - GenerationType as AUTO
#Entity
#Table(name = "devicetype")
public class Devicetype implements Serializable {
#Id
#Basic(optional = false)
#Column(name = "id")
private Integer id;
}
Table with initial test data
EntityManager factory
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.core.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgresPlusDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
</bean>
Issue Two: Gaps In the sequence value
For make resolve about error I have changed Entity class according to following manner (with GenerationType as SEQUENCE) and done the same steps (insert initial test data with sql script and try to insert data via application). Then data was inserted without any exception. Now my table contains records both inserted via script and application (as showing following picture). But newly add data (I have highlight on light blue color) via application had very higher PK value (started at 184 not from 6). That mean with "GenerationType as SEQUENCE" it seems hibernate not populate ID value in sequence manner (maintain some gaps). When I add further some data via application it seems it will stat to inserting data with another higher ID value (not start form 214). That mean is seems ID is not incrementing on sequence manner.
Entity Class - GenerationType as SEQUENCE
#Entity
#Table(name = "device_type")
public class DeviceType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name="my_seq", sequenceName="MY_SEQ", allocationSize=1, initialValue=1)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
}
Table data with gaps (for sequence ID)
This is how sequences (and so the PostgreSQL SERIAL type) behave.
If you are manually inserting values then you will need to update the sequence accordingly. Or, more usually, don't manually insert the values and let the sequence do it.
Gaps are inevitable unless you want to lock the table on each insert and kill off any hope of concurrency. I'd recommend not caring.
Remember - the numbers don't mean anything, they are just a convenient identifier.
Spend a few minutes reading up on how this all works: CREATE SEQUENCE, ALTER SEQUENCE
I have a class need to be dessrialized using jackson and the class has an collection property. The collection is empty, but not null.
Question: How to desersialise the class without empty collection. Sample code below:
class Person
{
String name;
List<Event> events;
//....getter, setter
}
if
person.list = new List<Event>();
persion.name = "hello";
then excepted the json would be:
{name: "hello"}
not
{name: "hello", events:[]}
How to make it? Thank you~~
================================================
I have solved this by n1ckolas's advice. Thank you first.
My jackson version is 2.1.1, and Spring-3.2.2 import better support for this verson of jackson. Also, this works for both arrays and collection.
Below is my configuraion:
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--Json Mapper-->
<bean name="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" autowire="no">
<property name="featuresToDisable">
<list>
<!--not to return empty colletion-->
<value type="com.fasterxml.jackson.databind.SerializationFeature">WRITE_EMPTY_JSON_ARRAYS</value>
</list>
</property>
</bean>
You can use #JsonInclude(JsonInclude.Include.NON_EMPTY) annotation on your class or filed.
import com.fasterxml.jackson.annotation.JsonInclude;
#JsonInclude(JsonInclude.Include.NON_EMPTY)
class Person
{
String name;
List<Event> events;
//....getter, setter
}
If you can change your original model with Jackson annotations, here is the way how to achieve this.
Jackson has WRITE_EMPTY_JSON_ARRAYS. And you may turn off it with:
objectMapper.configure(SerializationConfig.Feature.WRITE_EMPTY_JSON_ARRAYS, false);
But it works only for Arrays, but not for Collections. But you may combine #JsonProperty with #JsonIgnore, something like the following:
//....getter, setter of Person class
#JsonIgnore
public List<Event> getEvents() {
return events;
}
#JsonProperty("events")
public Event[] getEventsArr() {
return events.toArray(new Event[0]);
}
And afterwards you'll have output, as you expected.
EDIT: If you are using SpringMVC, then you can configure your actual ObjectMapper with explicit reference in mvc:annotation-driven:
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--custom Json Mapper configuration-->
<bean name="objectMapper" class="org.springframework.http.converter.json.JacksonObjectMapperFactoryBean" autowire="no">
<property name="featuresToDisable">
<list>
<!--Ignore unknown properties-->
<value type="org.codehaus.jackson.map.SerializationConfig.Feature">WRITE_EMPTY_JSON_ARRAYS</value>
</list>
</property>
</bean>
Offtop: usually it's quite useful to specify explicit instance of ObjectMapper, because:
you can configure it in the way you want
you can use its reference through #Autowired
If you are using Spring Boot, just add in your application.properties the following :
spring.jackson.serialization-inclusion=NON_EMPTY
Use this annotation #JsonInclude(JsonInclude.Include.NON_EMPTY)
#JsonInclude(JsonInclude.Include.NON_EMPTY)
person.list = new List<Event>();
from documentation
Value that indicates that only properties with null value, or what is
considered empty, are not to be included.
Spring boot automatically picks the property from the application.properties
you can add below property:
spring.jackson.serialization.write-empty-json-arrays=false
You can use JSON View, like in here : Jackson - suppressing serialization(write) of properties dynamically
Another way to do it is to define another class, almost similar with Person, but without the events property. Then based on the value of the collections, you can decide to serialize the original Person object, or the alternative, events-less object. This is IMHO simpler, and should works for your case above, but not as flexible as the first alternative.
#JsonInclude(JsonInclude.Include.NON_EMPTY) Include this, at class level, will do following things.
Include only not null values
Include only non empty list