SQL Server用户定义的函数(UDF)使用详解

SQL Server用户定义的函数

  • 一、背景知识
    • 1.1、用户定义函数的优点
    • 1.2、函数类型
    • 1.3、指引
    • 1.4、函数中的有效语句
    • 1.5、架构绑定函数
    • 1.6、指定参数
  • 二、创建用户定义函数
    • 2.1、限制和权限
    • 2.2、标量函数示例(标量 UDF)
    • 2.3、表值函数示例
      • 2.3.1、内联表值函数 (TVF)
      • 2.3.2、多语句表值函数 (MSTVF)
  • 三、修改用户定义的函数
  • 四、删除用户定义的函数
  • 五、执行用户定义的函数
  • 六、重命名用户定义函数
  • 七、查看用户定义的函数
    • 7.1、获取函数的定义和属性
    • 7.2、获取函数的依赖项

一、背景知识

与编程语言中的函数一样,SQL Server 用户定义函数是接受参数、执行操作(如复杂计算)并将该操作的结果作为值返回的例程。返回值可以是单个标量值,也可以是结果集。
在这里插入图片描述

1.1、用户定义函数的优点

  • 模块化编程。可以创建一次函数,将其存储在数据库中,并在程序中调用它任意次数。可以独立于程序源代码修改用户定义的函数。

  • 执行速度更快。与存储过程类似,Transact-SQL 用户定义函数通过缓存计划并重用它们进行重复执行来降低 Transact-SQL 代码的编译成本。这意味着用户定义的函数不需要在每次使用时重新解析和重新优化,从而缩短执行时间。

  • 与 Transact-SQL 函数相比,CLR 函数在计算任务、字符串操作和业务逻辑方面具有显著的性能优势。事务处理 SQL 函数更适合数据访问密集型逻辑。

  • 减少网络流量。基于某些无法在单个标量表达式中表示的复杂约束筛选数据的操作可以表示为函数。然后可以在 WHERE 子句中调用该函数,以减少发送到客户端的行数。

查询中的事务处理 SQL UDF 只能在单个线程(串行执行计划)上执行。因此,使用 UDF 会抑制并行查询处理。

1.2、函数类型

  • 标量函数。用户定义的标量函数返回 RETURNS 子句中定义的类型的单个数据值。对于内联标量函数,返回的标量值是单个语句的结果。对于多语句标量函数,函数体可以包含一系列返回单个值的 Transact-SQL 语句。返回类型可以是除文本、ntext、图像、光标和时间戳之外的任何数据类型。

  • 表值函数。用户定义的表值函数 (TVF) 返回表数据类型。对于内联表值函数,没有函数体;该表是单个 SELECT 语句的结果集。有关示例,请参阅创建用户定义函数(数据库引擎)。

  • 系统功能。SQL Server 提供了许多可用于执行各种操作的系统函数;它们无法修改。

1.3、指引

导致语句被取消并继续执行模块中的下一条语句(如触发器或存储过程)的 Transact-SQL 错误在函数中处理方式不同。在函数中,此类错误会导致函数的执行停止。这反过来会导致调用函数的语句被取消。

块中的语句不能有任何副作用。函数副作用是对具有函数范围之外的资源状态的任何永久更改,例如对数据库表的修改。函数中的语句可以进行的唯一更改是对函数局部对象的更改,例如局部游标或变量。对数据库表的修改、对非函数本地游标的操作、发送电子邮件、尝试修改目录以及生成返回给用户的结果集是无法在函数中执行的操作的示例。

如果语句对发出该语句时不存在的资源产生副作用,则 SQL Server 将执行该语句。但是,SQL Server 在调用函数时不会执行该函数。

查询中指定的函数的执行次数可能因优化程序构建的执行计划而异。例如,子句中的子查询调用的函数。子查询及其函数的执行次数可能因优化程序选择的不同访问路径而异。

确定性函数必须是架构绑定的。在创建确定性函数时使用SCHEMABINDING子句。

1.4、函数中的有效语句

在函数中有效的语句类型包括:

  • DECLARE语句可用于定义函数的本地数据变量和游标。

  • 将值赋值到函数的本地对象,例如用于将值赋值给标量变量和表局部变量。

  • 引用在函数中声明、打开、关闭和释放的本地游标的游标操作。 不允许使用将数据返回到客户端的语句。只允许使用该子句将值赋值给局部变量的 FETCH 语句。

  • 流控制语句(语句除外)。

  • SELECT包含选择列表的语句,这些表达式将值分配给函数的局部变量。

  • UPDATE语句修改函数的局部表变量。

  • EXECUTE调用扩展存储过程的语句。

内置系统功能:
(1)以下非确定性内置函数可用于事务处理 SQL 用户定义函数。

  • CURRENT_TIMESTAMP
  • GET_TRANSMISSION_STATUS
  • GETDATE
  • GETUTCDATE
  • @@CONNECTIONS
  • @@CPU_BUSY
  • @@DBTS
  • @@IDLE
  • @@IO_BUSY
  • @@MAX_CONNECTIONS
  • @@PACK_RECEIVED
  • @@PACK_SENT
  • @@PACKET_ERRORS
  • @@TIMETICKS
  • @@TOTAL_ERRORS
  • @@TOTAL_READ
  • @@TOTAL_WRITE

(2)以下非确定性内置函数不能在 Transact-SQL 用户定义函数中使用。

  • NEWID
  • NEWSEQUENTIALID
  • RAND
  • TEXTPTR

1.5、架构绑定函数

CREATE FUNCTION支持将函数绑定到它引用的任何对象(如表、视图和其他用户定义函数)的架构的子句。尝试更改或删除架构绑定函数引用的任何对象失败。

必须先满足以下条件,然后才能在创建函数中指定:

  • 函数引用的所有视图和用户定义函数都必须是架构绑定的。

  • 函数引用的所有对象必须与函数位于同一数据库中。必须使用由一部分或两部分组成的名称来引用对象。

  • 必须对函数中引用的所有对象(表、视图和用户定义函数)具有权限。

可以使用 ALTER FUNCTION、ALTER FUNCTIONWITH SCHEMABINDING 删除架构绑定。该语句应重新定义函数而不指定 。

1.6、指定参数

用户定义的函数采用零个或多个输入参数,并返回标量值或表。一个函数最多可以有 1024 个输入参数。当函数的参数具有默认值时,调用函数时必须指定关键字 DEFAULT 才能获取默认值。此行为不同于用户定义存储过程中具有默认值的参数,在用户定义存储过程中,省略参数也意味着默认值。用户定义的函数不支持输出参数。

二、创建用户定义函数

2.1、限制和权限

限制:

  • 用户定义的函数不能用于执行修改数据库状态的操作。

  • 用户定义的函数不能包含以表为目标的子句。

  • 用户定义的函数不能返回多个结果集。如果需要返回多个结果集,请使用存储过程。

  • 错误处理在用户定义的函数中受到限制。UDF 不支持TRY…CATCH@ERRORRAISERROR。

  • 用户定义函数不能调用存储过程,但可以调用扩展存储过程。

  • 用户定义的函数不能使用动态 SQL 或临时表。允许使用表变量。

  • SET语句不允许在用户定义的函数中使用。

  • 不允许使用FOR XML子句。

  • 用户定义的函数可以嵌套;也就是说,一个用户定义的函数可以调用另一个用户定义的函数。嵌套级别在被调用函数开始执行时递增,在被调用函数完成执行时递减。用户定义的函数最多可嵌套 32 个级别。超过最大嵌套级别会导致整个调用函数链失败。对来自 Transact-SQL 用户定义函数的托管代码的任何引用都计为 32 级嵌套限制中的一个级别。从托管代码中调用的方法不计入此限制。

  • 以下服务代理语句不能包含在 Transact-SQL 用户定义函数的定义中:BEGIN DIALOG CONVERSATION、END CONVERSATION、GET CONVERSATION GROUP、MOVE CONVERSATION、RECEIVE、SEND。

权限:
需要数据库中的权限以及对在其中创建函数的架构的权限。如果函数指定用户定义类型,则需要CREATE FUNCTIONALTEREXECUTE该类型的权限。

2.2、标量函数示例(标量 UDF)

创建一个多语句标量函数(标量 UDF)。该函数采用一个输入值 a 并返回单个数据值,即库存中指定产品的聚合数量。

IF OBJECT_ID (N'dbo.ufnGetInventoryStock', N'FN') IS NOT NULL
    DROP FUNCTION ufnGetInventoryStock;
GO
CREATE FUNCTION dbo.ufnGetInventoryStock(@ProductID int)
RETURNS int
AS
-- Returns the stock level for the product.
BEGIN
    DECLARE @ret int;
    SELECT @ret = SUM(p.Quantity)
    FROM Production.ProductInventory p
    WHERE p.ProductID = @ProductID
        AND p.LocationID = '6';
     IF (@ret IS NULL)
        SET @ret = 0;
    RETURN @ret;
END;

使用该函数返回介于 75 和 80 之间的产品的当前库存数量。

SELECT ProductModelID, Name, dbo.ufnGetInventoryStock(ProductID)AS CurrentSupply
FROM Production.Product
WHERE ProductModelID BETWEEN 75 and 80;

2.3、表值函数示例

2.3.1、内联表值函数 (TVF)

创建一个内联表值函数 (TVF)。该函数采用一个输入参数、一个客户(商店)ID,并返回列 、 和销售到商店的每个产品的年初至今销售额的汇总。

IF OBJECT_ID (N'Sales.ufn_SalesByStore', N'IF') IS NOT NULL
    DROP FUNCTION Sales.ufn_SalesByStore;
GO
CREATE FUNCTION Sales.ufn_SalesByStore (@storeid int)
RETURNS TABLE
AS
RETURN
(
    SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS 'Total'
    FROM Production.Product AS P
    JOIN Sales.SalesOrderDetail AS SD ON SD.ProductID = P.ProductID
    JOIN Sales.SalesOrderHeader AS SH ON SH.SalesOrderID = SD.SalesOrderID
    JOIN Sales.Customer AS C ON SH.CustomerID = C.CustomerID
    WHERE C.StoreID = @storeid
    GROUP BY P.ProductID, P.Name
);

调用该函数并指定客户 ID 602。

SELECT * FROM Sales.ufn_SalesByStore (602);

2.3.2、多语句表值函数 (MSTVF)

创建一个多语句表值函数 (MSTVF)。该函数采用单个输入参数 an,并返回直接或间接向指定员工报告的所有员工的列表。然后调用该函数,指定员工 ID 109。

IF OBJECT_ID (N'dbo.ufn_FindReports', N'TF') IS NOT NULL
    DROP FUNCTION dbo.ufn_FindReports;
GO
CREATE FUNCTION dbo.ufn_FindReports (@InEmpID INTEGER)
RETURNS @retFindReports TABLE
(
    EmployeeID int primary key NOT NULL,
    FirstName nvarchar(255) NOT NULL,
    LastName nvarchar(255) NOT NULL,
    JobTitle nvarchar(50) NOT NULL,
    RecursionLevel int NOT NULL
)
--Returns a result set that lists all the employees who report to the
--specific employee directly or indirectly.*/
AS
BEGIN
WITH EMP_cte(EmployeeID, OrganizationNode, FirstName, LastName, JobTitle, RecursionLevel) -- CTE name and columns
    AS (
        SELECT e.BusinessEntityID, e.OrganizationNode, p.FirstName, p.LastName, e.JobTitle, 0 -- Get the initial list of Employees for Manager n
        FROM HumanResources.Employee e
INNER JOIN Person.Person p
ON p.BusinessEntityID = e.BusinessEntityID
        WHERE e.BusinessEntityID = @InEmpID
        UNION ALL
        SELECT e.BusinessEntityID, e.OrganizationNode, p.FirstName, p.LastName, e.JobTitle, RecursionLevel + 1 -- Join recursive member to anchor
        FROM HumanResources.Employee e
            INNER JOIN EMP_cte
            ON e.OrganizationNode.GetAncestor(1) = EMP_cte.OrganizationNode
INNER JOIN Person.Person p
ON p.BusinessEntityID = e.BusinessEntityID
        )
-- copy the required columns to the result of the function
   INSERT @retFindReports
   SELECT EmployeeID, FirstName, LastName, JobTitle, RecursionLevel
   FROM EMP_cte
   RETURN
END;
GO

调用该函数并指定员工 ID 1。

SELECT EmployeeID, FirstName, LastName, JobTitle, RecursionLevel
FROM dbo.ufn_FindReports(1);

三、修改用户定义的函数

修改用户定义函数(如下所述)不会更改函数的权限,也不会影响任何依赖函数、存储过程或触发器。
ALTER 函数不能用于执行以下任何操作:

  • 将标量值函数更改为表值函数,反之亦然。

  • 将内联函数更改为多语句函数,反之亦然。

  • 将事务处理 SQL 函数更改为 CLR 函数,反之亦然。

权限:需要对函数或架构的 ALTER 权限。如果函数指定用户定义类型,则需要对该类型具有 EXECUTE 权限。

(1)更改标量值函数。

-- Scalar-Valued Function
USE [AdventureWorks2012]
GO
ALTER FUNCTION [dbo].[ufnGetAccountingEndDate]()
RETURNS [datetime]
AS
BEGIN
    RETURN DATEADD(millisecond, -2, CONVERT(datetime, '20040701', 112));
END;

(2)更改表值函数。

-- Table-Valued Function
USE [AdventureWorks2012]
GO
ALTER FUNCTION [dbo].[ufnGetContactInformation](@PersonID int)
RETURNS @retContactInformation TABLE
(
    -- Columns returned by the function
    [PersonID] int NOT NULL,
    [FirstName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [JobTitle] [nvarchar](50) NULL,
    [BusinessEntityType] [nvarchar](50) NULL
)
AS
-- Returns the first name, last name, job title and business entity type for the specified contact.
-- Since a contact can serve multiple roles, more than one row may be returned.
BEGIN
IF @PersonID IS NOT NULL
BEGIN
     IF EXISTS(SELECT * FROM [HumanResources].[Employee] e
     WHERE e.[BusinessEntityID] = @PersonID)
     INSERT INTO @retContactInformation
          SELECT @PersonID, p.FirstName, p.LastName, e.[JobTitle], 'Employee'
          FROM [HumanResources].[Employee] AS e
          INNER JOIN [Person].[Person] p ON p.[BusinessEntityID] = e.[BusinessEntityID]
          WHERE e.[BusinessEntityID] = @PersonID;

     IF EXISTS(SELECT * FROM [Purchasing].[Vendor] AS v
     INNER JOIN [Person].[BusinessEntityContact] bec ON bec.[BusinessEntityID] = v.[BusinessEntityID]
     WHERE bec.[PersonID] = @PersonID)
     INSERT INTO @retContactInformation
          SELECT @PersonID, p.FirstName, p.LastName, ct.[Name], 'Vendor Contact'
          FROM [Purchasing].[Vendor] AS v
          INNER JOIN [Person].[BusinessEntityContact] bec ON bec.[BusinessEntityID] = v.[BusinessEntityID]
          INNER JOIN [Person].ContactType ct ON ct.[ContactTypeID] = bec.[ContactTypeID]
          INNER JOIN [Person].[Person] p ON p.[BusinessEntityID] = bec.[PersonID]
          WHERE bec.[PersonID] = @PersonID;

     IF EXISTS(SELECT * FROM [Sales].[Store] AS s
     INNER JOIN [Person].[BusinessEntityContact] bec ON bec.[BusinessEntityID] = s.[BusinessEntityID]
     WHERE bec.[PersonID] = @PersonID)
     INSERT INTO @retContactInformation
          SELECT @PersonID, p.FirstName, p.LastName, ct.[Name], 'Store Contact'
          FROM [Sales].[Store] AS s
          INNER JOIN [Person].[BusinessEntityContact] bec ON bec.[BusinessEntityID] = s.[BusinessEntityID]
          INNER JOIN [Person].ContactType ct ON ct.[ContactTypeID] = bec.[ContactTypeID]
          INNER JOIN [Person].[Person] p ON p.[BusinessEntityID] = bec.[PersonID]
          WHERE bec.[PersonID] = @PersonID;

     IF EXISTS(SELECT * FROM [Person].[Person] AS p
     INNER JOIN [Sales].[Customer] AS c ON c.[PersonID] = p.[BusinessEntityID]
     WHERE p.[BusinessEntityID] = @PersonID AND c.[StoreID] IS NULL)
     INSERT INTO @retContactInformation
          SELECT @PersonID, p.FirstName, p.LastName, NULL, 'Consumer'
          FROM [Person].[Person] AS p
          INNER JOIN [Sales].[Customer] AS c ON c.[PersonID] = p.[BusinessEntityID]
          WHERE p.[BusinessEntityID] = @PersonID AND c.[StoreID] IS NULL;
     END
RETURN;
END;

四、删除用户定义的函数

限制:

  • 如果数据库中存在引用此函数且是使用 SCHEMABINDING 创建的 Transact-SQL 函数或视图,或者存在引用该函数的计算列、CHECK 约束或 DEFAULT 约束,则无法删除该函数。

  • 如果存在引用此函数并已编制索引的计算列,则无法删除该函数。

权限:需要对函数所属架构的 ALTER 权限,或对函数具有 CONTROL 权限。

(1)创建一个用户定义的函数:

-- creates function called "Sales.ufn_SalesByStore"
USE AdventureWorks2012;
GO
CREATE FUNCTION Sales.ufn_SalesByStore (@storeid int)
RETURNS TABLE
AS
RETURN
(
    SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS 'Total'
    FROM Production.Product AS P
    JOIN Sales.SalesOrderDetail AS SD ON SD.ProductID = P.ProductID
    JOIN Sales.SalesOrderHeader AS SH ON SH.SalesOrderID = SD.SalesOrderID
    JOIN Sales.Customer AS C ON SH.CustomerID = C.CustomerID
    WHERE C.StoreID = @storeid
    GROUP BY P.ProductID, P.Name
);
GO

(2)删除在上面示例中创建的用户定义函数:

USE AdventureWorks2012;
GO
-- determines if function exists in database
IF OBJECT_ID (N'Sales.fn_SalesByStore', N'IF') IS NOT NULL
-- deletes function
    DROP FUNCTION Sales.fn_SalesByStore;
GO

五、执行用户定义的函数

限制:
在 Transact-SQL 中,可以使用值或使用 @parameter_name=value 来提供参数。参数不是事务的一部分;因此,如果在稍后回滚的事务中更改了参数,则该参数的值不会还原为其以前的值。返回给调用方的值始终是模块返回时的值。

权限:
运行 EXECUTE 语句不需要权限。但是,需要对 EXECUTE 字符串中引用的安全对象具有权限。例如,如果字符串包含 INSERT 语句,则 EXECUTE 语句的调用方必须对目标表具有 INSERT 权限。在遇到 EXECUTE 语句时检查权限,即使 EXECUTE 语句包含在模块中也是如此。

示例;
此示例使用大多数版本的 中可用的标量值函数。该函数的目的是从给定整数返回销售状态的文本值。通过将整数 1 到 7 传递给参数来改变示例。

USE [AdventureWorks2016CTP3]
GO

-- Declare a variable to return the results of the function.
DECLARE @ret nvarchar(15);

-- Execute the function while passing a value to the @status parameter
EXEC @ret = dbo.ufnGetSalesOrderStatusText @Status = 5;

-- View the returned value.  The Execute and Select statements must be executed at the same time.
SELECT N'Order Status: ' + @ret;

-- Result:
-- Order Status: Shipped

六、重命名用户定义函数

限制:

  • 函数名称必须符合标识符规则。

  • 重命名用户定义函数不会更改 sys.sql_modules 目录视图的定义列中相应对象名称的名称。因此,建议不要重命名此对象类型。而是删除存储过程,然后使用其新名称重新创建存储过程。

  • 更改用户定义函数的名称或定义可能会导致依赖对象在对象未更新以反映对函数所做的更改时失败。

权限:
删除函数需要对函数所属架构具有 ALTER 权限,或者需要对函数具有 CONTROL 权限。若要重新创建函数,需要数据库中的 CREATE FUNCTION 权限和要在其中创建函数的架构的 ALTER 权限。

注意:若要使用 Transact-SQL 重命名用户定义函数,必须先删除现有函数,然后使用新名称重新创建它。确保使用函数旧名称的所有代码和应用程序现在都使用新名称。

七、查看用户定义的函数

获取有关 SQL Server 中用户定义函数的定义或属性的信息。可能需要查看函数的定义,以了解其数据是如何从源表派生的,或者查看函数定义的数据。

如果更改函数引用的对象的名称,则必须修改该函数,使其文本反映新名称。因此,在重命名对象之前,请先显示对象的依赖项,以确定是否有任何函数受到建议更改的影响。

权限:
用于查找函数上的所有依赖项需要对数据库具有 VIEW DEFINITION 权限,对数据库具有 SELECT 权限。系统对象定义(如 OBJECT_DEFINITION 中返回的那些定义)是公开可见的。

7.1、获取函数的定义和属性

(1)获取函数的定义和属性。

USE AdventureWorks2012;
GO
-- Get the function name, definition, and relevant properties
SELECT sm.object_id,
   OBJECT_NAME(sm.object_id) AS object_name,
   o.type,
   o.type_desc,
   sm.definition,
   sm.uses_ansi_nulls,
   sm.uses_quoted_identifier,
   sm.is_schema_bound,
   sm.execute_as_principal_id
-- using the two system tables sys.sql_modules and sys.objects
FROM sys.sql_modules AS sm
JOIN sys.objects AS o ON sm.object_id = o.object_id
-- from the function 'dbo.ufnGetProductDealerPrice'
WHERE sm.object_id = OBJECT_ID('dbo.ufnGetProductDealerPrice')
ORDER BY o.type;
GO

(2)获取示例函数的定义。

USE AdventureWorks2012;
GO
-- Get the definition of the function dbo.ufnGetProductDealerPrice
SELECT OBJECT_DEFINITION (OBJECT_ID('dbo.ufnGetProductDealerPrice')) AS ObjectDefinition;
GO

7.2、获取函数的依赖项

USE AdventureWorks2012;
GO
-- Get all of the dependency information
SELECT OBJECT_NAME(sed.referencing_id) AS referencing_entity_name,
    o.type_desc AS referencing_desciption,
    COALESCE(COL_NAME(sed.referencing_id, sed.referencing_minor_id), '(n/a)') AS referencing_minor_id,
    sed.referencing_class_desc, sed.referenced_class_desc,
    sed.referenced_server_name, sed.referenced_database_name, sed.referenced_schema_name,
    sed.referenced_entity_name,
    COALESCE(COL_NAME(sed.referenced_id, sed.referenced_minor_id), '(n/a)') AS referenced_column_name,
    sed.is_caller_dependent, sed.is_ambiguous
-- from the two system tables sys.sql_expression_dependencies and sys.object
FROM sys.sql_expression_dependencies AS sed
INNER JOIN sys.objects AS o ON sed.referencing_id = o.object_id
-- on the function dbo.ufnGetProductDealerPrice
WHERE sed.referencing_id = OBJECT_ID('dbo.ufnGetProductDealerPrice');
GO

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7367.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

项目管理软件调度的优势有哪些?

如果没有项目时间表,要跟踪在何时以及必须使用哪些资源之前需要完成什么是非常困难和耗时的。时间表是一个时间表,它概述了所有项目任务和需要完成的里程碑的开始和结束日期。 项目进度中的任务将具有依赖性,这意味着如果完成数据在一项活动上…

Redis7高级之Redlock算法和Redisson的使用(十)

10.1 Redlock 红锁算法 1.解决手写分布式锁的单点故障问题 Redis 提供了 Redlock 算法,用来实现基于多个实例的分布式锁锁变量由多个实例维护,即使有实例发生了故障,锁变量仍然是存在的,客户端还是可以完成锁操作Redlock算法是实…

计算机网络考试复习——第一章 1.5 1.6

1.5 计算机网络的类别 1.5.1计算机网络的定义: 系统集合,连接起来,协议工作,资源共享 计算机网络主要是由一些通用的、可编程的硬件互连而成的,而这些硬件并非专门用来实现某一特定目的(例如&#xff0…

Java源码(一)ThreadLocal、SpringBoot Jar 启动原理

思维导图 一、ThreadLocal 1.场景 项目采用SSMShiro登录认证,改造需求如下: 后台管理员登录需要限制,同一个用户的不同IP需要通过过自定义验证后才能登录。 2.问题 在完成需求后发现有管理员用户(这里就用A)通过验…

Android build.gradle配置详解

Android Studio是采用gradle来构建项目的,gradle是基于groovy语言的,如果只是用它构建普通Android项目的话,是可以不去学groovy的。当我们创建一个Android项目时会包含两个Android build.gradle配置详解文件,如下图: 一…

区块链3链(TRC ERC BSC)授权持币生息源码

分享一款3链(TRC ERC BSC)授权持币生息源码、来自群友投稿的资源、据说是运营级的。简单的看了下没有问题什么大问题、有能力的可以拿来二开其他的模板。 搭建非常简单,教程就不写了、环境NGINX1.2PHP7.2MYSQL5.6TP默认伪静态 此类源码需要…

【Python】数学 - 用 Python 自动化求解函数 f(x) 的值

目录 1、缘起 2、求以下函数的值 3、代码清单 3.1、求解 f(0)、f(1)、 f(​编辑)、f(​编辑) 3.2、求解 g(0)、g(1)、g(​编辑)、g(​编辑) 3.3、求解 h(0)、h(1)、h(​编辑)、h(​编辑) 4、总结 1、缘起 Python 是一种强大的编程语言,它具有广泛的应用领域。…

Python模拟星空

文章目录前言Turtle基础1.1 Turtle画板1.2 Turtle画笔1.3 Turtle画图1.4 Turtle填色1.5 Turtle写字模拟星空模拟星球浪漫星空尾声前言 Python模拟星空,你值得拥有!uu们一周不见啦,本周博主参考网上大佬们的星空,给大家带来了属于…

C语言操作符优先级

在平时写代码时,经常会用到操作符,但是如果不了解这些操作符的优先级,可能会让程序的执行效果和我们预期的不一样。 例如: int a 2;int b 3;int c 4;//int ret a b * c;//我们想要执行的顺序是ab的值再乘c//如果了解操作符优…

chat GPT人工智能写论文-怎么用chatGpt写论文

用chatGPT写文章会重复吗 使用 ChatGPT 写文章可能会出现重复的情况。因为 ChatGPT 是基于机器学习的自然语言处理技术,它并不具备人类的创造性思维,其生成的文本内容是基于已有语言数据的统计模型而产生的。 当输入信息重复、语言结构复杂或指定主题较…

【测试】《软件测试》阅读总结

第一章 软件测试的流程是什么? 需求分析--------测试计划----------测试开发--------测试执行-------测试报告 如何描述一个BUG 版本,测试环境、测试步骤和测试数据、实际结果、预期结果、附件(截图、错误日志) 软件测试过程包括…

HashMap,HashTable和ConcurrentHashMap之间有什么区别?

前言 在之前HashMap的学习中,我们可以知道HashMap是线程不安全的数据结构,它存储的一般是数据的键值对(Key-Value模型),其中Key允许为null,它底层是数组链表的实现,当单个链表的数据元素过多时,会转变为红黑树,在多线程环境下,对某个HashMap对象进行操作,是无法保证线程安全的,…

代理服务器与CDN的概念

代理服务器 特点:本身不产生内容,处于中间位置转发上下游的请求和响应 面向下游的客户端:它是服务器面向上游的服务器:它是客户端 正向代理:代理的对象是客户端 隐藏客户端身份绕过防火墙(突破访问限制&am…

今天面了一个来京东要求月薪25K,明显感觉他背了很多面试题...

最近有朋友去京东面试,面试前后进行了20天左右,包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说,80%的人都会栽在第一轮面试,要不是他面试前做足准备,估计都坚持不完后面几轮面试。 其实&…

LeetCode-146. LRU 缓存

目录LRU理论题目思路代码实现一代码实现二题目来源 146. LRU 缓存 LRU理论 LRU 是 Least Recently Used 的缩写,这种算法认为最近使用的数据是热门数据,下一次很大概率将会再次被使用。而最近很少被使用的数据,很大概率下一次不再用到。当缓…

把ChatGPT接入我的个人网站

效果图 详细内容和使用说明可以查看我的个人网站文章 把ChatGPT接入我的个人网站 献给有外网服务器的小伙伴 如果你本人已经有一台外网的服务器,并且页拥有一个OpenAI API Key,那么下面就可以参照我的教程来搭建一个自己的ChatGPT。 需要的环境 Cento…

大数据分析工具Power BI(三):导入数据操作介绍

导入数据操作介绍 进入PowBI,弹出的如下页面也可以直接关闭,在Power BI中想要导入数据需要通过Power Query 编辑器,Power Query 主要用来清洗和整理数据。

Go分布式爬虫笔记(十七) 4月Day1

文章目录17 协程线程与协程对比调度方式调度策略栈大小上下文切换速度GMP调度循环调度算法如果本地运行队列已经满了,无法处理全局运行队列中的协程怎么办?查找协程的先后顺序主动调度被动调度抢占调度执行时间过长的抢占调度陷入到系统调用中的抢占调度…

leetcode:颠倒二进制位(详解)

前言:内容包括:题目,代码实现,大致思路及图示 题目: 颠倒给定的 32 位无符号整数的二进制位。 提示: 请注意,在某些语言(如 Java)中,没有无符号整数类型。…

ThreeJS-聚光灯物体投影(二十)

聚光灯(灯泡) 关键代码: //直线光(由光源发出的灯光) // const directionalLight new THREE.DirectionalLight(0xFFFFFF, 0.7); // directionalLight.position.set(10, 10, 10); …