1

我正在 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

4 回答 4

2

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

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

于 2012-09-03T11:55:27.527 回答
2

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

你应该分开

  • 实体(只有 getter / setter 和可能的内部业务逻辑,根据您的整体模型,您可能也想将其分开)
  • 数据访问层:我将为您的每个实体提供接口ProductDao(然后,您可以使用您选择的技术(在您的情况下为 JDBC)具体实现这些。因此,如果以后您想更改数据访问技术,例如,您可以使用这些 (JdbcProductDaoHibernateProductDao) 的另一种实现。

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

这有很多好处:

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

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

于 2012-09-03T12:08:40.593 回答
1

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

  1. 在数据库和任何资源代码中添加一个 finally 块并在单独的 try-catch 中关闭每个连接(你只有 1 个),否则你会得到 con 泄漏
  2. 在数据库中:使用共享连接池
  3. 在产品 getById 中,如果产品正在被重用,将它们缓存在 HashMap 中,如果已经加载,则返回它,而不是每次都创建一个新对象。这取决于使用情况,但我们对许多具有 100 到 5,000 行的表执行此操作,并且偶尔会更改但会读取多次。
于 2012-09-03T11:57:57.640 回答
0

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

于 2012-09-03T12:01:00.537 回答