문제

I am new to Java and I'm trying to implement a basic database access layer. I'm using Apache DBUtils to reduce JDBC boilerplate code and this is working really well.

The problem is that my implementation uses a separate class for CRUD for each table in my database and it feels wrong to be duplicating so much functionality.

Is this an acceptable design and if not what can I do to reduce code duplication?
Could I refactor my solution to use generics in some fashion?

I realize I could use an ORM (myBatis, Hibernate etc) as a solution but I would like to try to stick with DBUtils and plain JDBC if I can help it.

Just for clarification:
Lets say I have 2 tables...

---------------------  
User    |  File  
---------------------  
userId  |  fileId  
name    |  path  
age     |  size  
---------------------  

In my current solution I would create 2 classes (UserStore, FileStore) and each class would implement similar basic CRUD methods:

protected boolean Create(User newUser)
{
    QueryRunner run = new QueryRunner(dataSource);
    try 
    {
        run.update("INSERT INTO User (name, age) " +
                "VALUES (?, ?)", newUser.getName(), newUser.getAge()); 
    }
    catch (SQLException ex) 
    {
        Log.logException(ex);
        return false;
    }
    return true;
}

protected User Read(int userId)
{
    try
    {
        User user = run.query("SELECT * FROM User WHERE userId = ? ", userId);
        return user;
    }
    catch (SQLException ex) 
    {
        Log.logException(ex);
        return null;
    }
}

protected update(User user)
{
    ... perform database query etc
}

protected delete(int userId)
{
    ... perform database query etc
}
도움이 되었습니까?

해결책

You asked how i would do this with Template method. Here is an example how you could do it:

public class AbstractDAO<T> {
private String table;
private String id_field;

public AbstractDAO(String table, String id_field){
this.table = table;
...
}

public T read(int id){
    try
{
    T user = run.query("SELECT * FROM "+ table + " WHERE "+id_field +" = ? ", id);
    return user;
}
catch (SQLException ex) 
{
    Log.logException(ex);
    return null;
}
}

This one looks easy, how about Create?

public boolean Create(T user){
    QueryRunner run = new QueryRunner(dataSource);
try 
{
    run.update("INSERT INTO "+table+ getFields() +
            "VALUES " + getParameters(user)); 
}
catch (SQLException ex) 
{
    Log.logException(ex);
    return false;
}

    return true;
}

protected abstract String getFields(); 
protected abstract String getParameters(T user);

Ugly, and insecure, but okay for transmitting the idea.

다른 팁

It looks like I can give you few simple suggestions for your question.

1)

Instead of managing queries inside DAOs like what you are doing, make a factory class that has list of queries for your needs.

like

class QueryFactory {
  static String INSERT_BOOK = "BLAH";
  static String DELETE_BOOK = "BLAH";
}

This will separate queries from DAO code and make it easier to manage.

2)

Implement a generic DAO

http://www.codeproject.com/Articles/251166/The-Generic-DAO-pattern-in-Java-with-Spring-3-and

3) As you have mentioned above, use ORM to help yourself binding beans to Database and many more features.

Using DBUtils you have already abstracted away a lot of boilerplate code. What remains is mostly the work that differs between entities : The right sql statement, transformation of entity objects into UPDATE parameters and vice versa with SELECTs, exception handling.

Unfortunately it is not easy to create a general abstraction that is flexible enough for these remaining tasks. That's what ORM mappers are all about. I would still suggest to look into one of these. If you stick to the JPA API, you are still in standards land and able to switch the ORM provider more easily (although there is always some coupling). I was impressed by SpringData's Repository abstraction. In simple use cases they give you zero code DAO's. If you are already using Spring and just want to persist your object model you should definitely look into it.

Alternatively I made some good experiences with jooq. It can also create DTO's and corresponding DAO's based on the tables in your schema. In contrast to ORM mappers it is closer to the relational schema, which may be an advantage or a disadvantage.

mybatis allows you to return a resulttype as hashmap:

<select id="mCount" resultType="hashmap"> select managerName, count(reportees) AS count from mgr_employee group by managerName; </select>

So you can effectively write out in a workflow like this: 1) Develop an interface 2a) Use mybatis annotation to define the query required OR 2b) Link the interface to a xml and write the query

Take note that this will not be involving any DAO and other boilerplates involve as above

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top