Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Saturday, January 30, 2016

Spring Framework: Confusions of RowCallbackHandler

I have had some time not writing my blog. Mainly because my previous employer doesn't allow me to access blogspot during the work hour - also I kind of ran out of topics. I would like to write something that is advanced, not only just tutorials. You can find some many entry-level materials repeating each other, but many times, you'll struggle too long when facing a deeper issue. At least I struggled so many times.

Anyway, I tried to restart blogging. And today's topic is about RowCallbackHandler interface in Spring framework.

You can find many tutorials/samples that suggesting you write program as below:

public class RowCallbackTutorial {
    private DataSource dataSource;
    public void query(String sql) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.query(sql, new RowCallbackHandler(){
            public void processRow(ResultSet rs) throws SQLException {
                System.out.println("Inside RowCallbackHandler");
while ( rs.next() ) { System.out.println("Got value:" + rs.getObject(1)); } } }); } }
This actually is not right. Mentioned in the Java doc of this interface, method processRow "should not call next() on the ResultSet" - I guess they mean "should not call the next() on the first row of the ResultSet", since the ResultSet has already opened and pointing to first row when this method is called.

Here is a test using Spring embedded database support.

First we prepare a sql script to create table and insert a few rows, "db/init.sql". I have:
    CREATE TABLE customer (
        id         INTEGER PRIMARY KEY,
        name       VARCHAR(30)
    );

    insert into customer values(1, 'cust1');
    insert into customer values(2, 'cust2');
Then we test with the data.

    public static void main(String[] args) {
        EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.DERBY)
        .addScript("db/init.sql")
        .build();
        String sql = "select * from customer";
        RowCallbackTutorial sample = new RowCallbackTutorial();
        sample.setDataSource(db);
        sample.query(sql);
    }
We're expecting the program to output:
    Got value:1
    Got value:2
In fact, the previous program will only show second row: Got value:2. Where is the first row?

The ResultSet has already opened, and the cursor is pointing to first row. The first "next()" will move the cursor to next row. So the correct operation should be:
                do {
                    System.out.println("Got value:" + rs.getObject(1));
                }  while ( rs.next() );
And run the program again, we now get the correct result:
    Got value:1
    Got value:2
Now here is the last question. What if the ResultSet is empty? Will "do {...} while ()" encounter any error?

The answer is, no problem. In such case, the RowCallbackHandler will not be invoked at all. Change the query to "select * from customer where 1=2" for a new test, the output "Inside RowCallbackHandler" will not appear.

Wednesday, October 24, 2012

Another program to find hot threads in Java VM

Many people know the GUI tools, such as jconsole and JTop, and maybe jvisualvm in latest JDK releases, to monitor and analyze JVM performance.

The tools jconsole together with JTop can be used to indentify threads that take most of the CPU usage. However, they work under GUI environment. In case you work in UNIX, without XServer, plus you don't have the JMX agent started, you may not have such luxury. It may be rare, but did happen in my case: HP UX, no XServer, cannot be attached to another XServer due to production firewall, the JMX agent is not started. Anyway, it's very frustrating.

Here's a tool can benefit the above case: http://weblogs.java.net/blog/brucechapman/archive/2008/03/hot_threads.html. It takes a process id as input, and prints top threads that take most of the CPU usage. In HP UX environemnt, I have to include tools.jar in the classpath:

    ${JAVA_HOME}/bin/java -Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar -jar HotThread.jar 

Without tools.jar, it gives error that "java.lang.NoClassDefFoundError: com/sun/tools/attach/VirtualMachine".
Tried this in development environment, but didn't have chance to try it in production, due to lengthy procedures. Sigh...