是否可以在不使用反射的情况下在Java中编写简单的通用DAO?

时间:2012-09-03 11:46:02

标签: java reflection dao genericdao

我正在开发Java 6(及更高版本)中的玩具数据访问机制。每个模型类都应该有一个findById静态方法,该方法应该从具有指定id的行中实例化一个对象。我想出了下面显示的方法。我的方法被认为是好的做法吗?如果没有,可以改进什么?

数据库(MySQL)引导脚本:

create database test;
create user test identified by 'test';
grant all on test.* to test;
use test;
create table products(id integer,name varchar(10));
insert into products values(1,'led');

源代码:

import java.sql.*;

class Test {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.jdbc.Driver");
        Product p = Product.findById(1);
        System.out.println(p.id + " " + p.name);
    }
}

class Database {
    static <T extends Model<T>> T findById(T m, String sql, int id) throws SQLException {
        try (Connection conn = DriverManager.getConnection("jdbc:mysql:///test", "test", "test");
                PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setInt(1, id);
            try (ResultSet rs = stmt.executeQuery()) {
                rs.next();
                m.load(rs);
            }
        }
        return m;
    }
}

abstract class Model<T> {
    abstract void load(ResultSet rs) throws SQLException;
}

class Product extends Model<Product> {
    int id;
    String name;

    static Product findById(int id) throws SQLException {
        return Database.findById(new Product(), "select * from products where id=?", id);
    }

    @Override
    void load(ResultSet rs) throws SQLException {
        this.id = rs.getInt("id");
        this.name = rs.getString("name");
    }
}

4 个答案:

答案 0 :(得分:2)

我宁愿使用基于DAO的方法。您需要使用基本的CRUD方法创建一个GenericDao<T>类,并且所有派生的DAO类都将具有指定实体类的开箱即用CRUD功能。

这里有两篇展示所描述技术的文章: http://www.codeproject.com/Articles/251166/The-Generic-DAO-pattern-in-Java-with-Spring-3-and http://www.ibm.com/developerworks/java/library/j-genericdao/index.html

答案 1 :(得分:2)

您正在混淆顾虑和责任,在您的实体(Product)和数据访问层之间引入紧密耦合。

你应该分开

  • 实体(只有getter / setter和可能的内部业务逻辑,根据您的整体模型,您可能也希望将其分开)
  • 数据访问层:我将为每个实体(ProductDao)提供接口,以及要执行的方法来检索/存储/删除实体。然后,您可以使用您选择的技术(在您的情况下为JDBC)具体实现这些。因此,如果您以后想要更改数据访问技术,则可以使用其他实现(JdbcProductDaoHibernateProductDao)。

您甚至可能希望更进一步,并将DAO层与实际存储库层分离,但这可能被视为过早优化,具体取决于系统中不同实体类的数量。

这有很多好处:

  • 光耦合整体设计更好
  • 更好的可测试性等。

此外,尝试在任何地方使用通用方法并不一定是个好主意:通常你会发现你想要的findById对于你的每个实体都略有不同,其中一些不适合你在Database中描述的泛型方法(我甚至没有提到它是一种静态方法,这是一种难闻的气味)。在我现在的团队中,我们使用三个规则:只有当你编写系统中可以从中受益的第三个元素时,才会引入重构的泛型类/方法。另外我们认为它过早优化。

答案 2 :(得分:1)

我喜欢基本设计。但是对于一个真正的生产项目,我会做3个改变:

  1. 在数据库和任何资源代码中添加一个finally块并关闭每个连接(您只有1个)在单独的try-catches中,否则会出现con泄漏
  2. 数据库中的
  3. :使用共享连接池
  4. 产品getById中的
  5. 如果产品正在重复使用,则将它们缓存在HashMap中,如果已经加载,则返回,如果每次都创建一个新对象。这取决于使用情况,但是我们为很多有100到5,000行的表做了这些表,偶尔会有更改但是多次读取。

答案 3 :(得分:0)

您正在重新发明对象关系映射(ORM)和数据访问对象(DAO)方法。存在许多Java库,它们完全按照您在此处执行的操作,例如Hibernate。我想你可能会发现这个库比得到这个问题的正确答案更有用。

相关问题