7、将逻辑迁移到数据库:优化与实践

将逻辑迁移到数据库:优化与实践

1. 引言

在现代软件开发中,数据库不仅是数据存储的地方,更是执行业务逻辑的重要场所。将应用程序中的逻辑迁移到数据库层,不仅可以提高系统的性能和安全性,还能简化应用程序代码,减少网络流量。本文将详细介绍如何通过创建存储过程、视图、用户定义函数(UDF)等数据库对象来实现这一目标,并确保数据的完整性和一致性。

2. 创建表和约束

数据库的核心对象是表,它是存储数据的基本单位。创建表时,除了定义列及其数据类型外,还需要设置约束来保证数据的正确性和完整性。常见的约束包括主键、外键、唯一约束和默认值等。

2.1 主键约束

主键约束用于唯一标识表中的每一行。主键列不能包含重复值或NULL值。以下是一个创建带有主键约束的表的示例:

CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    FirstName VARCHAR(50),
    LastName VARCHAR(50),
    HireDate DATE
);

2.2 外键约束

外键约束用于维护表之间的引用完整性。外键列的值必须存在于引用表的主键列中。例如,创建一个订单表并设置外键约束:

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    EmployeeID INT,
    OrderDate DATE,
    FOREIGN KEY (EmployeeID) REFERENCES Employees(EmployeeID)
);

2.3 唯一约束

唯一约束确保某一列或多列的组合值在整个表中是唯一的。以下是一个创建带有唯一约束的表的示例:

CREATE TABLE Customers (
    CustomerID INT PRIMARY KEY,
    Email VARCHAR(100) UNIQUE,
    FirstName VARCHAR(50),
    LastName VARCHAR(50)
);

2.4 默认值约束

默认值约束用于在插入新行时自动为某列赋值。例如,为订单表的订单日期设置默认值:

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    EmployeeID INT,
    OrderDate DATE DEFAULT GETDATE(),
    FOREIGN KEY (EmployeeID) REFERENCES Employees(EmployeeID)
);

3. 创建视图

视图是一种虚拟表,它基于SQL查询结果。视图可以帮助简化复杂的查询,并提供一种安全且易于访问的方式来呈现数据。创建视图的语法如下:

CREATE VIEW vw_EmployeeDetails AS
SELECT EmployeeID, FirstName, LastName, HireDate
FROM Employees;

使用视图可以隐藏底层表的复杂性,同时提供一致的数据视图。视图还可以用于实现数据抽象和访问控制。

4. 创建用户定义函数(UDF)

用户定义函数(UDF)是存储在数据库中的自定义函数,用于封装可重用的逻辑片段。UDF分为两种类型:标量值函数和表值函数。

4.1 标量值函数

标量值函数返回单个值。以下是一个计算两个整数之和的标量值函数:

CREATE FUNCTION fn_AddTwoNumbers (@Num1 INT, @Num2 INT)
RETURNS INT
AS
BEGIN
    RETURN (@Num1 + @Num2);
END;

使用标量值函数可以简化查询逻辑。例如:

SELECT EmployeeID, FirstName, LastName, dbo.fn_AddTwoNumbers(10, 20) AS Sum
FROM Employees;

4.2 表值函数

表值函数返回一个记录集。以下是一个返回员工详细信息的表值函数:

CREATE FUNCTION fn_GetEmployeeDetails (@EmployeeID INT)
RETURNS TABLE
AS
RETURN (
    SELECT EmployeeID, FirstName, LastName, HireDate
    FROM Employees
    WHERE EmployeeID = @EmployeeID
);

表值函数可以用于替代表,或者将结果保存到临时表或表变量中,稍后在脚本中使用。例如:

SELECT * FROM dbo.fn_GetEmployeeDetails(1);

5. 创建存储过程

存储过程是存储在数据库中的预编译SQL语句集合,用于封装复杂的业务逻辑。存储过程可以包含编程逻辑、更新数据、创建其他对象等。以下是一个简单的存储过程示例:

CREATE PROCEDURE sp_InsertEmployee
    @FirstName VARCHAR(50),
    @LastName VARCHAR(50),
    @HireDate DATE
AS
BEGIN
    INSERT INTO Employees (FirstName, LastName, HireDate)
    VALUES (@FirstName, @LastName, @HireDate);
END;

存储过程可以提高系统的安全性和性能,同时简化应用程序代码。以下是使用存储过程的流程图:

graph TD;
    A[调用存储过程] --> B[验证输入参数];
    B --> C[执行SQL语句];
    C --> D[返回结果或状态];

存储过程还可以用于防止SQL注入攻击。黑客通过SQL注入技术将恶意SQL命令插入Web表单中,最终接管数据库、服务器和网络。存储过程通过参数化查询有效防止此类攻击。

6. 性能考虑

虽然UDF和存储过程可以简化开发并提高安全性,但也需要注意性能问题。特别是当UDF在查询中内联访问数据时,数据库引擎将不得不为查询的每一行执行该函数,可能导致性能下降。以下是一个演示性能问题的示例:

-- 创建用户定义函数
CREATE FUNCTION udf_ProductTotal (@ProductID INT, @Year INT)
RETURNS MONEY
AS
BEGIN
    DECLARE @Sum MONEY;
    SELECT @Sum = SUM(LineTotal)
    FROM Sales.SalesOrderDetail AS sod
    INNER JOIN Sales.SalesOrderHeader AS soh
        ON sod.SalesOrderID = soh.SalesOrderID
    WHERE ProductID = @ProductID AND YEAR(OrderDate) = @Year;
    RETURN ISNULL(@Sum, 0);
END;

-- 测试查询性能
SELECT ProductID, dbo.udf_ProductTotal(ProductID, 2004) AS SumOfSales
FROM Production.Product
ORDER BY SumOfSales DESC;

为了避免性能问题,建议尽量减少在查询中使用内联访问数据的UDF,或者通过优化查询和索引来提高性能。


以上内容介绍了如何通过创建表、视图、用户定义函数和存储过程将应用程序中的逻辑迁移到数据库层。通过合理使用这些数据库对象,不仅可以提高系统的性能和安全性,还能简化应用程序代码,减少网络流量。下一部分将继续探讨更多高级主题,如触发器和数据类型等。

7. 触发器

触发器是SQL Server中一个非常强大的特性,类似于一种特殊的存储过程,每当数据被修改时就会自动运行。触发器可以在表上定义,以响应插入、更新或删除操作。它们可以用于强制执行数据完整性规则、记录审计信息或执行其他业务逻辑。

7.1 插入触发器

插入触发器在插入新行时触发。以下是一个插入触发器的示例,用于记录每次插入新员工时的日志:

CREATE TRIGGER tr_InsertEmployeeLog
ON Employees
AFTER INSERT
AS
BEGIN
    INSERT INTO EmployeeLog (EmployeeID, Action, LogDate)
    SELECT i.EmployeeID, 'Inserted', GETDATE()
    FROM inserted i;
END;

7.2 更新触发器

更新触发器在更新现有行时触发。以下是一个更新触发器的示例,用于记录每次更新员工信息时的日志:

CREATE TRIGGER tr_UpdateEmployeeLog
ON Employees
AFTER UPDATE
AS
BEGIN
    INSERT INTO EmployeeLog (EmployeeID, Action, LogDate)
    SELECT i.EmployeeID, 'Updated', GETDATE()
    FROM inserted i;
END;

7.3 删除触发器

删除触发器在删除现有行时触发。以下是一个删除触发器的示例,用于记录每次删除员工信息时的日志:

CREATE TRIGGER tr_DeleteEmployeeLog
ON Employees
AFTER DELETE
AS
BEGIN
    INSERT INTO EmployeeLog (EmployeeID, Action, LogDate)
    SELECT d.EmployeeID, 'Deleted', GETDATE()
    FROM deleted d;
END;

触发器可以显著影响性能,因此必须谨慎使用。触发器内的任何代码都必须非常高效,因为触发器触发的事务在触发器成功完成之前无法完成。此外,触发器可能会引发递归问题,导致性能瓶颈。

8. 数据类型

SQL Server提供了丰富的数据类型,用于存储各种类型的数据,包括字符串、数字、货币、XML、二进制和时间数据。选择合适的数据类型可以提高性能并确保数据的准确性和一致性。

8.1 字符串数据类型

字符串数据类型用于存储文本数据。常见的字符串数据类型包括 CHAR 、 VARCHAR 、 NCHAR 和 NVARCHAR 。以下是一个使用字符串数据类型的示例:

CREATE TABLE Contacts (
    ContactID INT PRIMARY KEY,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    Email NVARCHAR(100)
);

8.2 数值数据类型

数值数据类型用于存储数字数据。常见的数值数据类型包括 INT 、 BIGINT 、 DECIMAL 和 FLOAT 。以下是一个使用数值数据类型的示例:

CREATE TABLE Products (
    ProductID INT PRIMARY KEY,
    Name NVARCHAR(100),
    Price DECIMAL(18, 2),
    Quantity INT
);

8.3 时间和日期数据类型

时间和日期数据类型用于存储日期和时间信息。常见的日期和时间数据类型包括 DATE 、 DATETIME 、 SMALLDATETIME 和 TIME 。以下是一个使用时间和日期数据类型的示例:

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    OrderDate DATETIME,
    DeliveryDate DATE
);

8.4 用户定义类型(UDT)

用户定义类型(UDT)允许您创建自定义数据类型。UDT可以基于现有的SQL Server数据类型或.NET公共语言运行时(CLR)数据类型。以下是一个创建用户定义类型的示例:

CREATE TYPE dbo.CustomerID FROM INT NOT NULL;

UDT可以用于定义新表中的列,从而提高代码的可读性和一致性。

9. 数据定义语言(DDL)触发器

DDL触发器是在数据库或服务器级别定义的触发器,用于响应数据定义语言事件(如创建表、添加登录等)。DDL触发器可以用于记录这些事件或阻止某些操作。以下是一个DDL触发器的示例,用于记录创建表的事件:

CREATE TRIGGER tr_LogCreateTable
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
    INSERT INTO DDLLog (EventTime, EventType, EventSQL)
    VALUES (GETDATE(), EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]', 'NVARCHAR(100)'),
            EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'NVARCHAR(MAX)'));
END;

DDL触发器可以有效地监控和管理数据库结构的变化,确保数据定义的合规性和一致性。

10. 实践案例

为了更好地理解如何将逻辑迁移到数据库层,以下是一个完整的实践案例,演示如何创建存储过程、用户定义函数和触发器来管理订单和客户信息。

10.1 创建订单表和客户表

首先,创建订单表和客户表,并设置必要的约束:

CREATE TABLE Customers (
    CustomerID INT PRIMARY KEY,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    Email NVARCHAR(100) UNIQUE
);

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    CustomerID INT,
    OrderDate DATETIME DEFAULT GETDATE(),
    FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);

10.2 创建存储过程

接下来,创建一个存储过程用于插入新订单:

CREATE PROCEDURE sp_InsertOrder
    @CustomerID INT,
    @OrderDate DATETIME
AS
BEGIN
    INSERT INTO Orders (CustomerID, OrderDate)
    VALUES (@CustomerID, @OrderDate);
END;

10.3 创建用户定义函数

创建一个用户定义函数用于计算客户的订单总数:

CREATE FUNCTION fn_GetOrderCount (@CustomerID INT)
RETURNS INT
AS
BEGIN
    DECLARE @OrderCount INT;
    SELECT @OrderCount = COUNT(*)
    FROM Orders
    WHERE CustomerID = @CustomerID;
    RETURN @OrderCount;
END;

10.4 创建触发器

最后,创建一个触发器用于记录每次插入新订单时的日志:

CREATE TRIGGER tr_InsertOrderLog
ON Orders
AFTER INSERT
AS
BEGIN
    INSERT INTO OrderLog (OrderID, Action, LogDate)
    SELECT i.OrderID, 'Inserted', GETDATE()
    FROM inserted i;
END;

通过以上步骤,您可以将应用程序中的逻辑迁移到数据库层,从而提高系统的性能和安全性,同时简化应用程序代码,减少网络流量。

功能 描述
存储过程 封装复杂的业务逻辑,简化应用程序代码
用户定义函数 封装可重用的逻辑片段,简化查询
触发器 自动执行业务逻辑,确保数据完整性

通过合理使用这些数据库对象,不仅可以提高系统的性能和安全性,还能简化应用程序代码,减少网络流量。数据库编程不仅限于简单的数据操作,还包括高效的逻辑管理和性能优化。

graph TD;
    A[创建订单表和客户表] --> B[创建存储过程];
    B --> C[创建用户定义函数];
    C --> D[创建触发器];
    D --> E[测试和优化];

通过本文的介绍,您应该对如何将应用程序中的逻辑迁移到数据库层有了更深入的理解。合理使用存储过程、用户定义函数、视图和触发器等数据库对象,不仅可以提高系统的性能和安全性,还能简化应用程序代码,减少网络流量。希望这些内容能帮助您在未来的项目中更好地优化数据库应用。

Laravel数据库迁移与填充器:从手动建表到可版本化数据契约 数据库迁移是现代Web应用实现数据结构版本控制的核心机制,其本质是将DDL操作转化为可执行、可回滚、可协作的代码资产。基于PHP语言的Laravel Migration通过Schema Builder抽象SQL方言差异,支持条件逻辑与跨库兼容;Seeder则超越假数据生成,成为验证模型完整性与业务规则的集成测试载体。结合artisan命令管道、migrations表审计机制及CI/CD标准化流程,该方案显著提升中小型系统的环境一致性、发布可靠性与团队知识沉淀效率。关键词:Laravel、Database M 阅读详情

相关推荐

数据库迁移方案

从Oracle迁移到国产数据库是一项昂贵且耗时的任务,要了解要迁移的范围,不要浪费时间来迁移不再需要的对象。另外,检查是否需要迁移所有的历史数据,不要浪费时间来复制不需要的数据,例如过去维护中的备份数据和临时表。经过初步检查后,迁移的第一步是分析数据库信息和业务应用信息,找出两个数据库之间不兼容的特性,并估算迁移所需的时间(迁移工具效率)和成本(据库部署情况、数据量大小)。1.数据迁移试验 针对4数据迁移方案进行试验,调试割接脚本、稽核脚本,并对步骤时长进行记录和分析,优化执行瓶颈。

芦金宇的专栏 3403

Kettle 7.0数据库迁移实战指南

Kettle(Pentaho Data Integration, PDI)是一个开源的ETL工具,它拥有强大的数据抽取、转换和加载功能。它是Pentaho BI套件的一部分,由社区驱动,随着技术的进步不断进化。Kettle 7.0版本带来了更多的功能更新,使数据处理工作更加高效和可靠。Spoon是Kettle的主要用户界面工具,提供了设计ETL转换和作业的工作台。Spoon的界面设计遵循了典型的多窗口模式,主要可以分为以下几个部分:菜单栏。

weixin_42551310的博客 961

倍福Beckhoff运动控制功能块实战解析:从MC_ReadActualPosition到MC_GearInVelo

本文深入解析倍福(Beckhoff)TwinCAT运动控制功能块,从基础的MC_ReadActualPosition、MC_Power等轴状态读取与使能操作,到MC_MoveAbsolute、MC_MoveRelative等单轴定位指令,并重点剖析了用于动态速度同步的核心功能块MC_GearInVelo在飞锯等场景的应用。文章结合实战经验,详细介绍了齿轮耦合、电子凸轮(MC_CamIn)等高级同步功能的参数配置、调试技巧及常见问题,旨在帮助工程师快速掌握倍福运动控制工具箱,实现复杂的同步工艺。

transformer2023的博客 981

从零开始:使用Mask2Former训练你的专属数据集

本文详细介绍了如何从零开始使用Mask2Former训练自定义数据集。内容涵盖环境搭建、数据准备(将LabelMe格式转换为COCO格式)、数据集注册与模型配置、训练启动与调试,以及最终的模型推理与应用。通过实战步骤和常见问题解决方案,帮助读者掌握使用Mask2Former进行实例分割的核心流程,实现专属模型的训练与部署。

weixin_28678151的博客 444

STM32踩坑--NoST-LINK detected

这里出现的NoST-LINK detected是没有扫描到端口 在我使用一段Fly-MCU后,有一天突然发现出现如上错误,再检查的过程中检查以下几点 1.STM32 魔术棒的设置 1.1Debug设置 1.2 utilities 设置没有问题,与原来一样又看了下端口——在设备管理器中;也没有问题 ...

qq_53002477的博客 2万+

国产平替NeuroSky?实测金牛座TGAM脑电模块,从Arduino到Python的完整数据采集指南

本文详细介绍了国产金牛座TGAM脑电模块的完整使用流程,包括硬件连接、数据采集和Python分析。通过Arduino和Python的实战案例,展示了如何从脑电波传感器获取并解析专注度、放松度等数据,适用于专注力训练和脑机接口开发。

weixin_30735745的博客 575

法律AI工具横评:Kimi Work与WorkBuddy,谁更适合法律人?

在人工智能技术日益普及的今天,自然语言处理(NLP)和大语言模型(LLM)正深刻改变着专业领域的工作范式。其核心原理在于通过海量数据训练,使模型能够理解、生成和推理人类语言。这一技术价值在于将从业者从繁琐、重复的信息处理工作中解放出来,极大提升工作效率与知识获取的便捷性。在法律、金融、咨询等对文本处理要求极高的行业,AI助手已展现出在文档分析、信息检索和内容生成方面的巨大潜力。具体到法律应用场景,AI工具能够辅助完成合同审查、法律检索和文书起草等核心任务,成为专业人士的得力助手。本文聚焦于近期备受关注的两款

weixin_30279671的博客 559

【ESP32】SPI SRAM memory test fail。External RAM failed memory test!

log日志报错如下:这两条报错信息表明外部 SPI SRAM(静态随机存取存储器)的内存测试失败。

weixin_56217406的博客 1024

Codex 接入国产大模型指南:客户端与 CLI 双端实战

CC Switch是目前最流行的 Codex / Claude Code 模型切换工具,内置了协议转换功能,支持几乎所有主流国产模型。核心原理Codex → 本地 8317 端口(CC Switch)→ 协议转换 → 国产模型 API整个过程对 Codex 完全透明,Codex 以为自己在跟标准的 Responses API 对话。用户类型推荐方案理由新手 / 不想折腾配置简单,免费额度够用追求稳定体验通义千问(原生接入)官方兼容,功能最完整企业用户自建 AI 网关可控性强,支持多用户管理预算有限。

篮球界最会写bug的人;程序猿中打球最菜的人。 573

PC 端微信页面拆分及 JavaFx 使用

一、前言 对于一个知识点的学习过程来说,往往使用自己熟悉的工具或方式才更易于上手。因为所有同类型的知识点在抛出复杂的流程拨云见日后,所能得到的几乎都是同样的设计思想和实现理论。 在 Java 语言桌面版开发中,直至目前共提供了三套 UI 开发方式;Awt、Swing、JavaFx,以及一些扩展组件 SWT 等。在这三套 UI 组件中,JavaFx 是最新也是最为好用的,因为他提供了丰富的功能,以及...

bugstack虫洞栈 3606

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

上一篇: 3、探索前馈神经网络:从基础到实战
下一篇: 63、P4P问题的五个解与控制点的非对称位置
寂静夜空35
博客等级 码龄3年 59粉丝 1797原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值