We have seen three of the inheritance techniques as of yet.This is the fourth in the series.
Table per subclass
In this technique a table is created for every class in the hierarchy. There exists a separate table for every interface/abstract class/concrete class that has any persistent properties.
The above logs indicate the creation of 3 different tables.
As can be seen the common properties (including the identifier) are present in the SPORTS_PERSON table. The other tables hold foreign key relations to this primary key.
Each table holds the properties specific to its own type thus ensuring a very normalized schema. It is now also possible to enforce nullabilty constraints as each sub class has its own table. Adding a new subclass is as simple as creating a new table with similar foreign key relations. The existing code is not affected.
The queries in the logs indicate the use of inner joins to fetch the complete record for a Cricketer. Also the inserts involve creation of records in two tables. The performance in this approach is certainly not the best. For example the code to create a footballer is as below:
Update: For a brief summary of the Hibernate Inheritance types check this post.
Table per subclass
In this technique a table is created for every class in the hierarchy. There exists a separate table for every interface/abstract class/concrete class that has any persistent properties.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.inheritance.model"> <class name="SportsPerson" table="SPORTS_PERSON"> <id name="id" type="long"> <column name="ID" /> <generator class="native" /> </id> <property name="name" type="string" column="NAME" /> <joined-subclass name="Cricketer" table="CRICKETER"> <key column = "CRICKETER_ID" /> <property name="runs" type="integer" column="RUNS" /> <property name="wickets" type="integer" column="WICKETS" /> <property name="t20Player" type="boolean" column="T20_PLAYER" /> </joined-subclass> <joined-subclass name="Footballer" table="FOOTBALLER"> <key column = "FOOTBALLER_ID" /> <property name="goals" type="integer" column="GOALS" /> <property name="appearances" type="integer" column="APPEARANCES" /> <property name="sendOffs" type="integer" column="SEND_OFFS" /> </joined-subclass> </class> </hibernate-mapping>
On start up the SQL generated is as below:
922 [main] INFO org.hibernate.cfg.HbmBinder - Mapping class: com.inheritance. model.SportsPerson -> SPORTS_PERSON ... 1062 [main] INFO org.hibernate.cfg.HbmBinder - Mapping joined-subclass: com.in heritance.model.Cricketer -> CRICKETER ... 1078 [main] INFO org.hibernate.cfg.HbmBinder - Mapping joined-subclass: com.in heritance.model.Footballer -> FOOTBALLER 2594 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ver sion select: select ID from SPORTS_PERSON where ID =? 2594 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ins ert 0: insert into SPORTS_PERSON (NAME, ID) values (?, ?) 2594 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Upd ate 0: update SPORTS_PERSON set NAME=? where ID=? 2609 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Del ete 0: delete from SPORTS_PERSON where ID=? 2625 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Sna pshot select: select cricketer_.CRICKETER_ID, cricketer_1_.NAME as NAME0_, crick eter_.RUNS as RUNS1_, cricketer_.WICKETS as WICKETS1_, cricketer_.T20_PLAYER as T4_1_ from CRICKETER cricketer_ inner join SPORTS_PERSON cricketer_1_ on cricket er_.CRICKETER_ID=cricketer_1_.ID where cricketer_.CRICKETER_ID=? 2625 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ins ert 1: insert into CRICKETER (RUNS, WICKETS, T20_PLAYER, CRICKETER_ID) values (? , ?, ?, ?) 2625 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Upd ate 1: update CRICKETER set RUNS=?, WICKETS=?, T20_PLAYER=? where CRICKETER_ID=? 2625 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Del ete 1: delete from CRICKETER where CRICKETER_ID=? ...[similar queries for footballer] 3094 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table CRICKETER ( CRICKETER_ID bigint not null, RUNS integer, WICKETS integer, T20_PLAYER bit, primary key (CRICKETER_ID) ) 3094 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table FOOTBALLER ( FOOTBALLER_ID bigint not null, GOALS integer, APPEARANCES integer, SEND_OFFS integer, primary key (FOOTBALLER_ID) ) 3109 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table SPORTS_PERSON ( ID bigint not null auto_increment, NAME varchar(255), primary key (ID) ) 3109 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - alter table CRICKETER add index FKA046883E7573CC6 (CRICKETER_ID), add constraint FKA046883E7573CC6 foreign key (CRICKETER_ID) references SPORTS_PERSON (ID) 3125 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - alter table FOOTBALLER add index FK6B92FCDAEDEE02CA (FOOTBALLER_ID), add constraint FK6B92FCDAEDEE02CA foreign key (FOOTBALLER_ID) references SPORTS_PERSON (ID) 3172 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - schema export compl ete
The above logs indicate the creation of 3 different tables.
As can be seen the common properties (including the identifier) are present in the SPORTS_PERSON table. The other tables hold foreign key relations to this primary key.
Each table holds the properties specific to its own type thus ensuring a very normalized schema. It is now also possible to enforce nullabilty constraints as each sub class has its own table. Adding a new subclass is as simple as creating a new table with similar foreign key relations. The existing code is not affected.
The queries in the logs indicate the use of inner joins to fetch the complete record for a Cricketer. Also the inserts involve creation of records in two tables. The performance in this approach is certainly not the best. For example the code to create a footballer is as below:
private static void createFootballer() {
Footballer footballer = new Footballer();
footballer.setAppearances(5);
footballer.setName("Tom Cleaverly");
footballer.setGoals(3);
footballer.setSendOffs(0);
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
session.save(footballer);
t.commit();
}
The logs generated for the creation is as below:3906 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - executing identity-insert immediately 3906 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Inse rting entity: com.inheritance.model.Footballer (native id) 3906 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedSt atement (open PreparedStatements: 0, globally: 0) 3922 [main] DEBUG org.hibernate.SQL - insert into SPORTS_PERSON (NAME) values (?) ... 3938 [main] DEBUG org.hibernate.id.IdentifierGeneratorFactory - Natively genera ted identity: 1 3953 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Inse rting entity: [com.inheritance.model.Footballer#1] 3953 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedSt atement (open PreparedStatements: 0, globally: 0) 3953 [main] DEBUG org.hibernate.SQL - insert into FOOTBALLER (GOALS, APPEARANCES, SEND_OFFS, FOOTBALLER_ID) values (?, ?, ?, ?)
I also executed a query from the previous example
Query query = session.createQuery("from Footballer f where f.name like 'Tom%'");
The logs indicate the execution:937 [main] DEBUG org.hibernate.SQL - select footballer0_.FOOTBALLER_ID as ID0_, footballer0_1_.NAME as NAME0_, footballer0_.GOALS as GOALS2_, footballer0_.APPEARANCES as APPEARAN3_2_, footballer0_.SEND_OFFS as SEND4_2_ from FOOTBALLER footballer0_ inner join SPORTS_PERSON footballer0_1_ on footballer0_.FOOTBALLER_ID=footballer0_1_.ID where footballer0_1_.NAME like 'Tom%'
Even a simple query to fetch a Footballer involved the join between two tables. As the complexity increases, there could be a considerable degradation of performance.
Update: For a brief summary of the Hibernate Inheritance types check this post.
No comments:
Post a Comment