diff --git a/陈春晓的学习笔记/陈春晓4.8学习笔记.md b/陈春晓的学习笔记/陈春晓4.8学习笔记.md new file mode 100644 index 0000000..a082a89 --- /dev/null +++ b/陈春晓的学习笔记/陈春晓4.8学习笔记.md @@ -0,0 +1,778 @@ +# 技术 + +## MySQL + +--- + +### 一、多表查询 + +#### 1. 为什么要多表查询? + +实际开发中,数据会分散在多张表中(为了减少冗余)。例如: +- 用户表:存用户基本信息 +- 订单表:存订单信息 +- 查询“张三的订单”就需要同时查两张表 + +#### 2. 连接查询分类 + +| 连接类型 | 关键字 | 说明 | +| -------- | ---------- | ------------------------- | +| 内连接 | INNER JOIN | 只返回匹配的记录 | +| 左外连接 | LEFT JOIN | 左表全部 + 右表匹配的 | +| 右外连接 | RIGHT JOIN | 右表全部 + 左表匹配的 | +| 全外连接 | FULL JOIN | 两张表全部(MySQL不支持) | +| 交叉连接 | CROSS JOIN | 笛卡尔积(慎用) | + +#### 3. 内连接(INNER JOIN) + +```sql +-- 标准写法 +SELECT u.name, o.order_no, o.amount +FROM user u +INNER JOIN orders o ON u.id = o.user_id; + +-- 隐式写法(不推荐,可读性差) +SELECT u.name, o.order_no, o.amount +FROM user u, orders o +WHERE u.id = o.user_id; +``` + +#### 4. 左外连接(LEFT JOIN) + +```sql +-- 查询所有用户及其订单(没有订单的用户也会显示) +SELECT u.name, o.order_no, o.amount +FROM user u +LEFT JOIN orders o ON u.id = o.user_id; + +-- 结果示例: +-- 张三 | 001 | 100 +-- 张三 | 002 | 200 +-- 李四 | NULL | NULL (李四没有订单) +``` + +#### 5. 多表连接(三张以上) + +```sql +-- 查询订单详情:用户 + 订单 + 商品 +SELECT u.name, o.order_no, p.product_name, od.quantity +FROM user u +INNER JOIN orders o ON u.id = o.user_id +INNER JOIN order_detail od ON o.id = od.order_id +INNER JOIN product p ON od.product_id = p.id; +``` + +#### 6. 自连接 + +一张表和自己连接,用于存储层级关系(如员工-上级)。 + +```sql +-- 员工表:id, name, manager_id +SELECT e.name AS 员工, m.name AS 上级 +FROM employee e +LEFT JOIN employee m ON e.manager_id = m.id; +``` + +#### 7. 子查询 + +```sql +-- WHERE子查询:查询成绩高于平均分的学生 +SELECT name, score +FROM student +WHERE score > (SELECT AVG(score) FROM student); + +-- FROM子查询:将查询结果当作临时表 +SELECT t.class, AVG(t.score) +FROM (SELECT * FROM student WHERE score > 60) t +GROUP BY t.class; + +-- EXISTS子查询:存在性判断 +SELECT * FROM user u +WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id); +``` + +#### 8. UNION合并查询 + +```sql +-- 合并两个查询结果(去重) +SELECT name FROM user +UNION +SELECT name FROM vip_user; + +-- UNION ALL(不去重,性能更好) +SELECT name FROM user +UNION ALL +SELECT name FROM vip_user; +``` + +--- + +### 二、索引 + +#### 1. 索引的底层数据结构 + +MySQL默认使用**B+树**作为索引结构: + +| 数据结构 | 特点 | +| -------- | ------------------------------------------ | +| B+树 | 叶子节点存储数据,非叶子节点存指针,矮胖型 | +| 哈希表 | 等值查询快,范围查询慢 | +| 红黑树 | 高度太高,磁盘IO多 | + +**B+树优点:** +- 高度低(3-4层可存千万级数据) +- 叶子节点有序链表,支持范围查询 +- 磁盘IO次数少 + +#### 2. 索引分类 + +| 分类 | 说明 | 特点 | +| -------- | ------------ | -------------------------- | +| 主键索引 | PRIMARY KEY | 唯一、非空、一张表只有一个 | +| 唯一索引 | UNIQUE | 列值必须唯一,允许NULL | +| 普通索引 | INDEX | 最基本的索引,无限制 | +| 复合索引 | INDEX(a,b,c) | 多列组合,遵循最左前缀 | +| 全文索引 | FULLTEXT | 用于文本搜索(MyISAM) | +| 空间索引 | SPATIAL | 用于地理数据 | + +#### 3. 索引操作 + +```sql +-- 创建索引 +CREATE INDEX idx_name ON user(name); +CREATE UNIQUE INDEX idx_email ON user(email); +CREATE INDEX idx_name_age ON user(name, age); -- 复合索引 + +-- 建表时指定 +CREATE TABLE user ( + id INT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(20), + email VARCHAR(50) UNIQUE, + INDEX idx_name (name) +); + +-- 删除索引 +DROP INDEX idx_name ON user; + +-- 查看索引 +SHOW INDEX FROM user; + +-- 强制使用索引 +SELECT * FROM user FORCE INDEX (idx_name) WHERE name = '张三'; +``` + +#### 4. 复合索引最左前缀原则 + +```sql +-- 创建复合索引 (a, b, c) +CREATE INDEX idx_abc ON table(a, b, c); + +-- 能用到索引的查询 +WHERE a = 1 +WHERE a = 1 AND b = 2 +WHERE a = 1 AND b = 2 AND c = 3 + +-- 用不到索引的查询 +WHERE b = 2 -- 没带最左边a +WHERE a = 1 AND c = 3 -- 跳过了b,只有a能用 +``` + +#### 5. 索引失效场景 + +| 场景 | 示例 | 原因 | +| ------------ | ------------------------------ | ----------------------- | +| 函数操作 | `WHERE YEAR(create_time)=2024` | 对列用了函数 | +| 隐式类型转换 | `WHERE phone=13800138000` | phone是字符串,没用引号 | +| 模糊匹配开头 | `WHERE name LIKE '%三'` | 通配符在开头 | +| OR条件 | `WHERE a=1 OR b=2` | 两边都要有索引 | +| 不等号 | `WHERE age != 18` | 不等于不走索引 | +| IS NULL | 部分情况 | 取决于NULL值比例 | + +#### 6. 索引使用原则 + +| 原则 | 说明 | +| -------- | --------------------------------------- | +| 区分度高 | 列值越唯一越好(如手机号 > 性别) | +| 经常查询 | 建在WHERE、ORDER BY、GROUP BY、JOIN列上 | +| 不宜过多 | 单表索引不超过5-6个 | +| 小表不用 | 数据量小,全表扫描更快 | +| 避免重复 | 同样功能的索引只建一个 | + +#### 7. 查看SQL执行计划 + +```sql +EXPLAIN SELECT * FROM user WHERE name = '张三'; +``` + +**关键字段:** + +| 字段 | 含义 | 好坏 | +| ------------- | ------------ | --------------------------------- | +| type | 连接类型 | const > ref > range > index > ALL | +| possible_keys | 可能用的索引 | - | +| key | 实际用的索引 | 看是否用了想要的 | +| rows | 扫描行数 | 越少越好 | +| Extra | 额外信息 | Using index(覆盖索引)最好 | + +--- + +### 三、事务 + +#### 1. ACID详解 + +| 特性 | 含义 | 例子 | +| ------ | -------- | ---------------------------------- | +| 原子性 | 不可分割 | 转账:扣钱和加钱必须同时成功或失败 | +| 一致性 | 数据正确 | 转账前后总金额不变 | +| 隔离性 | 互不干扰 | 两个事务同时执行,互不影响 | +| 持久性 | 永久保存 | 提交后数据不丢失 | + +#### 2. 事务并发问题 + +| 问题 | 说明 | 例子 | +| ---------- | ------------------------ | --------------------------- | +| 脏读 | 读到未提交的数据 | A修改未提交,B读到,A回滚 | +| 不可重复读 | 同一事务两次读取结果不同 | A两次读,中间B修改了 | +| 幻读 | 读到新增的数据 | A查询,B插入,A再查多了一条 | + +#### 3. 隔离级别与问题对应 + +| 隔离级别 | 脏读 | 不可重复读 | 幻读 | +| ---------------- | ---- | ---------- | ----------------- | +| READ UNCOMMITTED | 可能 | 可能 | 可能 | +| READ COMMITTED | 不会 | 可能 | 可能 | +| REPEATABLE READ | 不会 | 不会 | 可能(MySQL解决) | +| SERIALIZABLE | 不会 | 不会 | 不会 | + +> MySQL默认 REPEATABLE READ,通过MVCC解决了幻读问题。 + +#### 4. 事务操作 + +```sql +-- 开启事务 +START TRANSACTION; +-- 或 +BEGIN; + +-- 执行SQL +UPDATE account SET money = money - 100 WHERE id = 1; +UPDATE account SET money = money + 100 WHERE id = 2; + +-- 查看当前事务隔离级别 +SELECT @@transaction_isolation; + +-- 设置保存点(回滚到指定位置) +SAVEPOINT sp1; +ROLLBACK TO sp1; + +-- 提交 +COMMIT; + +-- 回滚 +ROLLBACK; +``` + +--- + +### 四、视图 + +#### 1. 什么是视图? + +视图是**虚拟表**,不存储数据,查询时动态生成。 + +#### 2. 视图操作 + +```sql +-- 创建视图 +CREATE VIEW user_order_view AS +SELECT u.name, o.order_no, o.amount +FROM user u +LEFT JOIN orders o ON u.id = o.user_id; + +-- 使用视图(和表一样) +SELECT * FROM user_order_view WHERE amount > 100; + +-- 查看视图 +SHOW FULL TABLES WHERE Table_type = 'VIEW'; + +-- 删除视图 +DROP VIEW user_order_view; +``` + +#### 3. 视图的优缺点 + +| 优点 | 缺点 | +| ---------------------- | ------------ | +| 简化复杂查询 | 性能可能下降 | +| 数据安全(隐藏敏感列) | 增删改有限制 | +| 逻辑封装 | 维护成本 | + +--- + +### 五、存储过程 + +#### 1. 什么是存储过程? + +预编译的SQL代码块,类似Java中的方法。 + +```sql +-- 创建存储过程 +DELIMITER // +CREATE PROCEDURE get_user_by_id(IN uid INT) +BEGIN + SELECT * FROM user WHERE id = uid; +END // +DELIMITER ; + +-- 调用 +CALL get_user_by_id(1); + +-- 删除 +DROP PROCEDURE get_user_by_id; +``` + +#### 2. 带输出参数的存储过程 + +```sql +DELIMITER // +CREATE PROCEDURE get_user_count(OUT total INT) +BEGIN + SELECT COUNT(*) INTO total FROM user; +END // +DELIMITER ; + +-- 调用 +CALL get_user_count(@total); +SELECT @total; +``` + +#### 3. 存储过程优缺点 + +| 优点 | 缺点 | +| -------------- | ---------- | +| 减少网络传输 | 调试困难 | +| 预编译,性能好 | 移植性差 | +| 业务逻辑封装 | 维护成本高 | + +> 实际开发中,业务逻辑通常放在Java代码中,存储过程用得较少。 + +--- + +### 六、触发器 + +#### 1. 什么是触发器? + +在某个表执行INSERT、UPDATE、DELETE时**自动触发**执行的SQL。 + +```sql +-- 创建触发器:用户删除时,记录日志 +DELIMITER // +CREATE TRIGGER user_delete_log +AFTER DELETE ON user +FOR EACH ROW +BEGIN + INSERT INTO user_log(user_id, action, time) + VALUES (OLD.id, 'DELETE', NOW()); +END // +DELIMITER ; + +-- 查看触发器 +SHOW TRIGGERS; + +-- 删除触发器 +DROP TRIGGER user_delete_log; +``` + +> 注意:触发器使用要谨慎,会增加数据库压力,调试困难。 + +--- + +### 七、JDBC连接MySQL + +#### 1. 引入依赖 + +```xml + + mysql + mysql-connector-java + 8.0.33 + +``` + +#### 2. 完整代码示例 + +```java +import java.sql.*; + +public class MySQLDemo { + + // 连接参数 + private static final String URL = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8"; + private static final String USER = "root"; + private static final String PASSWORD = "123456"; + + public static void main(String[] args) { + // 1. 加载驱动(MySQL8可选,但建议保留) + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + // 2. try-with-resources自动关闭资源 + String sql = "SELECT id, name, age FROM user WHERE age > ?"; + + try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); + PreparedStatement ps = conn.prepareStatement(sql)) { + + // 设置参数 + ps.setInt(1, 18); + + // 执行查询 + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + int id = rs.getInt("id"); + String name = rs.getString("name"); + int age = rs.getInt("age"); + System.out.println(id + " | " + name + " | " + age); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + } +} +``` + +#### 3. CRUD完整操作 + +```java +public class UserDao { + + // 增 + public void add(User user) { + String sql = "INSERT INTO user(name, age, email) VALUES(?, ?, ?)"; + try (Connection conn = DBUtil.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + + ps.setString(1, user.getName()); + ps.setInt(2, user.getAge()); + ps.setString(3, user.getEmail()); + + int rows = ps.executeUpdate(); + if (rows > 0) { + ResultSet rs = ps.getGeneratedKeys(); + if (rs.next()) { + user.setId(rs.getInt(1)); // 获取自增ID + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 删 + public void delete(int id) { + String sql = "DELETE FROM user WHERE id = ?"; + try (Connection conn = DBUtil.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, id); + ps.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 改 + public void update(User user) { + String sql = "UPDATE user SET name=?, age=?, email=? WHERE id=?"; + try (Connection conn = DBUtil.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, user.getName()); + ps.setInt(2, user.getAge()); + ps.setString(3, user.getEmail()); + ps.setInt(4, user.getId()); + ps.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // 查(单个) + public User getById(int id) { + String sql = "SELECT * FROM user WHERE id = ?"; + try (Connection conn = DBUtil.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, id); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + User user = new User(); + user.setId(rs.getInt("id")); + user.setName(rs.getString("name")); + user.setAge(rs.getInt("age")); + user.setEmail(rs.getString("email")); + return user; + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + // 查(列表) + public List listAll() { + List list = new ArrayList<>(); + String sql = "SELECT * FROM user"; + try (Connection conn = DBUtil.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql); + ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + User user = new User(); + user.setId(rs.getInt("id")); + user.setName(rs.getString("name")); + user.setAge(rs.getInt("age")); + user.setEmail(rs.getString("email")); + list.add(user); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return list; + } +} +``` + +#### 4. 连接池工具类(Druid) + +```java +import com.alibaba.druid.pool.DruidDataSource; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class DBUtil { + private static DruidDataSource dataSource; + + static { + dataSource = new DruidDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai"); + dataSource.setUsername("root"); + dataSource.setPassword("123456"); + + // 连接池配置 + dataSource.setInitialSize(5); // 初始连接数 + dataSource.setMinIdle(5); // 最小空闲连接 + dataSource.setMaxActive(20); // 最大活跃连接 + dataSource.setMaxWait(60000); // 最大等待时间(毫秒) + dataSource.setValidationQuery("SELECT 1"); // 心跳检测 + dataSource.setTestOnBorrow(true); // 借用时检测 + } + + public static Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + public static DataSource getDataSource() { + return dataSource; + } +} +``` + +#### 5. JDBC事务操作 + +```java +public void transfer(int fromId, int toId, double amount) { + Connection conn = null; + try { + conn = DBUtil.getConnection(); + conn.setAutoCommit(false); // 开启事务 + + // 扣钱 + String sql1 = "UPDATE account SET money = money - ? WHERE id = ?"; + try (PreparedStatement ps = conn.prepareStatement(sql1)) { + ps.setDouble(1, amount); + ps.setInt(2, fromId); + ps.executeUpdate(); + } + + // 加钱 + String sql2 = "UPDATE account SET money = money + ? WHERE id = ?"; + try (PreparedStatement ps = conn.prepareStatement(sql2)) { + ps.setDouble(1, amount); + ps.setInt(2, toId); + ps.executeUpdate(); + } + + conn.commit(); // 提交 + System.out.println("转账成功"); + + } catch (Exception e) { + try { + if (conn != null) { + conn.rollback(); // 回滚 + } + } catch (SQLException ex) { + ex.printStackTrace(); + } + e.printStackTrace(); + System.out.println("转账失败"); + + } finally { + try { + if (conn != null) { + conn.setAutoCommit(true); // 恢复自动提交 + conn.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } +} +``` + +--- + +### 八、SQL优化技巧 + +| 优化点 | 错误写法 | 正确写法 | +| -------------- | -------------------------- | -------------------------------- | +| 避免SELECT * | `SELECT * FROM user` | `SELECT id, name FROM user` | +| 用LIMIT | 全表查 | `SELECT * FROM user LIMIT 10` | +| 用EXISTS代替IN | `WHERE id IN (SELECT ...)` | `WHERE EXISTS (SELECT 1...)` | +| 批量插入 | 循环单条INSERT | `INSERT INTO VALUES (1),(2),(3)` | +| 用UNION ALL | `UNION`(去重) | 不需要去重用`UNION ALL` | +| 避免OR | `WHERE a=1 OR b=2` | 用UNION或分开查 | + +--- + +### 九、今日练习 + +```sql +-- 1. 三表连接查询 +SELECT u.name, o.order_no, p.product_name +FROM user u +INNER JOIN orders o ON u.id = o.user_id +INNER JOIN order_item oi ON o.id = oi.order_id +INNER JOIN product p ON oi.product_id = p.id +WHERE u.id = 1; + +-- 2. 创建复合索引 +CREATE INDEX idx_name_age ON user(name, age); + +-- 3. 查看执行计划 +EXPLAIN SELECT * FROM user WHERE name = '张三'; + +-- 4. 事务操作 +START TRANSACTION; +UPDATE account SET money = money - 100 WHERE id = 1; +UPDATE account SET money = money + 100 WHERE id = 2; +COMMIT; + +-- 5. 创建视图 +CREATE VIEW rich_user AS +SELECT * FROM user WHERE money > 10000; + +-- 6. 分页查询(每页10条) +SELECT * FROM user ORDER BY id LIMIT 0, 10; -- 第1页 +SELECT * FROM user ORDER BY id LIMIT 10, 10; -- 第2页 +``` + + + +# 股票知识 + +## 超级云脑 + +--- + +### 一、投资决策的三大难题 + +在股票投资中,我们经常面临三个核心问题: + +| 问题编号 | 核心问题 | 具体描述 | +| -------- | -------------- | -------------------------------------- | +| 问题一 | 能持有吗? | 股票买完后,不知道能不能继续持有 | +| 问题二 | 有风险吗? | 股票在上涨过程中,不知道风险有多大 | +| 问题三 | 主力什么态度? | 股票遇到压力时,不知道主力是在买还是卖 | + +**解决方案:** 利用人工智能(AI)分析金融大数据,用AI解决决策难题。 + +--- + +### 二、超级云脑是什么? + +**定义:** 超级云脑是将人工智能与金融股票领域融合的工具,能够快速处理大量金融数据,为投资者提供行情分析和预判。 + +**三大优势:** + +| 优势 | 说明 | +| ---------- | -------------------------------------- | +| 处理速度快 | 瞬间处理大量金融数据 | +| 能赚钱 | 通过大数据分析帮助投资者获利 | +| 天然匹配 | 金融市场本身就是大数据市场,AI正好适合 | + +--- + +### 三、核心功能一:六色罗盘(判断安全与风险) + +六色罗盘是一个从**绿色(安全)到红色(风险)** 的图示工具。 + +| 区域 | 含义 | 操作建议 | +| -------- | ------ | ------------------ | +| 绿色区域 | 安全区 | 相对安全,可持有 | +| 红色区域 | 风险区 | 注意风险,考虑减仓 | + +**罗盘细分:** +- 强撑强压区 +- 弱撑强压区 +- 强撑中压区 +- 弱撑中压区 +- 强撑弱压区 +- 弱撑弱压区 + +> **使用方法:** 看指针指向哪个区域,绿色安全,红色危险。 + +--- + +### 四、核心功能二:技术指标分析(判断压力与支撑) + +技术指标分析告诉我们以下关键信息: + +| 指标 | 含义 | 示例数据 | +| ---------------- | ---------------------------- | ------------------ | +| 中长期筹码成本价 | 大多数持股者的平均成本 | 1.648 | +| 短期资金成本价 | 近期买入资金的平均成本 | 1.589 | +| 压力位 | 股价涨到这个位置可能遇到阻力 | 3.084 | +| 支撑位 | 股价跌到这个位置可能获得支撑 | 0.505 | +| 趋势 | 股价的长期运行方向 | 中长期处于上升趋势 | + +**关键判断:** +- 压力强度大 → 需要放巨量才能突破 +- 获利筹码增加 + 获利了结意愿不明显 → 筹码稳定性好 + +--- + +### 五、核心功能三:资金流向(判断主力态度) + +| 观察点 | 判断依据 | 结论 | +| ---------------- | ---------------- | ---------- | +| 庄家在买还是卖? | 当前多头资金占优 | 主力在买 | +| 资金是否持续? | 多头资金持续流入 | 资金在流进 | + +> **结论:** 当前市场多头资金占优,且持续流入,整体资金在流进。 + +--- + +### 六、超级云脑四大分析维度 + +| 维度 | 要回答的问题 | 对应功能 | +| -------- | ---------------------- | ------------ | +| 安全性 | 我的股票安全吗? | 六色罗盘 | +| 压力点 | 涨到什么价位要注意? | 技术指标分析 | +| 主力态度 | 主力在买还是卖? | 资金流向分析 | +| 资金动向 | 市场资金流入还是流出? | 资金流向分析 | + +--- + +###