Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Monday, 7 August 2017

This week 13/2017 (Hibernate)

I will write about few details connected with hibernate which are not commonly known.
  1. *Any
  2. Lazy loading - not working in all cases as expected
  3. Eager loading -  list collections
  4. @MapsId
  5. FetchMode and graphs
  6. Default constructor
  7. Final attributes


Ad 1. 
It is rarely to find @Any or @ManyToAny relation in code. However it is useful when it is need to create relation with many class's types. Table referring to many types should have additional column which defines a related type. 

1
2
3
4
5
6
@AnyMetaDef(name= "Vehicle", metaType = "string", idType = "int",
    metaValues = {
            @MetaValue(value = "C", targetEntity = Car.class),
            @MetaValue(value = "M", targetEntity = Motor.class)
    }
)

In this case in additional column are archived C and M - value of meta. Vehicle which is a interface for this two classes Car and Motor is used as a type in related entity. Principle of operation is similar to hardly typed relations.

Ad 2.
Lazy loading for relations @*ToOne not always works as it could be expected. Everything is connected with assumption that it is needed to know if relation with current entity is empty or not. When the key of relation is situated in coupled table, it is required to call additional query to check if that relation exists or not. If there is a relation hibernate creates proxy if not, it leaves null value. If we assume that entity has always related object it is possible to set attribute optional to false. In this case hibernate always creates proxy.
Other solution for this problem is to change table for relation key or manipulate with LazyToOne annotation and doesn't create proxy, what is not required.

Ad 3.
It is not common but sometimes I meet in entities that to keep collection some people use List. It is not recommended because some queries can receive multiplied instance of one row, especially it is common when it is used eager fetch mode.
In case when one entity has more then one eager list collection, we get javax.persistence.PersistenceException during start-up.


Ad 4.
@MapsId is an annotation which makes relation key of as primary key. It looks better in db, especially when entity has embedded key.

Ad 5.
JPA 2.1 introduce new feature - entity graph. This feature allows to change featch mode in runtime. One what is required, it is needed to define some path of connections between entities and use this definition in Query as a hint. This feature was available before JPA 2.1 but it wasn't standardized, so each implementation resolved it in other way.
Bellow some example.  

1
2
3
4
5
6
@NamedEntityGraphs({
        @NamedEntityGraph(name = "graph.Index.countrySymbols",
                attributeNodes = {@NamedAttributeNode(value = "country"), @NamedAttributeNode(value = "symbols")}),
        @NamedEntityGraph(name = "graph.Index.country",
                attributeNodes = {@NamedAttributeNode(value = "country")})
})

This part of code is added to class and then used by @Hint("graph.Index.countrySymbols") annotation.
You can find more [ref. 3]

Ad 6.
Hibernate requires default constructor (even private). Even using spring 4+ and Hibernate 5.2 I've got exception:
Caused by: org.hibernate.InstantiationException: No default constructor for entity: entity.Bill. 
It is a little strange for me because problem with instance creation, which was common for cglib, was resolved in Spring 4+ so I expected it should involve jpa entities as well.

Ad 7.
Hibernate ignores final type of variable in entity, especially it is noticeable when entity has defined some collection, initialised by the way of declaration. Chosen in declaration HashSet is replaced by hibernate implementation PersistentSet.

Resources:

  1. https://stackoverflow.com/questions/37282850/hibernate-org-hibernate-loader-multiplebagfetchexception-cannot-simultaneousl
  2. https://stackoverflow.com/questions/13334831/multiplebagfetchexception-thrown
  3. https://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/
  4. https://martinsdeveloperworld.wordpress.com/2014/07/02/using-namedentitygraph-to-load-jpa-entities-more-selectively-in-n1-scenarios/
  5. https://stackoverflow.com/questions/17987638/hibernate-one-to-one-lazy-loading-optional-false
  6. https://vladmihalcea.com/2016/07/26/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

Saturday, 27 August 2016

This week 13/2016

This week I was creating a functionality. An independent service to export large part of data to MS Excel file and part of service which retrieve data from database. It is obvious that xls format can contain about 65 thousand of rows, so I decided to use xlsx format which I thought it is unlimited but about this it will be later. My requirement was to export from database to excel a large set of data and not kill application. 

First of all I focused on the output. The solution was to not use a XSSFWorkbook but SXSSFWorkbook. In my application currently I use old version of Apache POI v3.7 and there isn't implemented SXSSFWorkbook so in this case there is impossible to solve my problem. SXSSFWorkbook is available from v3.8.
However what I could do after I upgrade a libraries? I checked and it is possible to export huge part of data using less then 64MB heap memory.  The SXSSFWorkbook implementation can save simple data in a stream. Process of creating file is split into two phases. In the first phase implementation is saving processed data into temporary file (on linux it is /tmp/.... file). In the second phase temporary xml file is compressed with additional files containing styles and other information into final file.

By the way I found out that xlsx is not unlimited and every sheet can have maximum a little more then one million rows (2^20) and about 16 thousand columns (2^14).

After I had found out how to export large volume of data to xlsx I looking for solution how to retrieve data from database row by row. I'd like to separate input from output service. I created interface of DataProvider and injected there a RowMapper and other types used in NamedParameterStatement's query method but it doesn't work. Finally I used a ScrollableResultSet with Forward option and limitation of retrieved data at once and it works.


Saturday, 6 August 2016

This week 11/2016

This week I was interested in collecting statistic from my application. I have never been doing that and I think a few times, it could be helpful to resolve some problems. Currently there is other motivation - from it depends my half year premium.

Ok, so I have my Java application and what's next?
I can measure ex. how is used cache, heap memory, CPU and etc.
How can I get this information? 
I can log it to file or other adapter or I can serve it by JMX MBean. Logging to file takes hard drive memory and it can be weight. JMX works as JMS service but it's allow to change some application parameters and is light.

Anyway I started from log statistic in file. What I did?

JVM:
Everything about jvm memory and threads is in class ManagementFactory with static methods. Only you have to dump it to log. MBeans are by default registered in JMX Server too.
I didn't find counter of blocked threads and not dead locked, so I prepared my own method to update MBean as below.

        ThreadInfo[] infos = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
        int blocked = 0;
        for(ThreadInfo ti : infos){
            if(Thread.State.BLOCKED.equals(ti.getThreadState())){
                blocked++;
            }
        }
        mbean.setBlocked(blocked);


Hibernate statistic:
I had to add in configuration parameter hibernate.generate_statistics and than I could get Statistics interface and enable collecting statistic in SessionFactory.

statistics = sessionFactory.getStatistics();
statistics.setStatisticsEnabled(true);
All values are available in Statistics objec.

If you need JMX you have to registry Statistic object as MBean in JMX Server.



EHCache statistic
To get EHCache statistics it is required add statistics attribute to every cache container definition.
statistics="true"

 Then it is possible to get statistics from every cache managers.
I noticed when there is a few cache factories, it is needed to set them not shared. Only cache shared with hibernate should be shared. Otherwise I couldn't get to cache manager for hibernate. I saw only one which I defined in spring configuration.

When I had two different configurations, finally two cache managers. I had to share only one which was based on hibernate ehcache file. Others shouldn't be shared otherwise I couldn't get reference to hibernate cache manager.


By the way I will write how to registry your own MBean on your JVM. What you need is to get JMX service and register your MBean. MBean class have to implement interface with postfix MBean. All method included in interface are available from JMX console. Getters presents values, setters change it and other methods can be executed from jconsole. Example code is shown below.

    MyHello mbean = new MyHelloMBean();
    MBeanServer mbs =  ManagementFactory.getPlatformMBeanServer();
    ObjectName name = new ObjectName("com.example:type=Hello");
    mbs.registerMBean(mbean, name);