发表于: 2020-09-01 23:29:19
0 1533
今天完成的事情
1. SQL 子查询
2. wait、notify 协同
收获
1. SQL 子查询
使用子查询可以让我们从多个数据表中获取目标数据。子查询即嵌套在其他查询中的查询。
使用子查询:
假设现在有三张表,订单表、商品表、客户信息表,我们需要:
a,取出含有商品 RGAN01 的所有订单信息
b,在上一个结果集中取出下这些订单的所有用户 id
c,然后根据用户 id 取出客户信息
有了子查询之后我们可以这样做:
SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id="RGAN01"));
实际上上面的 SQL 是分为三个由里到外执行的。最里层的返回订单列表给中间层查询出用户的 id 信息,最后由最外层的查询语句返回我们需要的信息。
需要注意的是子查询的 SELECT 只能够查询单个列表,否则返回错误。
在子查询中使用计算字段
客户信息与订单信息在两张表中,我们需要展示每个客户的订单数。
SELECT cust_name, cust_state, (SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id=Customers.cust_id) AS orders
FROM Customers;
这个子查询实际上执行了 4 次,因为搜索到了 4 位客户的信息。
上述 WHERE 子句的语义是在 Orders 表中找出与当前在 Customers 表中查询到的 cust_id 一致的订单数量。这个语句的逻辑和之前三层嵌套的 SELECT 语句不一样。
2. wait、notify 协同
在很早的 java 中式没有 JUC 包的,那么就需要使用 java 来实现一套线程协同方案。Object 中的 wait、notify 等方法正是在这个情境下产生的。
使用 wait 与 notify 实现一个生产者与消费者的模型,当消费者判断可以消费就进行消费并且 notify 生产者进行生产,否则就 wait。生产者判断可以进行生产就进行生产并且通知消费者来消费,否则就 wait。
运行效果:
wait 与 sleep 的区别:
wait() 之后线程就不占用资源了,而是等待 notify 通知之后再来处理。sleep 会一直占用资源。
notify 与 notifyAll 的区别:
notify 只会通知等待队列里面的一个线程,而 notifyAll 会通知所有的线程。
为什么在 wait 外要使用 while 循环来判断条件,而不是 if:
这个在 Object 的 wait 方法注解上有一个解释:
* As in the one argument version, interrupts and spurious wakeups are
* possible, and this method should always be used in a loop:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* ... // Perform action appropriate to condition
* }
* </pre>
我的理解是,如果把 wait 放在 if 里面,这个时候要是产生了虚假的唤醒,那么线程就顺着往下走了,跳过了条件的判断,这个逻辑就出问题了。
关于这个虚假的唤醒,我的理解有一种情况是 notifyAll 通知了所有的等待的生产者线程,但是可能只需要几个生产真就够了,这个时候如果不使用 while 的话,所有的生产真都会接着往下跑,逻辑出错。
但是如果是放在 while 里面,那么唤醒之后,还会进行条件的判断,这个时候各种意外的唤醒情况都会重新进入 wait 状态,直到真正的唤醒条件到来。
评论