1-【JavaWeb】数据库基础

计算机网络基础

1. 理解 Socket 技术的基础

Socket 是一种网络编程的工具,能够在网络设备之间传输数据。Java 的 SocketServerSocket 类用于建立 TCP 连接。

2. 使用 Socket 进行数据传输的简单示例

以下代码展示了如何使用 Java 的 SocketServerSocket 类在客户端和服务器端之间传输数据。

服务器端代码:

import java.io.*;
import java.net.*;

public class SimpleServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("Server is listening on port 8080");
            Socket socket = serverSocket.accept();
            System.out.println("Client connected");

            // 从客户端读取数据
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String message = reader.readLine();
            System.out.println("Received from client: " + message);

            // 向客户端发送数据
            OutputStream output = socket.getOutputStream();
            PrintWriter writer = new PrintWriter(output, true);
            writer.println("Hello, client!");

            socket.close();
        } catch (IOException ex) {
            System.out.println("Server exception: " + ex.getMessage());
        }
    }
}

客户端代码:

import java.io.*;
import java.net.*;

public class SimpleClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8080)) {
            // 向服务器发送数据
            OutputStream output = socket.getOutputStream();
            PrintWriter writer = new PrintWriter(output, true);
            writer.println("Hello, server!");

            // 从服务器读取数据
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String message = reader.readLine();
            System.out.println("Received from server: " + message);
        } catch (IOException ex) {
            System.out.println("Client exception: " + ex.getMessage());
        }
    }
}

3. 使用 Socket 传输文件

Socket 也可以用于传输文件。以下代码示例展示了如何通过 Socket 传输文件:

服务器端代码(接收文件):

import java.io.*;
import java.net.*;

public class FileServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("Server is listening on port 8080");
            Socket socket = serverSocket.accept();
            System.out.println("Client connected");

            // 接收文件
            InputStream input = socket.getInputStream();
            FileOutputStream fileOutput = new FileOutputStream("received_file.txt");
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                fileOutput.write(buffer, 0, bytesRead);
            }
            fileOutput.close();
            socket.close();
            System.out.println("File received");

        } catch (IOException ex) {
            System.out.println("Server exception: " + ex.getMessage());
        }
    }
}

客户端代码(发送文件):

import java.io.*;
import java.net.*;

public class FileClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8080)) {
            // 发送文件
            File file = new File("send_file.txt");
            FileInputStream fileInput = new FileInputStream(file);
            OutputStream output = socket.getOutputStream();
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fileInput.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }
            fileInput.close();
            System.out.println("File sent");

        } catch (IOException ex) {
            System.out.println("Client exception: " + ex.getMessage());
        }
    }
}

4. 使用浏览器访问 Socket 服务器

我们可以创建一个非常简单的 HTTP 服务器,来响应浏览器的请求。浏览器通过发送 HTTP 请求访问服务器,服务器响应 HTML 页面。

服务器端代码(响应浏览器请求):

import java.io.*;
import java.net.*;

public class HttpServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("HTTP Server is listening on port 8080");
            
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("New client connected");

                // 读取浏览器请求
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line;
                while (!(line = reader.readLine()).isEmpty()) {
                    System.out.println(line);  // 打印请求头
                }

                // 向浏览器响应 HTML
                OutputStream output = socket.getOutputStream();
                PrintWriter writer = new PrintWriter(output, true);
                writer.println("HTTP/1.1 200 OK");
                writer.println("Content-Type: text/html");
                writer.println();
                writer.println("<html><body><h1>Hello from Simple HTTP Server</h1></body></html>");

                socket.close();
            }
        } catch (IOException ex) {
            System.out.println("Server exception: " + ex.getMessage());
        }
    }
}
测试步骤:
  1. 运行服务器端程序 HttpServer
  2. 打开浏览器并访问 http://localhost:8080
  3. 浏览器会显示服务器返回的 HTML 内容。

总结

这些示例展示了 Socket 的基础应用、如何通过 Socket 传输数据和文件,以及如何使用浏览器访问一个简单的 Socket 服务器。

数据库基础

1. 什么是数据库

数据库是一种用于存储、管理和检索数据的结构化系统。它允许用户以高效和可靠的方式操作数据。常用的数据库系统管理数据的增删改查(CRUD操作,Create/Retrieve/Update/Delete)。

在 Java 中,我们通常使用 JDBC(Java Database Connectivity)与数据库进行交互。

2. 常见的数据库

以下是一些常见的数据库管理系统:

  • 关系型数据库

    • MySQL:开源、常用的关系型数据库。
    • PostgreSQL:功能丰富的开源数据库,支持复杂查询。
    • Oracle:企业级商业数据库系统。
    • SQL Server:由微软开发,广泛应用于企业。
  • 非关系型数据库(NoSQL)

    • MongoDB:面向文档的数据库,适合大规模数据存储。
    • Cassandra:分布式的NoSQL数据库,用于处理大量数据。

3. 数据模型

数据模型用于描述数据的结构、关系和约束。常见的数据模型包括:

  • 层次模型:数据以树的形式组织,每个记录有父子关系。
  • 网状模型:数据通过图来表示,记录间可以有多对多的关系。
  • 关系模型:数据通过表(关系)来表示,是目前最常用的模型。

在关系模型中,数据通过行和列存储。每个表中的一行代表一个记录,列表示字段或属性。关系数据库系统(RDBMS)使用 SQL(Structured Query Language)来操作数据。

4. 数据库的创建

我们以 MySQL 为例,展示如何通过 Java 使用 JDBC 创建数据库、表和插入数据。

连接到 MySQL 数据库并创建数据库:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class CreateDatabaseExample {
    public static void main(String[] args) {
        String jdbcURL = "jdbc:mysql://localhost:3306/";
        String username = "root";
        String password = "password";  // 你的MySQL密码

        try (Connection connection = DriverManager.getConnection(jdbcURL, username, password)) {
            Statement statement = connection.createStatement();
            String sql = "CREATE DATABASE IF NOT EXISTS TestDB";
            statement.executeUpdate(sql);
            System.out.println("Database created successfully");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

创建表并插入数据:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class CreateTableExample {
    public static void main(String[] args) {
        String jdbcURL = "jdbc:mysql://localhost:3306/TestDB";
        String username = "root";
        String password = "password";

        try (Connection connection = DriverManager.getConnection(jdbcURL, username, password)) {
            Statement statement = connection.createStatement();
            
            // 创建表
            String createTableSQL = "CREATE TABLE IF NOT EXISTS Users (" +
                                    "ID INT PRIMARY KEY AUTO_INCREMENT, " +
                                    "Name VARCHAR(50), " +
                                    "Email VARCHAR(50))";
            statement.executeUpdate(createTableSQL);
            System.out.println("Table created successfully");

            // 插入数据
            String insertSQL = "INSERT INTO Users (Name, Email) VALUES ('Alice', 'alice@example.com')";
            statement.executeUpdate(insertSQL);
            System.out.println("Data inserted successfully");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5. 数据库的规范化

数据库规范化是一个设计过程,其目的是通过消除数据冗余、确保数据一致性来提高数据库的效率。规范化将数据库分为多个表,并通过外键(foreign key)来保持数据的关系。

  • 第一范式(1NF):确保每个表中的字段是不可分的原子值。
  • 第二范式(2NF):消除部分依赖,即非主键字段必须完全依赖主键。
  • 第三范式(3NF):消除传递依赖,非主键字段不应该依赖其他非主键字段。

举例:规范化一个数据库

假设我们有一个未规范化的表 Orders,它包括订单信息和客户信息:

OrderIDCustomerNameCustomerAddressProductNameQuantity
1Alice123 StreetLaptop1
2Bob456 AvenuePhone2

为了规范化,我们可以将这个表拆分为两个表,一个存储订单信息,另一个存储客户信息。

  • Orders

    OrderIDCustomerIDProductNameQuantity
    1101Laptop1
    2102Phone2
  • Customers

    CustomerIDCustomerNameCustomerAddress
    101Alice123 Street
    102Bob456 Avenue

这样,客户的信息被单独存储,每次订单只需引用客户的 CustomerID,避免了重复存储客户数据。

补充

BCNF(Boyce-Codd范式)是第三范式(3NF)的一个更严格的版本。它的目标是确保每个非平凡的函数依赖关系都符合范式要求,进一步消除数据冗余和异常情况。

BCNF 的定义

BCNF 要求:

  • 表格中的每一个决定属性(determinant)必须是一个候选键。

候选键是表中的唯一标识一个记录的字段或字段组合。

如果一个表已经满足第三范式,但仍然存在非主属性依赖于非主键的情况,就需要将表进一步分解到 BCNF。

BCNF 与 3NF 的区别

BCNF 主要解决的是 3NF 不能解决的“非主属性依赖于候选键的部分”问题。简单来说:

  • 3NF 解决非主键字段对主键的传递依赖问题。
  • BCNF 解决主属性依赖于非主键的问题(候选键的依赖关系)。

BCNF 的例子

假设我们有一个表 StudentCourse,记录学生选修课程的情况:

StudentIDCourseIDInstructorInstructorOffice
1CS101Dr. SmithRoom 101
2CS101Dr. SmithRoom 101
3CS102Dr. JohnsonRoom 202
  • StudentID 是学生的唯一标识。
  • CourseID 是课程的唯一标识。
  • Instructor 是课程的授课老师,每个课程由一个固定的老师教授,并且每个老师都有一个固定的办公室。

在这个例子中,我们可以看到以下依赖关系:

  • StudentID -> CourseID
  • CourseID -> InstructorInstructorOffice

我们可以看到,CourseID 决定了 InstructorInstructorOffice,这意味着 InstructorInstructorOffice 依赖于 CourseID,而不是完全依赖于 StudentID(主键)。

此时,虽然这个表可能已经符合 3NF,但它并不符合 BCNF,因为 CourseID 是一个决定属性,但它不是候选键(即它不能唯一标识一行)。

将表分解为 BCNF

要将这个表分解为符合 BCNF 的表格,我们需要把 InstructorInstructorOffice 的依赖从原始表中移除。我们可以创建两个表:

  1. StudentCourse

    StudentIDCourseID
    1CS101
    2CS101
    3CS102
  2. CourseInstructor

    CourseIDInstructorInstructorOffice
    CS101Dr. SmithRoom 101
    CS102Dr. JohnsonRoom 202

现在,StudentCourse 表中每一行的数据依赖于候选键 StudentID,而 CourseInstructor 表中,每一行的数据依赖于候选键 CourseID,这就满足了 BCNF。

BCNF 的总结

  • BCNF 是 3NF 的加强版本,它消除了 3NF 不能消除的某些依赖关系。
  • BCNF 的要求是每一个决定属性必须是候选键。
  • 当表中的非主键属性依赖于候选键的部分属性时,就需要将其分解到 BCNF。

通过将表分解为多个表,BCNF 进一步减少了数据冗余,并确保了数据一致性和完整性。

总结

  • 数据库 是存储和管理数据的工具,常见的数据库有 MySQL、PostgreSQL、MongoDB 等。
  • 数据模型 描述了数据的组织方式,关系模型是最常见的数据模型。
  • 数据库创建 通过 SQL 和 JDBC 实现,Java 提供了强大的工具来与数据库进行交互。
  • 数据库规范化 是设计数据库的关键步骤,可以消除冗余并提高数据的完整性。

SQL

1. SQL 简介

SQL(Structured Query Language,结构化查询语言)是一种用于管理关系型数据库的数据查询语言。它允许用户执行以下操作:

  • 查询数据(SELECT)
  • 插入数据(INSERT)
  • 更新数据(UPDATE)
  • 删除数据(DELETE)
  • 创建表修改表结构(CREATE、ALTER、DROP)

2. 创建数据库和表

2.1 创建数据库

CREATE DATABASE TestDB;

2.2 选择数据库

USE TestDB;

2.3 创建表

CREATE TABLE Users (
    ID INT PRIMARY KEY AUTO_INCREMENT,
    Name VARCHAR(50),
    Email VARCHAR(50),
    Age INT
);

3. 插入数据

INSERT INTO Users (Name, Email, Age)
VALUES ('Alice', 'alice@example.com', 25);

INSERT INTO Users (Name, Email, Age)
VALUES ('Bob', 'bob@example.com', 30);

4. 查询数据

4.1 查询所有列

SELECT * FROM Users;

4.2 查询指定列

SELECT Name, Email FROM Users;

4.3 添加条件(WHERE)

SELECT * FROM Users WHERE Age > 25;

4.4 使用 ANDOR 条件

SELECT * FROM Users WHERE Age > 25 AND Name = 'Bob';

4.5 使用 LIKE 模糊匹配

SELECT * FROM Users WHERE Name LIKE 'A%';  -- 查找名字以A开头的用户

4.6 排序查询结果(ORDER BY)

SELECT * FROM Users ORDER BY Age DESC;

5. 更新数据

UPDATE Users
SET Age = 26
WHERE Name = 'Alice';

6. 删除数据

6.1 删除特定数据

DELETE FROM Users WHERE Name = 'Bob';

6.2 删除所有数据

DELETE FROM Users;  -- 仅删除数据,保留表结构

7. 表的修改

7.1 添加新列

ALTER TABLE Users ADD PhoneNumber VARCHAR(15);

7.2 修改列的数据类型

ALTER TABLE Users MODIFY Email VARCHAR(100);

7.3 删除列

ALTER TABLE Users DROP COLUMN PhoneNumber;

8. 连接查询(JOIN)

8.1 内连接(INNER JOIN)

SELECT Orders.OrderID, Users.Name, Orders.Product
FROM Orders
INNER JOIN Users ON Orders.UserID = Users.ID;

8.2 左连接(LEFT JOIN)

SELECT Users.Name, Orders.Product
FROM Users
LEFT JOIN Orders ON Users.ID = Orders.UserID;

9. 聚合函数

9.1 计数(COUNT)

SELECT COUNT(*) FROM Users;

9.2 最大值、最小值(MAX, MIN)

SELECT MAX(Age) FROM Users;
SELECT MIN(Age) FROM Users;

9.3 平均值(AVG)

SELECT AVG(Age) FROM Users;

9.4 求和(SUM)

SELECT SUM(Age) FROM Users;

10. 分组(GROUP BY)

SELECT Age, COUNT(*) FROM Users
GROUP BY Age;

11. 子查询

11.1 简单子查询

SELECT Name FROM Users
WHERE Age = (SELECT MAX(Age) FROM Users);

11.2 关联子查询

SELECT Name FROM Users u
WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.UserID = u.ID);

12. 视图(View)

12.1 创建视图

CREATE VIEW UserOrders AS
SELECT Users.Name, Orders.Product
FROM Users
JOIN Orders ON Users.ID = Orders.UserID;

12.2 查询视图

SELECT * FROM UserOrders;

12.3 删除视图

DROP VIEW UserOrders;

13. 事务(Transactions)

事务确保一系列的 SQL 操作要么全部成功,要么全部失败。

13.1 开始事务

START TRANSACTION;

13.2 提交事务

COMMIT;

13.3 回滚事务

ROLLBACK;

14. 索引(Indexes)

索引用于加速数据检索。

14.1 创建索引

CREATE INDEX idx_name ON Users (Name);

14.2 删除索引

DROP INDEX idx_name ON Users;

15. 数据库的约束

  • NOT NULL:确保字段不能为空。
  • UNIQUE:确保字段中的所有值唯一。
  • PRIMARY KEY:唯一标识表中的每条记录。
  • FOREIGN KEY:用来链接两个表。

15.1 创建带约束的表

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    UserID INT,
    Product VARCHAR(100),
    FOREIGN KEY (UserID) REFERENCES Users(ID)
);

16. 正则化(Normalization)

数据库的正则化用于减少冗余数据并确保数据一致性。常见的正则化范式包括:

  • 第一范式 (1NF):消除重复的列,确保每列原子化。
  • 第二范式 (2NF):消除部分依赖,确保所有非主键字段依赖于主键。
  • 第三范式 (3NF):消除传递依赖,确保非主键字段不依赖于其他非主键字段。
  • BCNF:消除所有非主键依赖。

数据库查询语言(DQL)

在 SQL 中,根据操作类型的不同,可以将 SQL 分为不同的类别,如数据定义语言(DDL)、数据操纵语言(DML)、数据库查询语言(DQL)和数据库控制语言(DCL)。下面我们专注于 数据库查询语言(DQL)数据库控制语言(DCL)

1. 数据库查询语言(DQL)

DQL(Data Query Language,数据查询语言)主要用于从数据库中检索数据。它的核心命令是 SELECT,允许用户执行复杂的查询操作,如过滤、排序、分组、聚合等。

核心语句:SELECT

SELECT 语句是 DQL 的基础,它允许从一个或多个表中检索数据。

基础用法

SELECT column1, column2, ...
FROM table_name;
  • column1, column2:要检索的列。
  • table_name:数据所在的表名。

DQL 常见操作

  1. 查询所有数据

    SELECT * FROM Users;
    
    • 使用 * 可以检索表中的所有列。
  2. 条件查询(WHERE)

    SELECT Name, Email FROM Users WHERE Age > 25;
    
    • WHERE 子句用于过滤结果。
  3. 排序查询结果(ORDER BY)

    SELECT Name, Age FROM Users ORDER BY Age DESC;
    
    • ORDER BY 用于按指定列排序,ASC 表示升序(默认),DESC 表示降序。
  4. 分组(GROUP BY)

    SELECT Age, COUNT(*) FROM Users GROUP BY Age;
    
    • GROUP BY 用于对结果进行分组。
  5. 聚合函数

    • COUNT:计数。
    • SUM:求和。
    • AVG:求平均值。
    • MAX:求最大值。
    • MIN:求最小值。

    例子:

    SELECT AVG(Age) FROM Users;
    
  6. 连接查询(JOIN)

    SELECT Orders.OrderID, Users.Name, Orders.Product
    FROM Orders
    INNER JOIN Users ON Orders.UserID = Users.ID;
    
    • INNER JOIN 通过匹配两个表的字段来获取相关联的数据。

复杂查询示例

SELECT u.Name, u.Email, o.Product
FROM Users u
INNER JOIN Orders o ON u.ID = o.UserID
WHERE u.Age > 25
ORDER BY u.Name ASC;
  • 该查询会检索用户 Users 和订单 Orders 中的相关数据,按用户名升序排列。

2. 数据库控制语言(DCL)

DCL(Data Control Language,数据控制语言)用于控制数据库中的权限和访问,主要是对用户的权限进行授予和撤销,确保数据库的安全性。

核心语句:GRANTREVOKE
  • GRANT:用于向用户授予权限。
  • REVOKE:用于从用户撤销权限。
常见 DCL 操作
  1. 创建用户
    在授予权限之前,通常需要先创建用户:

    CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
    
    • username 是新用户的用户名,password 是用户的密码。
  2. 授予权限(GRANT)

    GRANT SELECT, INSERT ON TestDB.Users TO 'username'@'localhost';
    
    • 该语句授予用户 usernameTestDB 数据库中的 Users 表执行 SELECT(查询)和 INSERT(插入)的权限。
  3. 查看当前用户的权限

    SHOW GRANTS FOR 'username'@'localhost';
    
    • 该语句显示给定用户的权限列表。
  4. 撤销权限(REVOKE)

    REVOKE SELECT ON TestDB.Users FROM 'username'@'localhost';
    
    • 该语句撤销用户 usernameTestDB.Users 表的 SELECT 权限。
  5. 授予所有权限

    GRANT ALL PRIVILEGES ON TestDB.* TO 'username'@'localhost';
    
    • ALL PRIVILEGES 表示授予所有权限,TestDB.* 表示该用户拥有对 TestDB 数据库中所有表的完全访问权限。
  6. 撤销所有权限

    REVOKE ALL PRIVILEGES ON TestDB.* FROM 'username'@'localhost';
    
    • 该语句撤销用户对 TestDB 数据库中所有表的所有权限。
权限级别

权限可以在不同级别上授予:

  • 数据库级别:对整个数据库授予权限。
    GRANT SELECT ON TestDB.* TO 'username'@'localhost';
    
  • 表级别:仅对指定表授予权限。
    GRANT INSERT, UPDATE ON TestDB.Users TO 'username'@'localhost';
    
  • 列级别:仅对指定列授予权限。
    GRANT SELECT (Name, Email) ON TestDB.Users TO 'username'@'localhost';
    
  • 特定操作:如授予某些高级权限,比如 GRANT OPTION 允许用户向其他用户授予权限。

3. 总结

DQL(数据库查询语言)
  • 主要用于从数据库中检索数据,核心命令是 SELECT
  • 可以通过 WHEREORDER BYGROUP BYJOIN 等来实现复杂查询和数据分析。
DCL(数据库控制语言)
  • 用于管理用户权限,确保数据库安全。
  • GRANT 用于授予权限,REVOKE 用于撤销权限。

通过熟练掌握 DQL 和 DCL,您可以轻松实现数据库的数据查询操作,并确保数据库访问的安全性。

视图、索引、触发器、事务

1. 视图(View)

概念

视图是一个虚拟表,它基于 SQL 查询的结果集。视图并不存储实际数据,它只是一个查询的逻辑表示,帮助简化复杂查询、提高安全性和增强数据抽象。

使用场景
  • 简化查询:将复杂的 SQL 查询封装在视图中,简化数据访问。
  • 数据安全:通过视图限制用户对敏感数据的访问。
  • 提高可重用性:避免多次重复相同的复杂查询。

创建视图的语法

CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

视图的示例

创建一个显示用户信息的视图:

CREATE VIEW UserDetails AS
SELECT Name, Email, Age
FROM Users
WHERE Age > 18;

现在你可以像查询表一样查询 UserDetails 视图:

SELECT * FROM UserDetails;

更新视图

有些视图是可更新的,允许通过视图更新基础表的数据。更新视图的语法与更新表相同:

UPDATE UserDetails
SET Age = 30
WHERE Name = 'Alice';

注意:并不是所有视图都是可更新的,尤其是涉及到多表连接、聚合等操作的视图。

删除视图

DROP VIEW UserDetails;

2. 索引(Index)

概念

索引是数据库对象,用于加快查询操作的速度。索引类似于书本的目录,它使得数据库能够更快速地定位所需数据。

使用场景

  • 加速查询:大幅提高 SELECT 语句的执行速度。
  • 强制唯一性:例如在主键或唯一约束上创建索引。
  • 排序:索引还可以用于加速排序操作(ORDER BY)。

创建索引的语法

CREATE INDEX index_name ON table_name (column1, column2, ...);

索引的示例

Users 表的 Name 列创建索引:

CREATE INDEX idx_name ON Users (Name);

删除索引

DROP INDEX idx_name ON Users;

索引的注意事项

  • 虽然索引能加速查询,但也会占用存储空间,并可能减慢插入、更新和删除操作。
  • 不要在小表或者频繁更新的列上创建索引,因为索引维护的开销可能大于它带来的性能提升。

3. 触发器(Trigger)

概念

触发器是一个自动执行的 SQL 语句,它在某些事件发生时触发。触发器通常与 INSERTUPDATEDELETE 操作相关联,能够在这些操作之前或之后自动执行某些操作。

使用场景
  • 数据完整性:确保在插入或更新数据时满足特定业务规则。
  • 自动日志记录:在数据更新时自动保存修改记录。
  • 复杂验证:在数据修改前后执行复杂的业务逻辑。

创建触发器的语法

CREATE TRIGGER trigger_name
AFTER | BEFORE INSERT | UPDATE | DELETE
ON table_name
FOR EACH ROW
BEGIN
    -- 触发器逻辑
END;

触发器的示例

Users 表中创建一个触发器,当插入新用户时,自动将他们的姓名转换为大写:

CREATE TRIGGER before_insert_user
BEFORE INSERT ON Users
FOR EACH ROW
BEGIN
    SET NEW.Name = UPPER(NEW.Name);
END;
  • BEFORE:在 INSERT 之前触发。
  • NEW:表示新插入的数据。

删除触发器

DROP TRIGGER trigger_name;

触发器的注意事项

  • 触发器是自动执行的,因此要谨慎使用,以免引起循环或性能问题。
  • 过多的触发器会影响数据库的性能,尤其是高频率触发的操作。

4. 事务(Transaction)

概念

事务是一组 SQL 操作的集合,这些操作要么全部成功,要么全部失败。事务的主要作用是保证数据库的完整性和一致性,尤其是在涉及多个表的复杂操作时。事务遵循 ACID 特性:

  • A(原子性):事务是不可分割的操作单位,要么全部完成,要么全部不执行。
  • C(一致性):事务执行前后,数据库处于一致的状态。
  • I(隔离性):多个事务并发执行时,互不干扰。
  • D(持久性):事务提交后,其结果永久保存,即使数据库系统崩溃。

使用场景

  • 多步操作:比如银行转账,涉及账户扣款和存款,两步操作必须要么都成功,要么都失败。
  • 数据一致性要求:确保多个相关表的更新操作一致完成。

事务的语法

  1. 开启事务

    START TRANSACTION;
    
  2. 提交事务

    COMMIT;
    
  3. 回滚事务(撤销未提交的更改):

    ROLLBACK;
    

事务的示例

银行转账示例,用户 A 转账给用户 B:

START TRANSACTION;

-- 从用户 A 的账户中扣除 100
UPDATE Accounts
SET Balance = Balance - 100
WHERE UserID = 'A';

-- 向用户 B 的账户中存入 100
UPDATE Accounts
SET Balance = Balance + 100
WHERE UserID = 'B';

-- 提交事务
COMMIT;

如果在操作过程中任何一步失败,则可以回滚事务,取消所有更改:

ROLLBACK;

自动提交和手动提交

  • 默认情况下,很多数据库系统(如 MySQL)在每个独立的 SQL 语句之后自动提交事务。这种模式称为 自动提交
  • 如果你想要手动控制事务,应该禁用自动提交:
    SET AUTOCOMMIT = 0;
    

事务的注意事项

  • 在执行批量操作时,使用事务可以保证数据一致性。
  • 过多的长时间事务会锁定资源,导致性能下降,因此要合理使用事务。

总结

  • 视图:视图是 SQL 查询的逻辑表示,它帮助简化查询、提高安全性和数据抽象。
  • 索引:索引用于加快查询速度,但需要权衡其在插入、更新和删除操作上的性能开销。
  • 触发器:触发器是在特定事件发生时自动执行的 SQL 语句,适用于确保数据完整性和自动化操作。
  • 事务:事务是一组 SQL 操作,确保数据库在操作失败时保持一致性,并遵循 ACID 原则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值