Question on Persistence (Entity Beans, Hibernate, JDBC)

Hi everybody!

Until now, I have read a lot about persistence in the J2EE-sector, but I am still confused about which technology to used in my case.

I hope, that maybe you can give me some hints, by telling me which technology is good or bad regarding my requirements:

I want to build a customer- and order-management system fullfilling the following requirements:

1. The client is a Java application, the server is a JBOSS 4.0.1

2. The databasa scheme exists already and I'm not allowed to change it.

Some data, that logically belongs together and which shall be presented together to the client is distributed over 2 database tables.

3. The user cannot just create new and view data, but will also edit existing data quite often.

4. The user can assign products to an order. Often, there will be more than 1000 products assigned to an order, which will be presented to the user as a table (e.g. JTable). The user can then edit each cell of that 1000-row table, which of course will lead to an update in the db.

5. The user can also assign customers to a specific role in an order-process. On the other hand, each customer can make many orders.

So, we have a n:m relation here with the db-tables Customer, Order, OrderCustomer.

6. A complex search functionality has to be implemented, where the db-query is created dynamically at runtime.

7. The application is a multi-user application (about 10 users). It will be very rare, that users will work on the same data at the same time, but it might happen.

8. The database type (SAP DB) will not be changed in the near future.

With these 8 requirements in mind, I dealed a lot with EntityBeans, Hibernate and JDBC with SesseionBeans during the last 2 weeks.

Until now, I came to the following conclusions.

Hibernate is too slow. That'S bad, for data is edited very often and sometimes I want to edit just a single cell in 1000-row table.

Hibernate's biggest advantage - that it makes your application independent of the database type - is not even required (see point 8).

JDBC with SessioBeans: Very fast (I tried a simple query and it was about 10 times faster than Hibernate).

The disadvantage is, that I have to take care about all the transaction, concurrency control etc. things.

If I use JDBC, I want to do it that way: A SessionFacade accesses a DAO-object which executes the DB-query and returns the result to the SessionFacade which in the last step will pass the result to the client.

Entity Beans: I am completely confused with Entity Beans.

I read a lot about the CompositeEntity-Pattern for BMP. But on sun's J2EE Pattern page (http://java.sun.com/blueprints/corej2eepatterns/Patterns/CompositeEntity.html)

they said, that it's just useful when using the EJB 1.1 specification, because from EJB 2.0. the container or whatever will take care about lazy loading and store optimization.

So, from EJB 2.0. you should prefer using CMP-Beans with Container Managed Relationships (CMR), but as I heard, the dependent objects cannot be accessed and changed by the client when using CMPBeans with CMR.

However, a simple DB/Entity-mapping will not work in my case, because as mentioned above, there are thousands of products from the db to be managed at the same time. So here, I thought, the Composite pattern with its lazy loading strategy would be useful.

Furthermore, I have an n:m relationship in my database scheme, which is not trivial to map to entity beans. And don't forget that some related data is spread over 2 databse tables.

To sum it up, it would be very nice if some of you could clarify this perisistence nightmare, especially some clarification about if and how to use EntityBeans when having n:m relationships, editing data a lot, managing lots of table rows at once and having related data distributed over 2 database tables.

So, which technology would you prefer with the 8 requirements in mind? Hibernate, Entity Beans or JDBC with SessionBeans? Or would you prefer a mixed solution?

Thanx for every hint.

Regards,

egon

[4190 byte] By [Egona] at [2007-10-2 6:40:21]
# 1

> Hibernate is too slow.

Why do you think so ? Hibernate is not slow.

> Hibernate's biggest advantage - that it makes your

> application independent of the database type - is not

> even required (see point 8).

well..... I wouldn't say it's the biggest advantage.

> So, which technology would you prefer with the 8

> requirements in mind? Hibernate, Entity Beans or JDBC

> with SessionBeans? Or would you prefer a mixed

> solution?

Forget about entity beans. They are inappropriate for you'r requirements.

Pure JDBC makes development time too long.

Hibernate would be the best solution for you. It is even nicely integrated with JBoss. It also supports native SQL if you really need it.

Maris_Orbidansa at 2007-7-16 13:48:34 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 2
> > Hibernate is too slow. > > Why do you think so ? Hibernate is not slow. > I agree with Maris_Orbidans, it's not Hibernate, its you. Please post the appropriate sections of code, xml mappings and sql generated by hibernate.
MichaelW13a at 2007-7-16 13:48:34 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 3

Here the requested information about the test:

Goal:

Find all customers, who's branches have the String "Branch" in their name.

Both times, a simple client accesses the same SessionBean in a JBOSS-Container.

This Bean has 2 methods. One accesses the DB via Hibernate (executeCriteria), the other one via JDBC (executeCriteriaJDBC).

The code to count the seconds of computation is as follows:

long startTime = System.currentTimeMillis();

List customerList = bean.executeCriteria(dc);

System.out.println("Hibernate: "+((System.currentTimeMillis()-startTime)/1000.0f)+" sek");

startTime = System.currentTimeMillis();

List customerListJDBC = bean.executeCriteriaJDBC(query);

System.out.println("JDBC: "+((System.currentTimeMillis()-startTime)/1000.0f)+" sek");

HIBERNATE:

CODE:

Branch Branch = new Branch();

Branch.setName("%Branch%");

Example example = Example.create(Branch);

DetachedCriteria dc = DetachedCriteria.forClass(Customer.class)

.createCriteria("branches").add(example.enableLike()).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

QUERY:

select

this_.UUID as UUID1_1_,

this_.NAME as NAME1_1_,

this_.CUSTOMERNO as CUSTOMERNO1_1_,

this_.SHORTDESC as SHORTDESC1_1_,

this_.LONGDESC as LONGDESC1_1_,

this_.TAXNUMBER as TAXNUMBER1_1_,

this_.SALESTAXID as SALESTAXID1_1_,

this_.ACCOUNTHOLDER as ACCOUNTH8_1_1_,

this_.BANKACCOUNT as BANKACCO9_1_1_,

this_.BANKCODE as BANKCODE1_1_,

this_.BANKNAME as BANKNAME1_1_,

this_.AREA1TEXT as AREA12_1_1_,

this_.AREA2TEXT as AREA13_1_1_,

this_.AREA3TEXT as AREA14_1_1_,

this_.AREA4TEXT as AREA15_1_1_,

this_.AREA5TEXT as AREA16_1_1_,

this_.CH_UUID as CH17_1_1_,

this_.REFTEXT1 as REFTEXT18_1_1_,

this_.REFTEXT2 as REFTEXT19_1_1_,

this_.REFTEXT3 as REFTEXT20_1_1_,

branch1_.UUID as UUID0_0_,

branch1_.NAME as NAME0_0_,

branch1_.ILN as ILN0_0_,

branch1_.BRANCHID as BRANCHID0_0_,

branch1_.SHORTDESC as SHORTDESC0_0_,

branch1_.LONGDESC as LONGDESC0_0_,

branch1_.BAGSRECEIVED as BAGSRECE7_0_0_,

branch1_.CUSTOMER_UUID as CUSTOMER8_0_0_

from

CUSTOMER this_,

BRANCH branch1_

where

this_.UUID=branch1_.CUSTOMER_UUID

and (

branch1_.NAME like ?

)

RESULT:

Customername: Customer_A

Customername: Customer_F

Customername: Customer_D

Customername: Customer_R

Customername: Customer_S

TIME:

Hibernate: 1.343 sek

JDBC:

QUERY:

Select distinct c.* from Customer c, Branch b where b.id=b.Customer_id and b.name like '%Branch%'

// After getting the result of the query: Create a list of Customer-objects. Set all attributes of each Customer-object.

RESULT:

Customername: Customer_R

Customername: Customer_A

Customername: Customer_S

Customername: Customer_D

Customername: Customer_F

TIME:

JDBC: 0.125 sek

The Customer.hbm.xml (auto-generated in Eclipse with Middlegen)

<?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>

<!--

Created by the Middlegen Hibernate plugin 2.2

http://boss.bekk.no/boss/middlegen/

http://www.hibernate.org/

-->

<class

name="hibernate.hibernate.Customer"

table="CUSTOMER"

lazy="false"

>

<id

name="uuid"

type="java.lang.String"

column="UUID"

>

<generator class="assigned" />

</id>

<property

name="name"

type="java.lang.String"

column="NAME"

length="100"

/>

<property

name="customerno"

type="java.lang.Integer"

column="CUSTOMERNO"

length="5"

/>

<property

name="shortdesc"

type="java.lang.String"

column="SHORTDESC"

length="50"

/>

<property

name="longdesc"

type="java.lang.String"

column="LONGDESC"

length="100"

/>

<property

name="taxnumber"

type="java.lang.String"

column="TAXNUMBER"

length="50"

/>

<property

name="salestaxid"

type="java.lang.String"

column="SALESTAXID"

length="50"

/>

<property

name="accountholder"

type="java.lang.String"

column="ACCOUNTHOLDER"

length="50"

/>

<property

name="bankaccount"

type="java.lang.String"

column="BANKACCOUNT"

length="50"

/>

<property

name="bankcode"

type="java.lang.String"

column="BANKCODE"

length="50"

/>

<property

name="bankname"

type="java.lang.String"

column="BANKNAME"

length="50"

/>

<property

name="area1text"

type="java.lang.String"

column="AREA1TEXT"

length="50"

/>

<property

name="area2text"

type="java.lang.String"

column="AREA2TEXT"

length="50"

/>

<property

name="area3text"

type="java.lang.String"

column="AREA3TEXT"

length="50"

/>

<property

name="area4text"

type="java.lang.String"

column="AREA4TEXT"

length="50"

/>

<property

name="area5text"

type="java.lang.String"

column="AREA5TEXT"

length="50"

/>

<property

name="chUuid"

type="java.lang.String"

column="CH_UUID"

length="50"

/>

<property

name="reftext1"

type="java.lang.String"

column="REFTEXT1"

length="50"

/>

<property

name="reftext2"

type="java.lang.String"

column="REFTEXT2"

length="50"

/>

<property

name="reftext3"

type="java.lang.String"

column="REFTEXT3"

length="50"

/>

<!-- Associations -->

<!-- bi-directional one-to-many association to Branch -->

<set

name="branches"

lazy="true"

inverse="true"

cascade="all"

>

<key>

<column name="CUSTOMER_UUID" />

</key>

<one-to-many

class="hibernate.hibernate.Branch"

/>

</set>

</class>

</hibernate-mapping>

So, seems to me like Hibernate is also getting the data from the Branch-Table related to each Customer. Maybe this is the reason, why Hibernate is slower.

But as you can see in the mapping-File of the customer, I wanted Branches to be lazy loaded.

Do you have any ideas, why Hibernate is so much slower? Any hints for optimizing that code?

Do you have any further tricks to optimize Hibernate? Unfortunately I am not allowed to make changes at the database, so I cannot e.g. set indices for optimization.

However, I抦 a Hibernate-Newbie. In fact, I just made this test and was very disappointed about its result, so I didn抰 keep on working with Hibernate.

But maybe you can proof me, that Hibernate is a good choice. If so, do you have any good resources (links, books) that help working with Hibernate in connection with JBOSS, describe how to map n:m relationships, show how to work with large results and so forth?

Thanx for help,

egon

Egona at 2007-7-16 13:48:34 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 4

Sorry about the late reply, my employers actually expect me to work in December! Don't know what they're thinking...

I'll take a closer look tonight but:

Does it make a difference if the jdbc is run before the hibernate test?

Has hibernate loaded all the appropriate configuration files before the test is run?

Try using bag instead of set.

Have you tried using the hibernate query language instead of query by example.

Disclaimer: I'm also a hibernate noob.

MichaelW13a at 2007-7-16 13:48:34 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 5

Well, I swaped the hibernate and jdbc execution order, so JDBC is executed before Hibernate and vice versa. The result is the same. I also executed the method several times, which increases perfomrnace, but the gap in time is the same, because both methods execute faster.

Jboss finds and loads all hibernate files I put into the ear file (hibernate.properties, mapping-files and java-classes).

I used query by example, especially detached criterias, because I'm accessing hibernate from a remote client, who is not part of the hibernate-session. I read in tutorials that detached criterias are the only chance to work with hibernate from outside a hibernate session. Is there any other, better, faster way? By the way, which is the fastest kind of query? HQL? Query by example? createSQLQuery ()?

In my view, the problem is, that Hibernate automatically loads all the additional branch-information from the branch-table to each customer (see hibernate-sql-query in former post) . But I don't need the branch-details, so I would like to request only the data from the customer-table as I did in the JDBC-query (see selfmade jdbc-query in former post). How do I manage this with hibernate?

Remember, I set the relationship between customer and branch to "lazy", which I thought means, that branches are only loaded from the db on explicit client-request and not automatically when a customer is loaded.

So, what did I do wrong?

Regards,

Gregor

Egona at 2007-7-16 13:48:34 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 6

> But I don't need the branch-details, so I would like

> to request only the data from the customer-table as I

> did in the JDBC-query (see selfmade jdbc-query in

> former post). How do I manage this with hibernate?

Write you'r select in HQL.

Enable SQL logging to see generated SQL.

Maris_Orbidansa at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 7

>I read in tutorials that detached

> criterias are the only chance to work with hibernate

> from outside a hibernate session. Is there any other,

> better, faster way?

Normally you should use a Hibernate session.

Perhaps it's detached query that makes you'r select slow.

>By the way, which is the fastest

> kind of query? HQL? Query by example? createSQLQuery

> ()?

createSQLQuery - it's just an SQL query - the same thing you use via JDBC.

> Remember, I set the relationship betwee

n customer and

> branch to "lazy", which I thought means, that

> branches are only loaded from the db on explicit

> client-request and not automatically when a customer

> is loaded.

To have that you need to use Hibernate session and enable object proxy.

Maris_Orbidansa at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 8

> To have that you need to use Hibernate session and

> enable object proxy.

Probably a stupid question, but I couldn't find anything useful with google.:

How do I enable object proxy?

I just set lazy=true in the customer-mappingfile and I use Hibernate-sessions.

Maybe you can explain the proxy thing by taking the above example Customer-Branch, where one customer can have many branches. I want the customer object to load its branches (a Set) lazyly.

Thanx,

egon

Egona at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 9

> Write you'r select in HQL.

Alright, I tried the query with HQL and it is faster than the criteria-query. Now, Hibernate is just a little slower than JDBC.

But I have to implement a complex search for customers where the query is generated dynamically at runtime. This search may involve about 10 tables from my db as restriciton (in the where-clause), depending on what restrictions the user chooses in the UI. That's why I played around with CriteriaQueries, where I can easily pass Example-objects as restrictions. But still, the problem with my sample CriteriaQuery above was, that hibernate also queried the branches for each customer, altough I don't need the branch-information. That made the execution time slow. Can anybody help? Is there another way beside CriteriaQuery to create queries at runtime easily with Hibernate?

Maybe my problem - that the criteriaQuery also gets the branches from the db - has something to do with the question I posted above. How do I enable the proxy? How can I check, if my lazy loading works or not?

Thanx again everybody of you for help,

egon

Egona at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 10

> Probably a stupid question, but I couldn't find

> anything useful with google.:

Buy a book about HIbernate and read it instead of wasting time with google

of forums like this. PDF with Hibernate in Action costs only 22.50$. You probably spend on ice cream more daily.

http://www.manning.com/books/bauer

> How do I enable object proxy?

> I just set lazy=true in the customer-mappingfile and

Branch should be lazy.

From Hibernate in Action:

For a <many-to-one> or <one-to-one> association, lazy fetching is possible only if the associated class mapping enables proxying. For the Item class, we enable proxying by specifying lazy="true": <class name="Item" lazy="true">

Maris_Orbidansa at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 11
> Is there another way beside> CriteriaQuery to create queries at runtime easily> with Hibernate?No.But you can generate HQL queries dynamically. It's not very difficult either.
Maris_Orbidansa at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 12

> Buy a book about HIbernate and read it instead of

> wasting time with google

> of forums like this. PDF with Hibernate in Action

> costs only 22.50$. You probably spend on ice cream

> more daily.

>

> http://www.manning.com/books/bauer

It might be true for the OP. For me 22.50$ is around 10% of my pay. ;-)

lonesharka at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 13
> It might be true for the OP. For me 22.50$ is around> 10% of my pay. ;-)Are you from Belorussia or Ukraine ?
Maris_Orbidansa at 2007-7-16 13:48:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...