mysql——索引事务和JDBC编程

1. 索引

索引是数据库中用于加速查询的数据结构,类似于书籍的目录。

索引的作用

  • 大幅提高查询速度

  • 加速表连接操作

  • 保证数据唯一性(唯一索引)

  • 优化排序和分组操作

创建主键约束( PRIMARY KEY )、唯一约束( UNIQUE )、外键约束( FOREIGN KEY )时,会自动创建对应列的索引。

  1. 创建索引
    对于非主键、非唯一约束、非外键的字段,可以创建普通索引

    create index 索引名 on 表名(字段名);

  2. 查看索引

    show index from 表名;

  3. 删除索引

    drop index 索引名 on 表名;

对于 创建主键约束( PRIMARY KEY )、唯一约束( UNIQUE )、外键约束( FOREIGN KEY )时,自动创建对应列的索引,是无法手动删除的
自定义索引可以手动删除。

1. 按数据结构分类

如果索引不存在,当我们想要查找某个数据时,时间复杂度为O(N)

  1. 哈希索引
  • 特点

    • 基于哈希表实现

    • 精确匹配效率极高(O(1)时间复杂度)

    • 不支持范围查询和排序

  • 适用场景:等值查询(=, IN)

  • 存储引擎支持:MEMORY引擎(默认)、InnoDB(自适应哈希索引)

  1. 二叉搜索树
    有可能为单分支二叉搜索树则时间复杂度为O(N)
  2. 红黑树
    可以避免成为单分支二叉搜索树,时间复杂度为O(logN)
  3. B 树(N叉搜索树)
  • 特点:默认索引类型,多路平衡查找树

每个节点上有 M 个key ,划分出了 M+1 个区间

进行查询时,直接从根节点出发,判断当前要查的节点在哪个区间中,决定下一步往哪里走

进行 插入/删除操作时可能涉及到节点的拆分和合并

  • 适用场景

    • 全值匹配(=)

    • 范围查询(>, <, BETWEEN)

    • 前缀匹配(LIKE 'abc%')

    • 排序(ORDER BY)

    • 分组(GROUP BY)

无法使用后缀匹配(like '%abc')

  • 存储引擎支持:InnoDB、MyISAM、MEMORY等
  1. B+树
    B 树的改进,针对数据库量身定做

特点:

  1. B+ 树也是一个N叉搜索树,每个节点上有 M 个key ,划分出了 M 个区间
  2. 父节点上的每个key都会以最大值的身份存储在子节点中,所以叶子节点这一层包含了整个树的数据全集
  3. B+ 树会使用链表将叶子节点串联起来
    (此时就可以非常方便的完成数据集合的遍历,也可以很方便的从数据集合中按照范围取出一个子集)
    优点:
  4. N 叉搜索树,树的高度是有限的,降低 io 的次数
  5. 擅长范围查询
  6. 所有查询最终都要落到叶子节点,查询和查询之间的时间开销是稳定的
  7. 由于叶子节点是全集,会把行数据只存储在叶子节点上,非叶子节点只存储一个用来排序的key
  8. 在进行查询时,可以将硬盘中的非叶子节点加载到内存中,整体查询的比较过程就可以在内存中进行。

2. 事务

A给B转2000块钱,在转账过程中,A的账户扣除2000块钱,此时突然断网或数据库挂了,B的账号没有增加2000块钱,这是一个重大错误。
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。
在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。

使用:
( 1 )开启事务: start transaction;
( 2 )执行多条 SQL 语句
( 3 )回滚或提交: rollback/commit;
说明: rollback 即是全部失败, commit 即是全部成功。
事务特性:

  1. 原子性:通过回滚的方式,保证这一系列操作都能执行正确或恢复如初
  2. 一致性:事务执行前后,数据库从一个一致状态变到另一个一致状态
  • 数据完整性约束不被破坏

  • 业务规则保持一致

  1. 持久性:事务一旦提交,其结果就是永久性的 :即使系统崩溃,数据也不会丢失
    通过redo log(重做日志)实现
  2. 隔离性:多个事务 并发执行时,一个事务的执行不应影响其他事务
    通过锁机制和MVCC(多版本并发控制)实现
    提高并发进程,数据库服务器执行效率变高,但会产生问题

数据隔离级别

隔离级别 脏读 不可重复读 幻读 说明
READ UNCOMMITTED 可能 可能 可能 可读取未提交数据
READ COMMITTED 不可能 可能 可能 只能读取已提交数据(读加锁)
REPEATABLE READ 不可能 不可能 可能 同一事务多次读取结果一致(MySQL默认) (读写都加锁)
SERIALIZABLE 不可能 不可能 不可能 完全串行化执行

1. 查看和设置隔离级别

复制代码
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置会话级隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 设置全局级隔离级别(需重启生效)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

2. 隔离级别问题演示

  • 锁机制

    • 共享锁(S锁):读锁,其他事务可读不可写

    • 排他锁(X锁):写锁,其他事务不可读写

(1) 脏读(Dirty Read)

一个事务A 在写数据的过程中,事务B读取了该数据,之后事务A又修改了该数据,导致事务B之前读取的数据时一个无效/过时的数据(也称为 脏数据)

复制代码
-- 会话1
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;  -- 未提交

-- 会话2(可以读取到未提交的数据)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT balance FROM accounts WHERE user_id = 1;  -- 看到未提交的修改

解决方法:

在事务A进行写操作时加锁(即在事务A进行写操作时,事务B不可以进行读操作)

(2) 不可重复读(Non-repeatable Read)

事务A提交一份数据后,事务B进行多次读取,在事务B读取数据过程中,事务A又修改了该数据并提交,导致事务B读取的前后数据不同。

复制代码
-- 会话1
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT balance FROM accounts WHERE user_id = 1;  -- 第一次读取

-- 会话2
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
COMMIT;

-- 会话1(同一事务内两次读取结果不同)
SELECT balance FROM accounts WHERE user_id = 1;  -- 第二次读取
COMMIT;

解决方法:

在事务B进行读操作时加锁(即在事务B读操作时,事务B不可以进行写操作)

在事务A进行写操作时加锁(即在事务A进行写操作时,事务B不可以进行读操作)

(3) 幻读(Phantom Read)

事务A提交一份数据后,事务B进行多次读取,在事务B读取数据过程中,事务A又提交了一份数据,导致事务B读取的前后结果集不同。

复制代码
-- 会话1
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM accounts WHERE balance > 1000;  -- 返回2条记录

-- 会话2
INSERT INTO accounts VALUES(3, '王五', 1500);
COMMIT;

-- 会话1(同一事务内相同查询返回不同行数)
SELECT * FROM accounts WHERE balance > 1000;  -- 返回3条记录
COMMIT;

解决方法:

引入串行化方式

总结:
( 1 )对于插入、删除数据频率高的表,不适用索引
( 2 )对于某列修改频率高的,该列不适用索引
( 3 )通过某列或某几列的条件查询频率高的,可以对这些列创建索引

3. JDBC 编程

编程语言,如 Java , C 、 C++ 、 Python 等
数据库,如 Oracle , MySQL , SQL Server 等
数据库驱动包:不同的数据库,对应不同的编程语言提供了不同的数据库驱动包,如: MySQL 提
供了 Java 的驱动包 mysql-connector-java ,需要基于 Java 操作 MySQL 即需要该驱动包。同样的,
要基于 Java 操作 Oracle 数据库则需要 Oracle 的数据库驱动包 ojdbc 。
JDBC ,即 Java Database Connectivity , java 数据库连接。是一种用于执行 SQL 语句的 Java API ,它是Java中的数据库连接规范。这个 API 由 java.sql.*,javax.sql.* 包中的一些类和接口组成,它为 Java 开发人员操作数据库提供了一个标准的API ,可以为多种关系数据库提供统一访问。

配置:

  1. 从中央仓库下载mysql的jdbc驱动包(jar)

  2. 将 jar 引入到项目中(拷贝,add as library)

高内聚:把相同/相关联的功能放在一起

高耦合:两个模块关联关系紧密,一个模块修改对另一个模块有很大影响

我们要求程序 高内聚,低耦合

jdbc开发案例

javax.sql jdbc 包

127.0.0.1 是一个特殊的IP地址,叫做"环回IP"(lookback)

每个机器上都有环回IP(127.0.0.1),只要把消息发送给这个IP,就等于发给自己

由于我们的jdbc程序和mysql服务器在同一个主机上,使用环回IP

复制代码
import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class Domo {
    public static void main(String[] args) throws SQLException {
        Scanner scan = new Scanner(System.in);
        System.out.print("请输入id:");
        int id = scan.nextInt();
        scan.nextLine();
        System.out.print("请输入姓名:");
        String name = scan.nextLine();
        //1.创建DataSource(抽象接口)
        //DataSource 描述"数据源头",即数据库服务器所在位置
        DataSource dataSource = new MysqlDataSource();
        //找到mysql服务器
        //url(网址):网络上具体资源位置
        ((MysqlDataSource) dataSource).setURL("jdbc:mysql://127.0.0.1:3306/school?characterEncoding=utf8&useSSL=false");//向下转型
        //认证用户名
        //root 管理员mysql默认自带用户
        ((MysqlDataSource) dataSource).setUser("root");
        //认证密码
        ((MysqlDataSource) dataSource).setPassword("123");
        //2. 和数据库服务器建立连接
        //getConnection()是jdbc中常见异常,如果执行sql或操作数据库过程中出现问题,一般都抛出这个异常
        //connection连接
        Connection connection=dataSource.getConnection();
        //3. 构造sql(代码中的sql不需要写;)
        String sql = "insert into student values(1,'lh'),(id,'"+ name +"'),(?,?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setInt(1,id);
        preparedStatement.setString(2,name);
        //4. 把sql发送给服务器,返回值是一个整数,表示影响的行数
        int n = preparedStatement.executeUpdate();
        System.out.println(n);
        //5. 释放资源,关闭连接(先申请资源,后释放)
        preparedStatement.close();
        connection.close();
    }
}

Prepared :准备好的/预处理的

Statement: 语句

先解析检查 sql ,看看sql是否有问题,解析完毕后,会得到结构化数据,直接把解析好的结构化数据发送给数据库,服务器就省下了这部分解析工作

如果直接把字符串格式的 sql 发给mysql 服务器,mysql 服务器就需要对 sql 解析和校验,但 mysql 服务器是服务于多个客户端,此时总的开销和总的负担就很大。

复制代码
import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Domo2 {
    public static void main(String[] args) throws SQLException {
        //建立DataSouece(抽象接口)
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource) dataSource).setURL("jdbc:mysql://127.0.0.1:3306/school?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("123");
        //2. 和数据库服务器建立连接
        Connection connection = dataSource.getConnection();
        //3. 构造sql
        String sql = "select * from student";
        PreparedStatement statement = connection.prepareStatement(sql);
        //4. 执行sql
        //ResultSet 表示查询的结果集合
        ResultSet resultSet = statement.executeQuery();
        //5. 遍历结果集合
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            System.out.println("id = "+id +", name ="+ name);
        }
        //释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
相关推荐
编程在手天下我有3 分钟前
缓存与数据库数据一致性:旁路缓存、读写穿透和异步写入模式解析
数据库·缓存·oracle·软件开发·架构设计·数据一致性
络712 分钟前
IDEA导入并启动若依项目步骤(SpringBoot+Vue3)
java·spring boot·mysql·vue·intellij-idea
云攀登者-望正茂15 分钟前
Redis 及其在系统设计中的作用
数据库·redis·缓存
ghostmen30 分钟前
Centos 实现 MySql 8.0.40 主从配置
linux·mysql·mysql主从
博睿谷IT99_40 分钟前
PostgreSQL性能优化实用技巧‌
数据库·postgresql·性能优化
Leo.yuan1 小时前
数据仓库是什么?数据仓库架构有哪些?
大数据·数据库·数据仓库·架构·数据分析
云边有个稻草人1 小时前
【金仓数据库征文】从云计算到区块链:金仓数据库的颠覆性创新之路
数据库·云计算·区块链·金仓数据库 2025 征文·数据库平替用金仓·金仓数据库概述·金仓数据库的产品优化提案
冼紫菜1 小时前
基于Redis实现高并发抢券系统的数据同步方案详解
java·数据库·redis·后端·mysql·缓存·性能优化
异常君2 小时前
MySQL重复数据克星:7种高效处理方案全解析
java·后端·mysql
屿暖_2 小时前
Rocky Linux 安装 PostgreSQL 数据库完整指南(2025版)
数据库