# 技术 ## 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 | | 趋势 | 股价的长期运行方向 | 中长期处于上升趋势 | **关键判断:** - 压力强度大 → 需要放巨量才能突破 - 获利筹码增加 + 获利了结意愿不明显 → 筹码稳定性好 --- ### 五、核心功能三:资金流向(判断主力态度) | 观察点 | 判断依据 | 结论 | | ---------------- | ---------------- | ---------- | | 庄家在买还是卖? | 当前多头资金占优 | 主力在买 | | 资金是否持续? | 多头资金持续流入 | 资金在流进 | > **结论:** 当前市场多头资金占优,且持续流入,整体资金在流进。 --- ### 六、超级云脑四大分析维度 | 维度 | 要回答的问题 | 对应功能 | | -------- | ---------------------- | ------------ | | 安全性 | 我的股票安全吗? | 六色罗盘 | | 压力点 | 涨到什么价位要注意? | 技术指标分析 | | 主力态度 | 主力在买还是卖? | 资金流向分析 | | 资金动向 | 市场资金流入还是流出? | 资金流向分析 | --- ###