3

I have an application that has the following java files:

Services:

AccountService.java
UserService.java
MessageService.java

DAOs:

AccountDAO.java
UserDAO.java
MessageDAO.java

Tables:

ACCOUNTS
USERS
MESSAGES

In MessageService.java, I have a function newMessage() that has to query data from all the 3 tables.

(1) According to Spring's decoupling standards, this is how the calls should be made:

                     AccountDAO.java -- ACCOUNTS
                    /
MessageService.java -- MessageDAO.java -- MESSAGES
                    \
                     UserDAO.java -- USERS

But the problem is, this approach makes 3 DB calls.

(2) For better Performance, I would do:

MessageService.java -- MessageDAO.java -- Join ACCOUNTS, MESSAGES and USERS

But this way, it's tightly coupled and if there's a change in USERS table, I'll have to change MessageDAO.java (and all other DAOs that I have, that use the USERS table) too. That is really bad, since (in the non-hypothetical) we have a LOT of DAOs

Which approach is considered a better practice? Or is there another approach that I'm missing?

th3an0maly
  • 3,360
  • 8
  • 33
  • 54
  • What are you using as your underlying persistent implementation? Hibernate? JPA? Something else? – parsifal Oct 10 '12 at 19:44
  • 2
    The general answer is that there are ways around decoupling for special circumstances (thus the importance of knowing the persistence layer), but for most circumstances, it's best to let the framework manage the relationships. And with appropriate caching, it's probably less of a performance hit than you think. – parsifal Oct 10 '12 at 19:45
  • I'm using `org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate` to connect to my database – th3an0maly Oct 10 '12 at 19:45
  • 1
    So you're doing direct JDBC calls in all of your DAOs? Yeah, in that case I see the issue. Feel free to use a join in `MessageDAO` if that makes logical sense. It's what Hibernate or JPA would do if you defined relationships between the tables. – parsifal Oct 10 '12 at 19:52
  • @parsifal The issue with that approach is, there could be a lot of changes in the future and it will be difficult to make modifications if we couple things so strongly like this – th3an0maly Oct 10 '12 at 19:57
  • 3
    I would suggest, then, that you switch to using an ORM such as Hibernate, which will allow you to represent your logical design (which has a relationship between the objects) and handle the complexity of the physical design. Otherwise, this question becomes "how much maintenance pain is reasonable," and we can't answer that for you. – parsifal Oct 10 '12 at 20:04

4 Answers4

4

According to Spring's decoupling standards, this is how the calls should be made

This is false. There are no "decoupling standards" with Spring. Please find me a reference in the Spring documentation that tells you how you must structure your persistence layer code.

Typically, you would have one DAO for each "entity" that your application wants to operate on, but it would be foolish to take this pattern to the extreme of deconstructing a query that joins multiple tables together into three distinct queries.

If you need to have a newMessage() method that joins some tables together in a query, choose which DAO that makes the most sense in - probably the MessageDAO and write the query/method in the way that makes sense.

But there is no rule saying that you must have distinct queries for each entity and that one DAO class is not allowed to make queries that touch the tables of other entities. This is too extreme and has no benefit.

If one the other hand you are worried about the maintainability of having multiple data layer classes that are aware of all of your tables, then look into an ORM solution as parsifal mentioned to alleviate some of this work.

matt b
  • 138,234
  • 66
  • 282
  • 345
4

The alternative is to use an ORM such as Hibernate, mapping each of your tables to an entity. Then define the logical relationships between those entities. For example, a 1:M relationship between users and messages. As your tables change, your mappings will need to change, but your SQL won't (because Hibernate will generate it).

For most relationships, Hibernate is very good at creating joins to retrieve related entities in one query. You can control whether this happens; I recommend using lazy loads as a default for most relationships, and switching to eager loads as-needed.

parsifal
  • 226
  • 1
  • 2
2

Doing this as 3 separate queries might impact correctness if the data might change between one query and the next. Don't let (your idea of) Spring's guidelines make you write code that gets the wrong results.

It sounds like a join in SQL is the right approach.

Ricky Clarkson
  • 2,909
  • 1
  • 19
  • 21
1

Whichever method you follow, it's always about finding a sweet spot between decoupling and performance. It holds with even the selection of number of layers, etc.

So I guess as @mattb recommended, it's completely fine to join tables in a DAO if it makes sense in the particular context