Blog Archives

Spring data -yet another abstraction -quickly getting started


We started with JDBC, then ORM which abstracted the underlying relation DB. Then came JPA -which abstracted the underlying ORM. Now Spring Data

But the kind of versatility we see today in data storage -relational, distributed, nosql and others, to me Spring Data seems to server the purpose.

It abstracts the CRUD for “different” type of data as relational, nosql and just by coding to appropriate interface CRUD operations can be achieved. For getting started use this link for configuring the entity manage, transaction manager -basically the setup stuff.

Write a DaoInterface -here the magic goes, the extended interface decides type of data , relational, nosql etc.

public interface TestDao extends CrudRepository<TestData , Integer> {
}

And then for CRUD operations use this Interface :

@Service
public class TestService{
    @Autowired
    TestDao testDao;
 	public boolean saveTestData(TestData testData){
    	if(testData!=null){
    		testDao.save(user);
                return true;
        }
    	return false;
    }
}
     @Entity
	@Table (name="testtable")
	public class TestData {
	 
	    @Id
	    @GeneratedValue
	    private Long id;
	     
	    public Long getId() {
	        return id;
	    }
	 
	    public void setId(Long id) {
	        this.id = id;
	    }

I found it simple, yet flexible and power full considering the fact that although projects start with SQL, but down the line NOSQL is definitely on their road map -this abstraction will ensure least throwaway code!

MySql connections autodrop after a certain hours


MySql is configured to drop any connection which has been Idle for more than 8 hours. What is the implication of this? After you return to your deployed app after a gap of 8 hours (If default SQL parameters have not been changed), you will be greeted with an exception.

How to solve this issue?

  1. Increase the wait_time parameter -Not a good Idea, it might unnecessarily hold on to the resources and not might be a sure shot way. Apart from that, being dependent on an “external” configuration for failover is not a very good idea -what if the server itself crashes, what if this configuration is missed in one of the instnaces, and many such issues will pop up against this approach.
  2. Use the parameter autoReconnect=true with JDBC URL -My SQl itself does not recommend this, have a look at link and people have reported that this does not work as well, refer link.
  3. Custom handling -have your code identify that connection has been lost and then recover it and try to reconnect, but then it would be a lot of fail over mechanism in code.
  4. The best way I found was to configure pooling mechanism as c3p0. See this post how to configure c3p0 in JPA for hibernate, it’s simple, easy and reliable.

So how do you test that issue is solved?

  1. Change wait_timeout in MySql to just 2 minutes, this is how it can be done from MySql workbench admin console mysql_timeout
  2. Keep value of idleTestPeriod less than wait_timeout -A quick recap what idleTestPeriod signifies
  3. idleTestPeriod:  default value=0; If this is a number greater than 0, c3p0 will test all idle, pooled but unchecked-out connections, every this number of seconds
    
  4. Login after wait_timeout has passed -it should not throw a exception

Solving classloading issue while adding pooling support using c3p0 in JPA with hibernate underneath


I added c3p0 for pooling in JPA, but encountered an exception

Unable to load class [org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider]

My configuration looked like

<property name="hibernate.connection.provider_class"
          value="org.hibernate.connection.C3P0ConnectionProvider" />
<property name="hibernate.c3p0.max_size" value="10" />
<property name="hibernate.c3p0.min_size" value="0" />
<property name="hibernate.c3p0.acquire_increment" value="5" />
<property name="hibernate.c3p0.idle_test_period" value="60" />
<property name="hibernate.c3p0.max_statements" value="0" />
<property name="hibernate.c3p0.timeout" value="100" />	    

Details about these properties and other defined at link

Looking at log trace it’s not difficult to figure out that jar is not correct, so first change, upgrade to latest c3p0 artifact.

Previous

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>3.6.10.Final</version>
</dependency>

Latest

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>4.1.9.Final</version>
</dependency>

After changing this, it worked but printed an Warning

WARN - HHH000208: org.hibernate.connection.C3P0ConnectionProvider has been deprecated in favor of org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider; that provider will be used instead.

This indicates that provider_class should be changed to remove the depricated class, so it should be

<property name="hibernate.connection.provider_class"
          value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />

This cleanly integrated the c3p0 implementation.

How to log query parameters passed to JPA queries


I am using JPA with hibernate underneath. Using the property

<property name="hibernate.show_sql" value="true"/>

Shows just the SQL and not the values of parameters passed -it displays ? marks for query parameter as incomeexpe0_.transactiondate)>=?
Want to know what was the exact parameters passed -This is real helpful for debugging.
This can be achieved using hibernate logging -Add following two lines in your log4J.properties file

log4j.logger.org.hibernate.SQL=TRACE
log4j.logger.org.hibernate.type=TRACE

If this is used “log4j.logger.org.hibernate.SQL=TRACE” -No need to use property hibernate.show_sql, it wil take care of dumping queries.
The secondstatement, “log4j.logger.org.hibernate.type”, logs the JDBC parameters passed to a query

TRACE [main] (BasicBinder.java:83) - binding parameter [1] as [TIMESTAMP] - Thu Jan 03 01:00:18 IST 2013
TRACE [main] (BasicBinder.java:83) - binding parameter [2] as [TIMESTAMP] - Thu Jan 03 23:00:19 IST 2013

For even more advanced analysis and precise JDBC formatted queries (Non in an ORM form, but REAL sql), jdbc proxy driver like P6Spy can be used.

Data truncation exception while joining one to one in JPA


Lets say a class is having one to one relation ship with other entity, it looks like

public class StudentDetails implements Serializable{
    @OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER) 
    @Column(name="classid")
    private ClassDetails classId;
}

When I tried to save rows in the table, it threw an exception

javax.persistence.PersistenceException: org.hibernate.exception.DataException: Data truncation: Data too long for column 'classid' at row 1
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
}

What went wrong? When I looked at generated table the filed type for classid was LOB while I expected it to be an int (It just an ID from foreign key). The culprit is -using column instead of joincolumn

public class StudentDetails implements Serializable{
    @OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER) 
    @Column(name="classid")  
    private ClassDetails classId;

Instead of column, it should be join column

    @OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER) 
    @JoinColumn(name="classid",nullable=false) <strong> See the joincolumn </strong> 
	private ClassDetails classId;}

If join column is not specified, JPA assumes that ClassDetails object will be saved (along with its all nested graph) to DB and hence it creates a LOB type -telling it that its a joined foreign key resulted in a int data type for the field.

Fetching Nested collections in JPA


While coding in JPA with hibernate underneath I got an exception org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags. I was using “LIST” for the association and fetching eagerly

	@ManyToMany(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch = FetchType.EAGER)
	@JoinTable(name="class_subject", 
	joinColumns={@JoinColumn(name="classid")}, inverseJoinColumns=@JoinColumn(name="subjectid"))
	private List<SubjectDetails> subjects;

The problem seems to be two fold:

  1. JPA allows only two level of nesting for collection, Parententity->Childentity is fine but it does not allow Parententity->childentity->SubChildEntity
  2. Using List for collection instead of SET -remember a SET guarantees unique elements while list does not

What could be solution:

  1. Use SET instead of List and thats what I have done for the moment
	private SET<SubjectDetails> subjects;

  • Hibernate does allow, so we can use specific annotation but it will defy the whole purpose of using JPA
  • Review the model, instead of depending on Object graph to be fetched “Automagically” by ORM, can we move the logic in service layer and do the population as on need basis for required UI? And if you say it would throw lazy initialization because you have used session at DAO -Red Flag -its an anti pattern