You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

23 KiB

技术

MySQL


一、多表查询

1. 为什么要多表查询?

实际开发中,数据会分散在多张表中(为了减少冗余)。例如:

  • 用户表:存用户基本信息
  • 订单表:存订单信息
  • 查询“张三的订单”就需要同时查两张表

2. 连接查询分类

连接类型 关键字 说明
内连接 INNER JOIN 只返回匹配的记录
左外连接 LEFT JOIN 左表全部 + 右表匹配的
右外连接 RIGHT JOIN 右表全部 + 左表匹配的
全外连接 FULL JOIN 两张表全部(MySQL不支持)
交叉连接 CROSS JOIN 笛卡尔积(慎用)

3. 内连接(INNER JOIN)

-- 标准写法
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)

-- 查询所有用户及其订单(没有订单的用户也会显示)
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. 多表连接(三张以上)

-- 查询订单详情:用户 + 订单 + 商品
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. 自连接

一张表和自己连接,用于存储层级关系(如员工-上级)。

-- 员工表: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. 子查询

-- 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合并查询

-- 合并两个查询结果(去重)
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. 索引操作

-- 创建索引
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. 复合索引最左前缀原则

-- 创建复合索引 (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执行计划

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. 事务操作

-- 开启事务
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. 视图操作

-- 创建视图
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中的方法。

-- 创建存储过程
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. 带输出参数的存储过程

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。

-- 创建触发器:用户删除时,记录日志
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. 引入依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

2. 完整代码示例

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完整操作

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<User> listAll() {
        List<User> 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)

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事务操作

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或分开查

九、今日练习

-- 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
趋势 股价的长期运行方向 中长期处于上升趋势

关键判断:

  • 压力强度大 → 需要放巨量才能突破
  • 获利筹码增加 + 获利了结意愿不明显 → 筹码稳定性好

五、核心功能三:资金流向(判断主力态度)

观察点 判断依据 结论
庄家在买还是卖? 当前多头资金占优 主力在买
资金是否持续? 多头资金持续流入 资金在流进

结论: 当前市场多头资金占优,且持续流入,整体资金在流进。


六、超级云脑四大分析维度

维度 要回答的问题 对应功能
安全性 我的股票安全吗? 六色罗盘
压力点 涨到什么价位要注意? 技术指标分析
主力态度 主力在买还是卖? 资金流向分析
资金动向 市场资金流入还是流出? 资金流向分析