-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 
Author Message
 Post subject: dynamically select database schema with postgresql
PostPosted: Thu Sep 08, 2005 7:25 am 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
Hibernate version:3.0.5

Mapping documents:

Code between sessionFactory.openSession() and session.close():

Full stack trace of any exception that occurs:

Name and version of the database you are using: PostgreSQL 7.4.7

The generated SQL (show_sql=true):

Debug level Hibernate log excerpt:

Here is my issue. I have one database which is composed of n schema (each customer got one schema). Each time we have a new customer, we had a new schema to the database.
All schemas got the same DML (same table definition and all the other stuff).

Depending on which client connect to the web application, I want to connect to the appropriate schema. (equivalent to postgres SQL command : SET search_path TO customer1).

I want to be able to add new customer dinamically to the application, so no repackaging.

I want to share the same connection pool for all the customers.

I had a look at the documentation and the forums and did not find much informations. I tried to execute the "SET search_path TO customer1" directly into hibernate but it did not work using Query or SQLQuery.

Am I trying to do something which should not be done? Is there a way to execute this set command into hibernate?

http://forum.hibernate.org/viewtopic.ph ... ple+schema
http://forum.hibernate.org/viewtopic.ph ... ple+schema


Thanks for your help.
Damien


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 08, 2005 7:54 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
session.connection().createStatement("SET search_path TO customer1").execute();


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 08, 2005 8:30 am 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
thanks a lot for your answer.
here is what I have done.
The first request using JDBC retrieve the right informations but retrieving the information with hibernate did retrieve the information from the 'public' schema instead of the 'customer1' schema.
I guess that is probably due to something I misunderstand in the way hibernate works.
Why is hibernate still requesting the public schema? Does it has something to do with the Transaction?

Session session = null;
Transaction tx = null;
Configuration configuration = new Configuration();
SessionFactory sessionfactory = configuration.configure()
.buildSessionFactory();
session = sessionfactory.openSession();
Connection connection = session.connection();
tx = session.beginTransaction();
connection.prepareStatement("SET search_path TO public").execute();
PreparedStatement stnt = connection
.prepareStatement("select * from okorganisme;");
ResultSet rs = stnt.executeQuery();
while (rs.next()) {
logger.debug("result : " + rs.getString(1));
}
Criteria crit2 = session.createCriteria(Okorganisme.class);
List varorganisme = crit2.list();
for (Iterator it = varorganisme.iterator(); it.hasNext();) {
Okorganisme okorganisme = (Okorganisme) it.next();
logger.debug("okvarproperty id ["
+ okorganisme.getIdorganisme() + "] idokrs["
+ okorganisme.getIdokrs() + "]");
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 08, 2005 8:38 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Hibernate uses public shema because you set search_path to public in your code.

"connection.prepareStatement("SET search_path TO public").execute();"

Why do you use set to public shema and expect result from different shema ?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 08, 2005 8:55 am 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
you are right, my fault. I made a mistake copying my code.
It was a second test I made to test the result of the JDBC select.
Sorry for this.

The right code was indeed :
connection.prepareStatement("SET search_path TO customer1").execute();

here are the resulting logs:

...
result : sdfqsdfsd
...
okorganisme id [essai2] idokrs[essai2]
okorganisme id [essai] idokrs[essai]

In the database,

I indeed got one record in okorganisme in the 'customer1' schema and 2 records in the 'public' schema.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 08, 2005 1:07 pm 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
here is something new I found into hibernate logs :

19:04:34,218 DEBUG SQL:324 - select this_.idorganisme as idorgani1_0_, this_.idokrs as idokrs20_0_ from public.okorganisme this_

Apparently, hibernate forces the request to the public schema. Does someone know if this can be disabled?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 12, 2005 5:35 am 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
for people interested by this problem, I guess I found my error.

i did replace :
<class name="com.ok.docflow.database.Okorganisme" table="okorganisme" schema="public" lazy="false">

by :
<class name="com.ok.docflow.database.Okorganisme" table="okorganisme" lazy="false">

and now the generated hibernate SQL looks like this :

select this_.idorganisme as idorgani1_0_, this_.idokrs as idokrs20_0_ from okorganisme this_

which does not include any more schema.
I did not read carefully enough the xml definition of hibernate files and as I generated them directly from the database, I did not notice it included a schema specific field.

So now I am able to question the right schema into my database. I will do more tests to verify I can switch from one schema to another.
I am wondering if the hibernate cache system will work correctly with this tweak done on the connection. It is maybe caching data based on primary key.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 12, 2005 7:08 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
sauvaged wrote:
So now I am able to question the right schema into my database. I will do more tests to verify I can switch from one schema to another.
I am wondering if the hibernate cache system will work correctly with this tweak done on the connection. It is maybe caching data based on primary key.

Create session factory per shema to isolate factory level caches or do not use global cache. It is related to factory level cache only, session cache will work without problems, just do not reuse session (open a new session before to change shema)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 12, 2005 8:38 am 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
balakuis, thanks for answering again.

I guess you are right but I would like to avoid creating one session factory per client as I guess it will create n connection pools. As I might have hundreds of customer, I would prefer avoid having 200 or 300 connections to the databse.
As I am new to hibernate, I might misunderstand how connection pooling is working.
disabling the cache system would be an acceptable issue for me. I did a test but I guess I only disabled the second level cache.
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>
I guess the good answer is RTFM as I will probably find another cache to disable.

And doing so, my unit test is not working.
I connect to schema customer1
select using JDBC
select using hibernate
commit transaction
open new transaction
connect to schema public
select using JDBC
select using hibernate

the first 2 selects are ok. the second JDBC select is ok but the second hibernate select return the list from schema customer1 instead of schema public.

in the hibernate logs, I got :
select this_.idorganisme as idorgani1_0_, this_.idokrs as idokrs20_0_ from okorganisme this_
select this_.idorganisme as idorgani1_0_, this_.idokrs as idokrs20_0_ from okorganisme this_

that is why I guess a cache is acting here.

I even try with closing session and reopening one new.

here is my test :

Log logger = new TestLogger();
logger.debug("Executing Hibernate Test");
Session session = null;
Transaction tx = null;
try {
SessionFactory sessionfactory = new Configuration().configure().buildSessionFactory();
session = sessionfactory.openSession();
Connection connection = session.connection();
tx = session.beginTransaction();
connection.prepareStatement("SET LOCAL search_path TO customer1").execute();
PreparedStatement stnt = connection.prepareStatement("select * from okorganisme;");
ResultSet rs = stnt.executeQuery();
while (rs.next()) {
logger.debug("JDBC okorganisme id [" + rs.getString(1) + "] idokrs[" + rs.getString(2) + "]");
}
connection.prepareStatement("SET LOCAL search_path TO customer1").execute();
stnt = connection.prepareStatement("SHOW search_path");
rs = stnt.executeQuery();
while (rs.next()) {
logger.debug("SHOW search_path [" + rs.getString(1) + "]");
}
Criteria crit2 = session.createCriteria(Okorganisme.class);
for (Iterator it = crit2.list().iterator(); it.hasNext();) {
Okorganisme okorganisme = (Okorganisme) it.next();
logger.debug("HIBE okorganisme id [" + okorganisme.getIdorganisme() + "] idokrs["
+ okorganisme.getIdokrs() + "]");
}
tx.commit();
session.close();
session = null;
session = sessionfactory.openSession();
connection = session.connection();
tx = session.beginTransaction();
connection.prepareStatement("SET LOCAL search_path TO public").execute();
stnt = connection.prepareStatement("select * from okorganisme;");
rs = stnt.executeQuery();
while (rs.next()) {
logger.debug("JDBC okorganisme id [" + rs.getString(1) + "] idokrs[" + rs.getString(2) + "]");
}
connection.prepareStatement("SET LOCAL search_path TO customer1").execute();
stnt = connection.prepareStatement("SHOW search_path");
rs = stnt.executeQuery();
while (rs.next()) {
logger.debug("SHOW search_path [" + rs.getString(1) + "]");
}
crit2 = session.createCriteria(Okorganisme.class);
for (Iterator it = crit2.list().iterator(); it.hasNext();) {
Okorganisme okorganisme = (Okorganisme) it.next();
logger.debug("HIBE okorganisme id [" + okorganisme.getIdorganisme() + "] idokrs["
+ okorganisme.getIdokrs() + "]");
}
tx.commit();
} catch (Throwable ex) {
logger.debug("Throwable : " + ex.getMessage());
tx.rollback();
assertTrue(ex.getMessage(), false);
}
session.close();
assertTrue(true);


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 12, 2005 10:38 am 
Newbie

Joined: Mon Mar 15, 2004 5:41 am
Posts: 7
Location: France, Paris
sorry for this post I found the answer. the code is wrong as I was setting customer1 before hibernate select.
so it is working fine in fact.
thanks balukias


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.