簡體   English   中英

Java SQL 多對多關系

[英]Java SQL Many to Many relationship

我在 MySQL 中有一個名為 Orders 的表,其中包含訂單的詳細信息。 我有另一個名為 OrderItems 的表。

OrderItems 包含以下字段:OrderID、ProductID、Qty

現在在 Java 中,我有一個名為 Order 的類,它有一個列表。

假設我想從我的數據庫中獲取所有訂單,包括每個訂單的訂單項。 但我想以最有效的方式做到這一點。

我目前的解決方案(我認為可能很慢)是:

循環遍歷行的 ResultSet 並定義 OrderDetails,每次循環遍歷一行時,我都會執行另一個 PreparedStatement 並使用當前訂單的 OrderID 循環遍歷 OrderItems。 然后我在列表中添加項目並轉到下一個訂單。

但我可以想象,這個過程會極其緩慢且資源密集。 什么是最有效的方法來做到這一點,同時仍然被歸一化(3NF)。

根據要求,我寫了一個解決方案的例子

public List<Order> getAllOrders() throws SQLException{
    ArrayList<Order> list = new ArrayList<Order>(0);
    ResultSet x = qry("Select * from Orders");
    while(x.next()){
        Order r = new Order();
        //setOrderDetails
        r.setItems(getOrderItems(r));       
    }
    return list;
}
public ArrayList<OrderItem> getOrderItems(Order r) throws SQLException {
    ArrayList<OrderItem> list = new ArrayList<OrderItem>(0);
    ResultSet x = qry("Select * from OrderItems where OrderID = "+r.getId()+";");
    while(x.next()){
        OrderItem  newItem = new OrderItem();
        newItem.setOrderId(r.getId());
        newItem.setProduct(null); //Uses some kind of inner join to get the product details
        newItem.setPrice(newItem.getProduct().getPrice());
        newItem.setQuantity(x.getInt(4));
    }
    return list;
}

好的,我已經按照你們的建議做了……平均仍然需要 20 多秒看起來如何

日志:

Time took to connect: 3270ms
Start CustomerService: 38ms
Start ProductService: 1ms
Start OrderService: 2ms
Customer Size: 4
Qry All Customers: 149ms
Products Size: 420
Qry All Products: 391ms
Order already contains: ENALAPRILMALEAAT HCT 20/12,5MG ACTAVIS BV
Add Order(28 items) Took: 2350ms
Qry all orders(27 orders) took: 7929ms

這真的很難......有時可能需要長達 20 秒。(查詢所有訂單)

這是另一個仍在計時 30 秒的訂單,僅可查詢 28 個訂單..(每個訂單最多 28 個項目

Time took to connect: 7117ms
Start CustomerService: 35ms
Start ProductService: 1ms
Start OrderService: 1ms
Customer Size: 4
Qry All Customers: 126ms
Products Size: 420
Qry All Products: 700ms
Add Order(6 items) Took: 2117ms
Qry all orders(28 orders) took: 30150ms

在我看來,您的數據(每周 4 個新訂單的 600 種產品)並不大,您現在應該需要進行性能優化。 但是如果你應該,你可以優化它,如果你的代碼看起來像下面這樣(我只是稍微修改了你的代碼):

public List<Order> getAllOrders() throws SQLException{
   ArrayList<Order> list = new ArrayList<Order>(0);
   PreparedStatement ps = connection.prepareStatement("Select * from OrderItems where OrderID = ?");        // (1)
   ResultSet x = qry("Select * from Orders");
   while(x.next()){
       Order r = new Order();
       //setOrderDetails
       r.setItems(getOrderItems(r, ps));
       list.add(r);    
   }

   return list;
}

public ArrayList<OrderItem> getOrderItems(Order r, PreparedStatement ps) throws SQLException {
    ArrayList<OrderItem> list = new ArrayList<OrderItem>(0);
    ps.setString(1, r.getId());       // (2)
    ResultSet x = ps.executeQuery();  // (3)
    while(x.next()){
        OrderItem  newItem = new OrderItem();
        newItem.setOrderId(r.getId());
        newItem.setProduct(null); //Uses some kind of inner join to get the product details
        newItem.setPrice(newItem.getProduct().getPrice());
        newItem.setQuantity(x.getInt(4));
    }
    return list;
}

現在發生了什么變化?

  1. 准備好的語句現在已退出循環,它將被重用(請參閱更改 (1))。 與之前准備好的查詢相比,這應該會帶來巨大的性能提升,因為查詢只會被解析一次。

  2. 在 (2) 中,將為當前訂單設置參數。

  3. 在 (3) 中,將執行查詢。

這是一個遲到的答案,但對於那些查詢時間很慢的人來說。 嘗試將自動提交設置為 false。 在代碼中實際創建連接時,執行 connection.setAutoCommit(false); 然后在代碼中放入 connection.commit(); 執行查詢后。 我在嘗試插入 150000 個對象時遇到了同樣的問題,這需要大約 23 分鍾。 將自動提交設置為 false 然后提交后,我花了大約 27 秒。 我希望它有幫助。

這是提交的代碼示例:

@Override
public void create(Member member) {
    try {
        Connection connection = localConnection.getConnection();
        PreparedStatement sqlInsert = connection.prepareStatement(memberDaoUtil.create());

        sqlInsert.setString(1, member.getMemberId());
        sqlInsert.setString(2, member.getName());
        sqlInsert.setString(3, member.getPersonalNumber());
        sqlInsert.setString(4, member.getUsername());
        sqlInsert.setString(5, member.getPassword());
        sqlInsert.setInt(6, member.getNumOfBoats());
        sqlInsert.setBoolean(7, member.isAdmin());

        sqlInsert.executeUpdate();
        connection.commit();
        sqlInsert.close();

    } catch(SQLException ex) {
        ex.printStackTrace();
    }
}

然后也在連接的構造函數中:

private LocalConnection(Connection connection) {
    this.connection = connection;
    try {
        connection.setAutoCommit(false);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

你可以看到 connection.setAutoCommit(false); 您可以在下面的鏈接中閱讀它的作用。 了解自動提交

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM