如何减少数据库访问层中的代码重复?

时间:2013-05-13 08:51:04

标签: java sql database generics dao

我是Java的新手,我正在尝试实现基本的数据库访问层。 我正在使用Apache DBUtils来减少JDBC样板代码,这非常有用。

问题是我的实现为我的数据库中的每个表使用一个单独的CRUD类,并且复制这么多功能感觉不对。

这是否是可接受的设计,如果不能,我该怎么做才能减少代码重复? 我可以重构我的解决方案以某种方式使用泛型吗?

我意识到我可以使用ORM(myBatis,Hibernate等)作为解决方案,但我想尝试坚持使用DBUtils和普通JDBC,如果我能帮助它的话。

只是为了澄清:
可以说我有两张桌子......

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

在我目前的解决方案中,我将创建2个类(UserStore,FileStore)和 每个类都将实现类似的基本CRUD方法:

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
}

4 个答案:

答案 0 :(得分:0)

看起来我可以为您的问题提供一些简单的建议。

1)

不要像你正在做的那样管理DAO中的查询,而是创建一个包含查询列表的工厂类。

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

这会将查询与DAO代码分开,并使其更易于管理。

2)

实施通用DAO

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

3)如上所述,使用ORM帮助自己将bean绑定到数据库以及更多功能。

答案 1 :(得分:0)

使用DBUtils已经抽象出了大量的样板代码。剩下的主要是实体之间不同的工作:正确的sql语句,将实体对象转换为UPDATE参数,反之亦然,使用SELECT,异常处理。

不幸的是,为这些剩余的任务创建足够灵活的通用抽象并不容易。这就是ORM地图制作者的全部意义所在。我仍然建议调查其中一个。如果您坚持使用JPA API,那么您仍然处于标准状态,并且能够更轻松地切换ORM提供程序(尽管总有一些耦合)。 SpringData的Repository抽象给我留下了深刻的印象。在简单用例中,他们为您提供代码DAO。如果您已经在使用Spring,并且只想坚持您的对象模型,那么您一定要查看它。

或者我用jooq做了一些很好的经历。它还可以根据模式中的表创建DTO和相应的DAO。与ORM映射器相比,它更接近关系模式,这可能是一个优点或缺点。

答案 2 :(得分:0)

您问我将如何使用Template方法执行此操作。这是一个如何做到的例子:

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;
}
}

这个看起来很简单,怎么样?

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);

丑陋且不安全,但可以传达这个想法。

答案 3 :(得分:0)

mybatis允许您将结果类型作为hashmap返回:

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

所以你可以在这样的工作流程中有效地写出来: 1)开发界面 2a)使用mybatis批注定义所需的查询OR 2b)将接口链接到xml并编写查询

请注意,这不涉及任何DAO和其他涉及如上所述的模板