java - 没有任何 ORM 的延迟加载/初始化设计模式

标签 java lazy-loading spring-jdbc

我使用 Spring JDBC 将数据从数据库加载到业务模型实体中。我的 DAO 接口(interface)由扩展 JdbcDaoSupport 类的类实现,这些类负责使用 RowMapper 类创建实体。 然后我有一个外观类,它包含所有 DAO 接口(interface)并充当请求业务实体的模型类(业务逻辑类)的网关。因为没有延迟加载,所有业务实体数据都是一次性加载的。这对大多数情况都很好,但在某些情况下我确实想从数据库中延迟加载数据。

例如,我从数据库中获取所有订单,并希望仅在日期满足特定条件(业务逻辑)时加载订单详细信息。这是我设计的一个简单示例。我正在寻找改进设计的方法,以便在需要时支持延迟加载订单详细信息数据。 您可以在业务逻辑类中看到,ProcessOrder 方法仅在订单日期为今天时才需要订单详细信息,否则不关心详细信息。但是,当通过外观类查询 Order 时,我的 DAO 加载了所有的 Order Details。

我理解的一种方法是在 DAO 和 Facade 类中公开 GetOrderDetails 方法,并允许业务逻辑类在需要时加载它。但是,它对我不起作用。我刚刚在这里提到了一个非常简单的案例,但可能存在业务对象被传递到另一个转换层的复杂场景,我不希望这些层负责加载数据的惰性部分。

此外,另一种可能性是使用 Hibernate 之类的 ORM 工具。然而,在我的应用程序中,这种情况可能只适用于极少数地方,并且感觉使用 ORM 工具来实现这种行为是一种矫枉过正。

我不是在寻找任何 super 花哨的东西,只是一个简单的设计来实现我的特殊情况。感谢您提供任何帮助/建议。

class Order // Simple POJO business entity
{
   int OrderID;
   Date OrderDate;
   Collection<OrderDetail> OrderDetails; // Need to load lazily
}

class OrderDetail //Simple POJO business entity
{
   Order order;
   int ItemID;
   double Cost;
   int Quantity;
}

// DAO Interface
interface OrderDAO
{
   Order getOrder(int aOrderID);
}

// Concrete DAO class
JdbcOrderDao extends JdbcDaoSupport implements OrderDao
{
   Order getOrder(int aOrderID)
   {
      Order order = getJdbcTemplate.query(....., new OrderRowMapper());
      populateOrderDetails(order);
      return order;
   }

   private PopulateOrderDetails(Order aOrder)
   {
      //Query the DB and fill the Order details data.
   }

   private class OrderRowMapper implements ParameterizedRowMapper<Order>
   {
      // Code implemented to create and return the business entity from the resultset;
   }
}

// Facade class that hides the DAO interface and exposes the business methods
ServiceFacade
{
   private OrderDAO orderDAO;

   public Order GetOrder(int aOrderID)
   {
      return orderDAO.getOrder(aOrderID);
   }
}

// Business Logic class
BusinessModelLoader
{
   List<Order> Orders = new ArrayList<Order>();
   LoadOrders()
   {
     for(Integer orderID : allOrderIDs)
       Orders.add(facade.getOrder(orderID));
   }

   ProcessOrders()
   {
      for(Order order: Orders)
      {
         if (order.OrderDate == Today)
         {
            List<OrderDetail> details = order.OrderDetails; // Need to perform lazy loading here automatically
            // Do something with details
         }
      }
   }
}

最佳答案

延迟获取背后的主要思想是定义如何获取数据而不是自己获取数据,这意味着当 order.getOrderDetails() 被调用时,正是应该触发查询的时间.实现这一点的一种方法是通过在本例中扩展 OrderRowMapper 中的模型来装饰 getOrderDetails() 方法,对于您的示例,它看起来像这样

class Order // Simple POJO business entity
{
    int OrderID;
    Date OrderDate;
    Collection<OrderDetail> OrderDetails; // Need to load lazily

    public void setOrderDetails(Collection<OrderDetail> orderDetails) {
        this.OrderDetails = OrderDetails;
    }

    public Collection<OrderDetail> getOrderDetails() {
        return OrderDetails;
    }

}

class OrderDetail //Simple POJO business entity
{
    Order order;
    int ItemID;
    double Cost;
    int Quantity;
}

// DAO Interface
interface OrderDAO
{
    Order getOrder(int aOrderID);
}

// Concrete DAO class
class JdbcOrderDao extends JdbcDaoSupport implements OrderDao
{
    Order getOrder(int aOrderID)
    {
        Order order = getJdbcTemplate().queryForObject("...", new OrderRowMapper(this));
        return order;
    }

    public void populateOrderDetails(Order aOrder)
    {
        //Query the DB and retrieve the order details
    }

    private class OrderRowMapper implements RowMapper<Order>
    {
        private JdbcOrderDao dao;

        public OrderRowMapper(JdbcOrderDao dao) {
            this.dao = dao;
        }

        @Override
        public Order mapRow(ResultSet rs, int rowNum) throws SQLException {
            Order order = new Order() {
                @Override
                public Collection<OrderDetail> getOrderDetails() {
                    dao.populateOrderDetails(this);
                    return super.getOrderDetails();
                }
            };
            // set other fields
            return order;
        }

    }
}


所以你的业务类现在会触发查询

// Business Logic class
class BusinessModelLoader
{
   List<Order> Orders = new ArrayList<Order>();
   LoadOrders()
   {
     for(Integer orderID : allOrderIDs)
       Orders.add(facade.getOrder(orderID));
   }

   ProcessOrders()
   {
      for(Order order: Orders)
      {
         if (order.OrderDate == Today)
         {
            Collection<OrderDetail> details = order.getOrderDetails(); // performs lazy loading here automatically
            // Do something with details
         }
      }
   }
}

关于java - 没有任何 ORM 的延迟加载/初始化设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13237863/

相关文章:

java - 如何在java中的JTextArea上添加JScrollPane?

java - Android studio 在 Intent 命中后崩溃

java - Kafka 不会均匀地填充主题中的分区

android - 在 ListView 中延迟加载图像

java - JDBC SQL 时区

java - 如何读取服务器文件并将其作为可下载文件在 XPage 的用户 Web 浏览器中输出

javascript - 延迟加载图像在 iPhone 浏览器中不起作用

javascript - jQuery.Lazy() : Plugin is not loading my 'li' contents

java - 参数未传递给过程

tomcat - 在嵌入式 Tomcat 中使用 Guice?