• (cs)

    Self-styled database expert?

  • BB (unregistered)

    There's actually a point to disposing context if you insert many files when using EDMX, but not every time..

  • RFoxMich (unregistered)

    It goes to 11

  • Milan (unregistered)

    Maybe I'm wrong, but IMHO this code actually do what it supposed to do. AFAIK each driver fetch result set from database server in predefined chunks. Unless explicitly specified, driver should use default chunk size. For example Oracle fetch 10 rows.

    Also bonus points for closing resources. If not used in multithread environment, I would say it is not WTF, but a radically different approach.

    Though if code was designed with this behavior in mind is question. :)

  • Spike (unregistered)

    Better pattern; instead of populating a list, use a callback to process each item as you go. It basically gives the same result as the second block of code, but without any of the same threading and code cleanup issues. Plus if you still want to populate a list, you can provide a callback that does that instead.

  • palako (unregistered)

    Deal of the week, two WTFs in one! The "we've all written a DAO part", unless your library underneath provides some sort of cursor, is as WTF as the one you're making fun of.

  • (cs)
    In each he made all the variables static, along with some static variables to maintain state.
    It's not clear to me which variables this is talking about. The "static variables to maintain state" seems to refer to con, ps, and rs; so what are the "all the variables"?

    Should this be interpreted as meaning that the second code snippet is missing some anonymised lines saying

    private static String foo;
    private static int bar;
    // etc.
    and that the constructor stores its arguments in these static fields?

    If so, that's arguably a bigger WTF than any of the code that's actually shown. If not, what other variables is it talking about?

  • (cs)
    "But it's only reading one row at a time!"
    And I'm only going to punch your teeth out one at a time...
  • QJo (unregistered) in reply to palako
    palako:
    Deal of the week, two WTFs in one! The "we've all written a DAO part", unless your library underneath provides some sort of cursor, is as WTF as the one you're making fun of.
    con = connectionPool.getConnection();
    

    Where's the problem?

  • su (unregistered)

    We've all seen DAOs trying to fetch a million datasets in a object/array.

  • Didakos (unregistered)

    I have to say that, apart from using static variables for apparently no reason, I don't see the second code snippet as a worse WTF than the first. In many cases, rather than loading all the data from a dataset into a list/array, it's better to return the dataset object itself and iterate through it.

  • (cs) in reply to su
    su:
    We've all seen DAOs trying to fetch a million datasets in a object/array.
    Ah yes, but do the users of those DAOs then just pick the first ten items of the collection?
  • EvilSnack (unregistered)

    "We've all written a DAO:"

    Actually, some of us haven't, and not all of us are familiar with the acronym.

  • (cs) in reply to Didakos
    Didakos:
    I have to say that, apart from using static variables for apparently no reason, I don't see the second code snippet as a worse WTF than the first. In many cases, rather than loading all the data from a dataset into a list/array, it's better to return the dataset object itself and iterate through it.
    Actually, you're usually best off returning collection that is backed with a cursor so that you don't pull the data in until it is needed, together with some clever bits to disconnect (or realize) on transaction commit.
  • (cs) in reply to dkf

    issue there is that in java you need to know the size to be able to return a valid container (if you want to conform to the contract)

  • David Anthony Ottoman (unregistered) in reply to EvilSnack

    DAO: Data Access Object

  • su (unregistered) in reply to dkf

    sure... and fetch the million datasets again to pick the next ten items.

  • ¯\(°_o)/¯ I DUNNO LOL (unregistered)

    I think the best part of this code is how if you don't read all the results of the SELECT, there's no way to tell it to rewind.

    So you read rows 1-10, do something with them, and then return because you don't need any more rows. Then the next time through you start with row 11. Which is one row louder.

  • (cs)

    who wants to bet that he made those variables static because he (at one point) made the method static and he got a "can't access instance fields inside static method" error

  • (cs)

    ummm... who could I ask? Stack Overflow, they might give me a clue.

  • Paul M (unregistered)

    I see what he's trying to do, but the way to go about it is to extend ResultSet with a class whose "next" method returns the object, or a List object which - behind the scenes - uses a scrollable result set, maybe even some fancy-pants garbage-collectable reference objects.

  • JimmyCrackedCorn (unregistered)

    One common approach to the 'get x records from dataset' problem is to approach it from the sql select end:

    select * from sometable order by name limit 20,10

    This selects the 21st to the 30th rows (skip the first 20, give the next 10).

    Caching 10 records (or 100, or 1000) instead of the million record dataset can be a much more efficient approach.

  • trololo (unregistered) in reply to JimmyCrackedCorn
    JimmyCrackedCorn:
    One common approach to the 'get x records from dataset' problem is to approach it from the sql select end:
    select * from sometable order by name limit 20,10

    This selects the 21st to the 30th rows (skip the first 20, give the next 10).

    Caching 10 records (or 100, or 1000) instead of the million record dataset can be a much more efficient approach.

    True story

  • (cs) in reply to EvilSnack
    EvilSnack:
    "We've all written a DAO:"

    Actually, some of us haven't, and not all of us are familiar with the acronym.

    <looks at self> Yeah, I figured it was an Americanization of "TAO," like zen.

  • T.R. (unregistered)

    Apart from the fact that the resultset is static, the function still tries to build an entity and return it to the caller after the resultset has already been closed... and this would certainly throw an exception.

    I hope that, at least, the caller then checks if the object returned is not null.

  • T.R. (unregistered)

    My bad, I didn't see the return null statement... So I guess in a single-threaded environment, it kind of works, but then I don't see the benefit of using a method instead of simply inlining the code in the caller.

  • Anomaly (unregistered)

    "He created a dedicated DAO for each and every query."

    Presumably the code posted is copy/pasted with various queries in place of ("select ..."). This would create a dedicate dao for each and every query. Then SelectAllDAO or SelectTenDAO or SelectPreviousDAO classes/methods/abominations are created. These are static so that classes from the main program can access any query without needing a reference to each query directly. And without the need for each instance of the main application to create those instances.

    We have 500 users using a program. Instead of having those users create 500 different instances of the DAOs the server can handle the instances itself. Of course this could lead to bottlenecking or locking if two or more users try to use the same DAO at the same time.

    As for the use of nextrow only the code posted may only be for NextRowDAO. To "rewind" use PreviousRowDAO.

    Captcha jumentum //Not touching that one.

  • IT_Grunt (unregistered) in reply to ¯\(°_o)/¯ I DUNNO LOL
    ¯\(°_o)/¯ I DUNNO LOL:
    I think the best part of this code is how if you don't read all the results of the SELECT, there's no way to tell it to rewind.

    So you read rows 1-10, do something with them, and then return because you don't need any more rows. Then the next time through you start with row 11. Which is one row louder.

    I see what you did there! Nice one :-)

  • (cs) in reply to Milan
    Milan:
    Also bonus points for closing resources.
    Bonus WTF for not closing resources in a fucking finally-block or using Automated-Resource-Managment (the latter if you are already on JDK 1.7).
  • hrezs (unregistered) in reply to ratchet freak
    ratchet freak:
    who wants to bet that he made those variables static because he (at one point) made the method static and he got a "can't access instance fields inside static method" error

    and the method was static because he was testing it by running main?

    captcha: causa - causa don't know any better

  • Noone (unregistered) in reply to Milan
    Milan:
    AFAIK each driver fetch result set from database server in predefined chunks.

    Unless you use MySQL, in which case the default is to fetch the entire dataset before rs.next() even returns. You have to do some magic incantation to make it stream rows, and even then it only works if you have the right set of client, server, query type, and all sorts of craziness.

    How many times have I heard "but it works on my workstation" from developers, and then the code has an OutOfMemory error on the server because someone tries to fetch an n-table join all at once.

  • eVil (unregistered)

    TRWTF is using capital letters at the start of all words in the title of this article, so that people like me who hail from "Reading" now automatically mispronounce the word reading like their own home town.

  • (cs) in reply to ratchet freak
    ratchet freak:
    issue there is that in java you need to know the size to be able to return a valid container (if you want to conform to the contract)
    So just return an Iterator!
  • Me (unregistered) in reply to eVil
    eVil:
    TRWTF is using capital letters at the start of all words in the title of this article, so that people like me who hail from "Reading" now automatically mispronounce the word reading like their own home town.
    It's called "Title Case", and it's normal for titles and headings to use it.

    TRWTF is that reading[1] a very common typographical convention is now causing you to pronounce things incorrectly.

    [1] No pun intended, I swear

  • ANON (unregistered) in reply to JimmyCrackedCorn
    JimmyCrackedCorn:
    One common approach to the 'get x records from dataset' problem is to approach it from the sql select end:
    select * from sometable order by name limit 20,10

    This selects the 21st to the 30th rows (skip the first 20, give the next 10).

    Caching 10 records (or 100, or 1000) instead of the million record dataset can be a much more efficient approach.

    I think this just fetches 10 random rows and sorts them by name afterwards, because order by is done after limit.

  • Insensitive Claude (unregistered)

    Those who do not study set theory are doomed to slow queries.

  • Captain Wibble (unregistered)

    Ok, DBA, not really been a fecker (front end coder) for many years - but static variables? Am I wrong in thinking this could lead to some stunning data inconsistency wtfs? Or is this a single connection to the database?

  • aefgiogij (unregistered)

    It's the Duh of DAO.

  • (cs) in reply to eVil
    eVil:
    TRWTF is using capital letters at the start of all words in the title of this article, so that people like me who hail from "Reading" now automatically mispronounce the word reading like their own home town.
    Oh yeah, do we fuck.

    And now for the soccer results: "Reading One, Row at a Time." Oh do fuck off.

  • Meep (unregistered) in reply to QJo
    QJo:
    palako:
    Deal of the week, two WTFs in one! The "we've all written a DAO part", unless your library underneath provides some sort of cursor, is as WTF as the one you're making fun of.
    con = connectionPool.getConnection();
    

    Where's the problem?

    He never closes his connection, so with a few of these the connection pool will be used up.

  • Herp (unregistered)

    I've noticed that snoofle seems to have been taking the feedback on the comments section seriously and incorporating them into his articles. For instance, this story doesn't have a weird, convoluted background as many of the other ones do. I like that it gets right down to the WTF rather than having a long winded based-on-a-true-story lead in.

    Thanks, snoofle!

  • Jeff Grigg (unregistered)

    'When Jason pointed out that this is not the way to control how much data the server sends back at once, his colleague countered: "But it's only reading one row at a time!"'

    In fact, it doesn't. Databases typically send back several thousand rows at once. Doing a round-trip across to the database for every row would be very slow.

  • (cs) in reply to Jeff Grigg
    Jeff Grigg:
    'When Jason pointed out that this is not the way to control how much data the server sends back at once, his colleague countered: "But it's only reading one row at a time!"'

    In fact, it doesn't. Databases typically send back several thousand rows at once. Doing a round-trip across to the database for every row would be very slow.

    It boils down to perspective. From the perspective of the caller of that method it does "Read" one row at a time. That part is accurate. From the perspective of the database, the underlying connection object and everything else, yes, it does indeed grab it all.

    I've seen this type of code before, several times. I keep a list of names in case their resumes come across my desk.

  • JustSomeGuy (unregistered) in reply to trololo
    trololo:
    JimmyCrackedCorn:
    One common approach to the 'get x records from dataset' problem is to approach it from the sql select end:
    select * from sometable order by name limit 20,10

    This selects the 21st to the 30th rows (skip the first 20, give the next 10).

    Caching 10 records (or 100, or 1000) instead of the million record dataset can be a much more efficient approach.

    True story

    The problem with selecting rows like that (with limits) is that a data change (in the background) to rows you've already processed can cause you to either select the same row twice (someone inserts a row) or miss rows (someone deletes a row).

  • Norman Diamond (unregistered) in reply to Matt Westwood
    Matt Westwood:
    eVil:
    TRWTF is using capital letters at the start of all words in the title of this article, so that people like me who hail from "Reading" now automatically mispronounce the word reading like their own home town.
    Oh yeah, do we fuck.

    And now for the soccer results: "Reading One, Row at a Time." Oh do fuck off.

    "I came here for an argument"

    "No you didn't. And this isn't the capital."

    "One row at a time, please."

  • finally (unregistered)

    TRWTF is that DB objects are not closed in the finally block

  • JimmyCrackedCorn (unregistered) in reply to JustSomeGuy

    The hehavior will always like that unless you get all the records in the database with one query. This side effect may or may not be acceptable behavior for your business use case. For huge database queries, you may need to reconsider to leverage stored procedures.

  • JimmyCrackedCorn (unregistered) in reply to ANON

    I have used this technique with SQL Server with outstanding results. I didn't encounter this, but with other products YMMV.

  • Andrew (unregistered) in reply to JimmyCrackedCorn
    JimmyCrackedCorn:
    One common approach to the 'get x records from dataset' problem is to approach it from the sql select end:
    select * from sometable order by name limit 20,10

    This selects the 21st to the 30th rows (skip the first 20, give the next 10).

    Caching 10 records (or 100, or 1000) instead of the million record dataset can be a much more efficient approach.

    Bingo... That's exactly what I was thinking.

  • (cs) in reply to palako
    palako:
    Deal of the week, two WTFs in one! The "we've all written a DAO part", unless your library underneath provides some sort of cursor, is as WTF as the one you're making fun of.
    You know kid, some of us were writing code accessing DBs before you read Hibernate for Dummies, hell before it was even written!

Leave a comment on “But...It's Reading One Row at a Time!”

Log In or post as a guest

Replying to comment #:

« Return to Article