Thursday, September 30, 2010

Validation Query on WebSphere DataSource

Do you remember this?? (for those who have worked before with DBCP : validationQuery)

I was tired to look for this attribute in Websphere and I found it :P


Tip: On DB2 the equivalent to SELECT 1 FROM DUAL is SELECT 1 FROM SYSIBM.SYSDUMMY1

Monday, September 20, 2010

Pass Collection of Objects with Attributes to a Stored Procedure using iBatis

In my last entry I had a requirement which needed to pass a List to an Oracle Stored Procedure, well, that thing is history.
But now the problem becomes more complex, because, what happen if I'm expecting on my Stored Proc and Type (STRUCT)
This is my Collection in Oracle!
And this is my Stored Proc (this is just a sample which receives the TABLE of Records)
This is the table where I'm going to INSERT
Obviously, the solution is Create a Handler like I did on my last entry, but is not going to be as simple, because I need to Map my Oracle STRUCT with my Java Code, so I have to do an domain object (POJO) coupled to Oracle and my Handler.
Once we have our Mapper class, then let's do the Handler!!!
And this is how it looks my Map (XML)

In case you have to receive the Array from your Stored Proc, you just have to write in your Handler somethig like this:

References: Using iBatis with a stored function returning a Collection Type and Oracle UDT Collections as IN and OUT parameters with iBatis

Friday, September 17, 2010

Pass Collection to Stored Procedure using iBatis

Today I had a really crazy idea: "Why not making my query work with a list of parameters like I do with Hibernate using the operator IN???"
It sounds simple, Isn't it??? Ok, then try to do it with an Stored Procedure in Oracle :P
Then, this is my Stored Proc (I had to create a Type to have support for Arrays in Oracle, because an Array is not a simple-provided data type): As you can see, my dear visitor, I'm expecting some simple parameters and I'm returning a ResultSet, really straight forward, but the problem comes with the Array of NUMBER (that's why I created my
TYPE NUMBER_ARRAY AS TABLE OF NUMBER
)

The solution to this problem is easier than it seems, just create a Handler dude!!! The magic begins when I transform the Connection (because I have to work at the connection level) provided by the Application Server (WebSphere on this case - If this happens to me on another App Server or with another Connection Pool, I'm going to be in trouble, because the issue will be how to retrieve a Native java.sql.Connection, but that will be another story).
Let's analyze this monster:
* Get Native Connection
*Create my ArrayDescriptor for my Type (these NUMBER_ARRAY is my TYPE I created previously)
*Create my parameter, an ARRAY (al fin y al cabo) and we're set!

Finally this is my mapping file for my stored procedure

And my code lived happily ever after!!! Abur!!!

Friday, September 10, 2010

JDBC url for oracle RAC

If you have to connect to oracle RAC (Real Application Cluster) using JDBC with thin driver, the classic url:
jdbc:oracle:thin:@<HOST>:1521:<SID>
doesn’t work and you get the error ORA – 12505.
Instead, you must use this url:
jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=on)
(ADDRESS=(PROTOCOL=TCP)(HOST=host1) (PORT=1521))
(ADDRESS=(PROTOCOL=TCP)(HOST=host2) (PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=service)))
If you have an oracle client, like toad, check the tsnames.ora for the correct values of SERVICE_NAME and host.

Wednesday, September 8, 2010

Log SQL Statements on Hibernate

Hibernate, in the end, is all about dispatching SQL statements. SQL is at the heart of communication with an RDBMS system, and it is extremely important when struggling through performance problems or other bugs, that you know what is going on. After all, knowing the executed SQL allows you to determine the number of queries to complete an O/R mapping task, not to mention that seeing SQL queries is critical to understanding how to optimize the queries via indices and other database settings.
There are two ways (due to the legacy of Hibernate) to enable SQL logging. The first is to simply enable SQL logging in the Hibernate configuration By setting the hibernate.show_sql to TRUE

This is a nice quick and dirty solution, but it is relatively inflexible. SQL statements are always logged to System.out when that property is enabled, and on some servers, System.out isn't accessible by the average developer; or is cluttered with a million other log statements.

Alternatively, Hibernate uses the Apache-Jakarta Commons Logging package, which means that it will utilize log4j , java.util.logging , or potentially another logging framework. Typically, log messages are sent to commons logging, and then they are dispatched to one of these logging frameworks. Then, those logging frameworks determine where the message should be sent (log files, sockets, emails, database records, system out, system err, etc). It is easy to see how using these log frameworks will increase the flexibility of log statements. With Hibernate, simply setting the org.hibernate.SQL logger to 'DEBUG' or 'ALL' will ensure that all SQL statements are logged to the console.


If you set up a log4j category for org.hibernate.type
Get it to write out to the same log file as the org.hibernate.SQL
The type one will list the parameters for you after the SQL e.g.
2006-07-28 09:57:12,061 DEBUG org.hibernate.SQL - insert into BASKET_LINE_ALLOC (LAST_UPDATED, QUANTITY, CUSTOMER_REF, NOTES, BRANCH_ID, FUND_ID, TEMPLATE_ID, 
BASKET_LINE_ALLOC_ID) values (?, ?, ?, ?, ?, ?, ?, ?) 
2006-07-28 09:57:12,081 DEBUG org.hibernate.type.TimestampType - binding '2006-07-28 09:57:12' to parameter: 1 
2006-07-28 09:57:12,081 DEBUG org.hibernate.type.IntegerType - binding '3' to parameter: 2 
2006-07-28 09:57:12,082 DEBUG org.hibernate.type.StringType - binding '' to parameter: 3 
2006-07-28 09:57:12,082 DEBUG org.hibernate.type.StringType - binding '' to parameter: 4 
2006-07-28 09:57:12,082 DEBUG org.hibernate.type.LongType - binding '511' to parameter: 5 
2006-07-28 09:57:12,082 DEBUG org.hibernate.type.LongType - binding '512' to parameter: 6 
2006-07-28 09:57:12,082 DEBUG org.hibernate.type.LongType - binding null to parameter: 7 
2006-07-28 09:57:12,082 DEBUG org.hibernate.type.LongType - binding '180030' to parameter: 8 

@Autowired and @Qualifier

"Your best friends could be @Autowired and @Qualifier"
I have to migrate data from DB2 to Oracle, both databases have the same structure, well, my Oracle has better design, but I'm reusing the some objects, like POJO's and DAO's, the only thing I changed were my mappings, because I have to keep my mappings for DB2 and for Oracle.
If I have the same DAO for both databases, what can I do?
daoApplicationContext.xml
As you can see, I have 2 different DAO's sharing the same Interface & Implementation, but each one belongs to a different "sessionFactory" serviceApplicationContext.xml
Nothing special, right? But now here it comes the interesting part, because @Autowired by itself it will inject the given bean in your ServiceImpl, but you must have only one bean of that type. In my case I have more than 1, so @Autowired will throw an error when loading the context.
Then it comes @Qualifier which will match based on the given name, and problem solved chavos!!!

Notes: I used org.springframework.beans.BeanUtils to create a copy of my bean (pojo) returned from DB2 into a non-persistent Pojo which I'll manipulate before inserting into Oracle (DB2 completes each column value with spaces to achieve the given size of that column, so each time you query a DB2 column you'll get a lot of extra spaces)

Wednesday, September 1, 2010

EmbeddedId in Hibernate, AnnotatedClasses

I had to do some inserts to a table with a composite PK:



Nothing special, I decided to use Hibernate with annotations (but what about the PK: just create another class -duh, but How can I tell hibernate this is my PK? @EmbeddedId and @Embeddable):
@Embeddable
Defines my composite PK
@EmbeddedId
Includes my composite Pk in my main Pojo
If you want to include in your sessionFactory (daoApplicationContext.xml) my annotated pojos, add this entry
As a reminder, if you want to use a propeties file to provide parameter for your DataSource, you have to do this: