探索SQL Server元数据(二)
背景
上一篇中,我介绍了SQL Server 允许访问数据库的元数据,为什么有元数据,如何使用元数据。这一篇中我会介绍如何进一步找到各种有价值的信息。以触发器为例,因为它们往往一起很多问题。
那么如何找到触发器的数据?
以sys.system_viewsis表开始。让我们查询出数据库中使用触发器的信息。可以告知你当前SQL Server版本中有什么触发器。
SELECT schema_name(schema_ID)+'.'+ name FROM sys.system_views WHERE name LIKE '%trigger%'
---------------------------------------- sys.dm_exec_trigger_stats sys.server_trigger_events sys.server_triggers sys.trigger_event_types sys.trigger_events sys.triggers (6 row(s) affected)
其中sys.triggers看起来信息很多,它又包含什么列?下面这个查询很容易查到:
SELECT Thecol.name+ ' '+ Type_name(TheCol.system_type_id) + CASE WHEN TheCol.is_nullable= THEN ' NULL' ELSE ' NOT NULL' END as Column_Information FROM sys.system_views AS TheView INNER JOIN sys.system_columns AS TheCol ON TheView.object_ID=TheCol.Object_ID WHERE TheView.name = 'triggers' ORDER BY column_ID;
结果如下:
Column_Information ---------------------------------------- name nvarchar NOT NULL object_id int NOT NULL parent_class tinyint NOT NULL parent_class_desc nvarchar NULL parent_id int NOT NULL type char NOT NULL type_desc nvarchar NULL create_date datetime NOT NULL modify_date datetime NOT NULL is_ms_shipped bit NOT NULL is_disabled bit NOT NULL is_not_for_replication bit NOT NULL is_instead_of_trigger bit NOT NULL
因此我们多这个信息有了更好的理解,有了一个目录的目录。这个概念有点让人头晕,但是另一方面,它也是相当简单的。我们能够查出元数据,再找个查询中,需要做的就是改变这个单词‘triggers’来查找你想要的视图名称。.
在2012及其以后版本,可以使用一个新的表值函数极大地简化上述查询,并可以避免各种连接。在下面的查询中,我们将查找sys.triggers 视图 中的列。可以使用相同的查询通过更改字符串中的对象名称来获取任何视图的定义。
SELECT name+ ' '+ system_type_name + CASE WHEN is_nullable= THEN ' NULL' ELSE ' NOT NULL' END as Column_Information FROM sys.dm_exec_describe_first_result_set ( N'SELECT * FROM sys.triggers;', NULL, ) AS f ORDER BY column_ordinal;
查询结果如下:
Column_Information ---------------------------------------- name nvarchar() NOT NULL object_id int NOT NULL parent_class tinyint NOT NULL parent_class_desc nvarchar() NULL parent_id int NOT NULL type char() NOT NULL type_desc nvarchar() NULL create_date datetime NOT NULL modify_date datetime NOT NULL is_ms_shipped bit NOT NULL is_disabled bit NOT NULL is_not_for_replication bit NOT NULL is_instead_of_trigger bit NOT NULL
sys.dm_exec_describe_first_result_set函数的最大优势在于你能看到任何结果的列,不仅仅是表和视图、存储过程或者贬值函数。
为了查出任何列的信息,你可以使用稍微修改的版本,只需要改变代码中的字符串'sys.triggers'即可,如下:
Declare @TheParamater nvarchar() Select @TheParamater = 'sys.triggers' Select @TheParamater = 'SELECT * FROM ' + @TheParamater SELECT name+ ' '+ system_type_name + CASE WHEN is_nullable= THEN ' NULL' ELSE ' NOT NULL' END as Column_Information FROM sys.dm_exec_describe_first_result_set ( @TheParamater, NULL, ) AS f ORDER BY column_ordinal;
但是当然一个触发器是首先是一个对象,因此一定在sys.objects?
在我们使用sys.triggers的信息之前,需要来重复一遍,所有的数据库对象都存在于sys.objects中,在SQL Server 中的对象包括以下:聚合的CLR函数,check 约束,SQL标量函数,CLR标量函数,CLR表值函数,SQL内联表值函数,内部表,SQL存储过程,CLR存储过程,计划指南,主键约束,老式规则,复制过滤程序,系统基础表,同义词,序列对象,服务队列,CLR DML 触发器,SQL表值函数,表类型,用户自定义表,唯一约束,视图和扩展存储过程等。
触发器是对象所以基础信息一定保存在sys.objects。不走运的是,有时我们需要额外的信息,这些信息可以通过目录视图查询。这些额外数据有是什么呢?
修改我们使用过的查询,来查询sys.triggers的列,这次我们会看到额外信息。这些额外列是来自于sys.objects。
SELECT coalesce(trigger_column.name,'NOT INCLUDED') AS In_Sys_Triggers, coalesce(object_column.name,'NOT INCLUDED') AS In_Sys_Objects FROM (SELECT Thecol.name FROM sys.system_views AS TheView INNER JOIN sys.system_columns AS TheCol ON TheView.object_ID=TheCol.Object_ID WHERE TheView.name = 'triggers') trigger_column FULL OUTER JOIN (SELECT Thecol.name FROM sys.system_views AS TheView INNER JOIN sys.system_columns AS TheCol ON TheView.object_ID=TheCol.Object_ID WHERE TheView.name = 'objects') object_column ON trigger_column.name=object_column.name 查询结果: In_Sys_Triggers In_Sys_Objects ------------------------------ ---------------------- name name object_id object_id NOT INCLUDED principal_id NOT INCLUDED schema_id NOT INCLUDED parent_object_id type type type_desc type_desc create_date create_date modify_date modify_date is_ms_shipped is_ms_shipped NOT INCLUDED is_published NOT INCLUDED is_schema_published is_not_for_replication NOT INCLUDED is_instead_of_trigger NOT INCLUDED parent_id NOT INCLUDED is_disabled NOT INCLUDED parent_class NOT INCLUDED parent_class_desc NOT INCLUDED
以上这些让我们知道在sys.triggers的额外信息,但是因为它始终是表的子对象,所以有些不相关信息是不会展示在这些指定的视图或者sys.triggers中的。现在就要带大家去继续找找这些信息。
触发器的问题
触发器是有用的,但是因为它们在SSMS对象资源管理器窗格中不是可见的,所以一般用来提醒错误。触发器有时候会有些微妙的地方让其出问题,比如,当导入过程中禁用了触发器,并且由于某些原因他们没有重启。
下面是一个关于触发器的简要提醒:
触发器可以在视图,表或者服务器上,任何这些对象上都可以有超过1个触发器。普通的DML触发器能被定义来执行替代一些数据修改(Insert,Update或者Delete)或者在数据修改之后执行。每一个触发器与只与一个对象管理。DDL触发器与数据库关联或者被定义在服务器级别,这类触发器一般在Create,Alter或者Drop这类SQL语句执行后触发。
像DML触发器一样,可以有多个DDL触发器被创建在同一个T-SQL语句上。一个DDL触发器和语句触发它的语句在同一个事务中运行,所以除了Alter DATABASE之外都可以被回滚。DDL触发器运行在T-SQL语句执行完毕后,也就是不能作为Instead OF触发器使用。
两种触发器都与事件相关,在DML触发器中,包含INSERT, UPDATE, 和DELETE,然而很多事件都可以与DDL触发器关联,稍后我们将了解。
在数据库中列出触发器
那么怎么获取触发器列表?下面我在AdventureWorks数据库中进行查询,注意该库的视图中没有触发器。
第一个查询所有信息都在sys.triggers 的目录视图中。
SELECT name AS TriggerName, coalesce(object_schema_name(parent_ID)+'.' +object_name(parent_ID),'Database ('+db_name()+')') AS TheParent FROM sys.triggers; TriggerName TheParent ------------------------------ ---------------------------------------- ddlDatabaseTriggerLog Database (AdventureWorks2012) dEmployee HumanResources.Employee iuPerson Person.Person iPurchaseOrderDetail Purchasing.PurchaseOrderDetail uPurchaseOrderDetail Purchasing.PurchaseOrderDetail uPurchaseOrderHeader Purchasing.PurchaseOrderHeader iduSalesOrderDetail Sales.SalesOrderDetail uSalesOrderHeader Sales.SalesOrderHeader dVendor Purchasing.Vendor iWorkOrder Production.WorkOrder uWorkOrder Production.WorkOrder
我使用元数据函数db_name()使SQL保持简单。db_name()告诉我数据库的名称。object_schema_name()用来查询object_ID代表的对象的架构,以及object_name()查询对象名称。这些对对象的引用指向触发器的所有者,触发器可以是数据库本身,也可以是表:服务器触发器有自己的系统视图,稍后我会展示。
如果想要看到所有触发器,那么我们最好使用sys.objects 视图:
SELECT name as TriggerName, object_schema_name(parent_object_ID)+'.' +object_name(parent_object_ID) AS TheParent FROM sys.objects WHERE OBJECTPROPERTYEX(object_id,'IsTrigger') =
注意,输出不包含数据库级别的触发器,因为所有的DML触发器都在sys.objects视图中,但是你会漏掉在sys.triggers视图中的触发器。
上面查询结果:
name TheParent ------------------------------ ------------------------------- dEmployee HumanResources.Employee iuPerson Person.Person iPurchaseOrderDetail Purchasing.PurchaseOrderDetail uPurchaseOrderDetail Purchasing.PurchaseOrderDetail uPurchaseOrderHeader Purchasing.PurchaseOrderHeader iduSalesOrderDetail Sales.SalesOrderDetail uSalesOrderHeader Sales.SalesOrderHeader dVendor Purchasing.Vendor iWorkOrder Production.WorkOrder uWorkOrder Production.WorkOrder
我的表和视图有多少个触发器?
我想知道每个表有多少个触发器,并且什么情况下触发它们。下面我们列出了具有触发器的表以及每个事件的触发器数量。每个表或者视图对于触发器行为都有一个INSTEAD OF 触发器,可能是UPDATE, DELETE, 或者 INSERT
。但是一个表可以有多个AFTER触发器行为。这些将展示在下面的查询中(排除视图):
SELECT convert(CHAR(),coalesce(object_schema_name(parent_ID)+'.' +object_name(parent_ID),'Database ('+db_name()+')')) AS 'Table', triggers,[KD1] [AC2] convert(SMALLINT,objectpropertyex(parent_ID, N'TABLEDeleteTriggerCount')) AS 'Delete', convert(SMALLINT,objectpropertyex(parent_ID, N'TABLEInsertTriggerCount')) AS 'Insert', convert(SMALLINT,objectpropertyex(parent_ID, N'TABLEUpdateTriggerCount')) AS 'Update' FROM (SELECT count(*) AS triggers, parent_ID FROM sys.triggers WHERE objectpropertyex(parent_ID, N'IsTable') = GROUP BY parent_ID )TablesOnly; --查询结果如下: Table triggers Delete Insert Update -------------------------------- ----------- ------ ------ ------ Purchasing.Vendor Production.WorkOrder Purchasing.PurchaseOrderDetail Purchasing.PurchaseOrderHeader Sales.SalesOrderDetail HumanResources.Employee Sales.SalesOrderHeader Person.Person ( row(s) affected)
如果超过一个触发器被触发在一个表上,它们不保证顺序,当然也可以使用sp_settriggerorder来控制顺序。通过使用objectpropertyex()元数据函数,需要根据事件输入参数‘ExecIsLastDeleteTrigger’, ‘ExecIsLastInsertTrigger’ 或者 ‘ExecIsLastUpdateTrigger’来确认谁是最后一个执行的触发器 。为了得到第一个触发器,酌情使用ObjectPropertyEx() 元数据函数,需要输入参数 ‘ExecIsFirstDeleteTrigger’, ‘ExecIsFirstInsertTrigger’ 或者 ‘ExecIsFirstUpdateTrigger’。
因此我们现在知道了表有哪些触发器,哪些事件触发这些触发器。可以使用objectpropertyex()元数据函数,这个函数返回很多不同信息,根据指定的参数不同。通过查看MSDN中的文档,查看其中的一个文档是否有助于元数据查询,总是值得检查的。
触发器何时触发事件?
让我们看一下这些触发器,DML触发器可以在所有其他时间发生后触发,但是可以在约束被处理前并且触发INSTEAD OF触发动作。下面我们就来看看所有的触发的到底是AFTER 还是INSTEAD OF 触发器,有事什么时间触发了触发器。
/* 列出触发器,无论它们是否启用,以及触发器事件。*/ SELECT convert(CHAR(),name) AS triggerName, convert(CHAR(),coalesce(object_schema_name(parent_ID)+'.' +object_name(parent_ID),'Database ('+db_name()+')')) AS TheParent, is_disabled, CASE WHEN is_instead_of_trigger= THEN 'INSTEAD OF ' ELSE 'AFTER ' END +Stuff (--get a list of events for each trigger (SELECT ', '+type_desc FROM sys.trigger_events te WHERE te.object_ID=sys.triggers.object_ID FOR XML PATH(''), TYPE).value('.', 'varchar(max)'),,,'') AS events FROM sys.triggers;
结果如下:
triggerName TheParent is_disabled events ------------------------- -------------------------------- ----------- --------- ddlDatabaseTriggerLog Database (AdventureWorks2012) AFTER CREATE_TABLE, ALTER_TABLE, DROP_TABLE, CREATE_VIEW, ALTER_VIEW, DROP_VIEW, CREATE_INDEX, ALTER_INDEX, DROP_INDEX, CREATE_XML_INDEX, ALTER_FULLTEXT_INDEX, CREATE_FULLTEXT_INDEX, DROP_FULLTEXT_INDEX, CREATE_SPATIAL_INDEX, CREATE_STATISTICS, UPDATE_STAT t_AB dbo.AB INSTEAD OF INSERT dEmployee HumanResources.Employee INSTEAD OF DELETE iuPerson Person.Person AFTER INSERT, UPDATE iPurchaseOrderDetail Purchasing.PurchaseOrderDetail AFTER INSERT uPurchaseOrderDetail Purchasing.PurchaseOrderDetail AFTER UPDATE uPurchaseOrderHeader Purchasing.PurchaseOrderHeader AFTER UPDATE iduSalesOrderDetail Sales.SalesOrderDetail AFTER INSERT, UPDATE, DELETE uSalesOrderHeader Sales.SalesOrderHeader AFTER UPDATE dVendor Purchasing.Vendor INSTEAD OF DELETE iWorkOrder Production.WorkOrder AFTER INSERT uWorkOrder Production.WorkOrder AFTER UPDATE
As you will notice, we used a FOR XML PATH(‘’) trick here to make a list of the events for each trigger to make it easier to read. These events were pulled from the sys.trigger_events view using a correlated subquery.
注意到我们使用了FOR XML PATH(‘’)来列出事件的每一个触发器,更容易读取理解。sys.trigger_events使用相关子查询来查询这些事件。
触发器的多长?
许多数据库人员不赞成冗长触发器的定义,但他们可能会发现,根据定义的长度排序的触发器列表是研究数据库的一种有用方法。
SELECT convert(CHAR(),coalesce(object_schema_name(t.object_ID)+'.','') +name) AS TheTrigger, convert(CHAR(),coalesce(object_schema_name(parent_ID)+'.' +object_name(parent_ID),'Database ('+db_name()+')')) AS theParent, len(definition) AS length --the length of the definition FROM sys.SQL_modules m INNER JOIN sys.triggers t ON t.object_ID=m.object_ID ORDER BY length DESC;
访问sys.SQL_modules视图可以查看触发器定义的SQL DDL,并按大小顺序列出它们,最上面是最大的。
结果:
TheTrigger theParent length -------------------------------- -------------------------------- -------- Sales.iduSalesOrderDetail Sales.SalesOrderDetail Sales.uSalesOrderHeader Sales.SalesOrderHeader Purchasing.uPurchaseOrderDetail Purchasing.PurchaseOrderDetail Purchasing.iPurchaseOrderDetail Purchasing.PurchaseOrderDetail Person.iuPerson Person.Person ddlDatabaseTriggerLog Database (AdventureWorks2012) Purchasing.dVendor Purchasing.Vendor Production.uWorkOrder Production.WorkOrder Purchasing.uPurchaseOrderHeader Purchasing.PurchaseOrderHeader Production.iWorkOrder Production.WorkOrder HumanResources.dEmployee HumanResources.Employee
好吧,我可能太挑剔了,不太喜欢太长的,但是逻辑有时候会很长。事实上,前三名在我看来是不可靠的,尽管我总是倾向于尽可能少地使用触发器。
这些触发器访问了多少对象
在代码中,每个触发器要访问多少对象(比如表和函数)?
我们只需要检查表达式依赖项。这个查询使用一个视图来列出“软”依赖项(如触发器、视图和函数)。
SELECT coalesce(object_schema_name(parent_id) +'.','')+convert(CHAR(),name) AS TheTrigger, count(*) AS Dependencies FROM sys.triggers INNER JOIN sys.SQL_Expression_dependencies ON [referencing_id]=object_ID GROUP BY name, parent_id ORDER BY count(*) DESC;
--结果: TheTrigger Dependencies ---------------------------------------- ------------ Sales.iduSalesOrderDetail Sales.uSalesOrderHeader Purchasing.iPurchaseOrderDetail Purchasing.uPurchaseOrderDetail Purchasing.uPurchaseOrderHeader Production.iWorkOrder Production.uWorkOrder dbo.t_AB Purchasing.dVendor Person.iuPerson ddlDatabaseTriggerLog
居然有两个触发器有7个依赖!让我们就Sales.iduSalesOrderDetail来实际看一下,有哪些依赖。
特定触发器访问或者写入哪些对象?
我们可以列出触发器在代码中引用的所有对象
SELECT convert(char(),name) as TheTrigger, convert(char(),coalesce([referenced_server_name]+'.','') +coalesce([referenced_database_name]+'.','') +coalesce([referenced_schema_name]+'.','')+[referenced_entity_name])
as referencedObject FROM sys.triggers INNER JOIN sys.SQL_Expression_dependencies ON [referencing_id]=object_ID WHERE name LIKE 'iduSalesOrderDetail'; --查询结果: TheTrigger referencedObject -------------------------------- -------------------------------- iduSalesOrderDetail Sales.Customer iduSalesOrderDetail Person.Person iduSalesOrderDetail Sales.SalesOrderDetail iduSalesOrderDetail Sales.SalesOrderHeader iduSalesOrderDetail Production.TransactionHistory iduSalesOrderDetail dbo.uspLogError iduSalesOrderDetail dbo.uspPrintError
触发器里有什么代码?
现在让我们通过检查触发器的源代码来确认这一点。.
SELECT OBJECT_DEFINITION ( object_id('sales.iduSalesOrderDetail') );
我们之前的查询是正确的,扫描源码可知所有的依赖项。大量依赖项表名对于数据库的重构等需要非常小心,例如,修改一个基础表的列。
据需要做什么,您可能希望检查来自元数据视图的定义,而不是使用OBJECT_DEFINITION函数。
SELECT definition FROM sys.SQL_modules m INNER JOIN sys.triggers t ON t.object_ID=m.object_ID WHERE t.object_ID=object_id('sales.iduSalesOrderDetail');
搜索触发器的代码
There are always plenty of ways of using the metadata views and functions. I wonder if all these triggers are executing that uspPrintError procedure?
有很多使用元数据视图和函数的方法。想知道是否所有这些触发器都执行uspPrintError存储过程?
/* 在所有触发器中搜索字符串 */
SELECT convert(CHAR(),coalesce(object_schema_name(object_ID)+'.','') +name) AS TheTrigger, '...'+substring(definition, hit-,) +'...' FROM (SELECT name, definition, t.object_ID, charindex('EXECUTE [dbo].[uspPrintError]',definition) AS hit FROM sys.SQL_modules m INNER JOIN sys.triggers t ON t.object_ID=m.object_ID)f WHERE hit>;
结果如图:
8个引用正在执行这个过程。我们在sys.SQL_modules中搜索了所有的定义可以找到一个特定的字符串,这种方式很慢很暴力,但是它是有效的!
在所有对象中搜索字符串
我想知道除了触发器之外是否还有其他对象调用这个过程?我们稍微修改查询以搜索sys.objects视图,而不是sys.triggers,以搜索所有具有与之关联的代码的对象。我们还需要显示对象的类型
/* 在所有对象中搜索字符串 */
SELECT convert(CHAR(),coalesce(object_schema_name(object_ID)+'.','') +object_name(object_ID)) AS TheObject, type_desc, '...'+substring(definition,hit-,)+'...' as TheExtract FROM (SELECT type_desc, definition, o.object_ID, charindex('uspPrintError',definition) AS hit FROM sys.SQL_modules m INNER JOIN sys.objects o ON o.object_ID=m.object_ID)f WHERE hit>;
查询结果如下图:
From this output we can see that, other than the procedure itself where it is defined, and the triggers, only dbo.uspLogError is executing the uspPrintError procedure. (see the first column, second line down)
从这个输出中我们可以看到,除了在定义它的过程本身之外,还有触发器,只有dbo.uspLogError正在执行uspPrintError过程。(见第一列,第二行往下)
列出服务器级触发器及其定义
我们可以通过系统视图了解它们吗?嗯,是的。以下是列出服务器触发器及其定义的语句
SELECT name, definition FROM sys.server_SQL_modules m INNER JOIN sys.server_triggers t ON t.object_ID=m.object_ID;
注意,只能看到有权限看的触发器
总结
本文讨论过触发器,并且你能查出触发器,以及潜在的问题。这里并没有针对关于触发器的查询提供一个全面的工具箱,因为我只是使用触发器作为示例来展示在查询系统视图时可能使用的一些技术。在我们学习了索引、列和参数之后,我们将回到触发器,并了解了编写访问系统视图和information schema视图的查询的一些日常用途。表是元数据的许多方面的基础。它们是几种类型的对象的父类,其他元数据如索引是表的属性。我们正在慢慢地努力去发现所有关于表的信息。期待下期
探索SQL Server元数据(二)的更多相关文章
- 探索SQL Server元数据(一)
简介 在数据库中,我们除了存储数据外,还存储了大量的元数据.它们主要的作用就是描述数据库怎么建立.配置.以及各种对象的属性等.本篇简单介绍如何使用和查询元数据,如何更有效的管理SQLServer 数据 ...
- 探索SQL Server元数据(三):索引元数据
背景 在第一篇中我介绍了如何访问元数据,元数据为什么在数据库里面,以及如何使用元数据.介绍了如何查出各种数据库对象的在数据库里面的名字.第二篇,我选择了触发器的主题,因为它是一个能提供很好例子的数据库 ...
- 人人都是 DBA(II)SQL Server 元数据
SQL Server 中维护了一组表用于存储 SQL Server 中所有的对象.数据类型.约束条件.配置选项.可用资源等信息,这些信息称为元数据信息(Metadata),而这些表称为系统基础表(Sy ...
- SQL Server元数据查询
原文:SQL Server元数据查询 1.查询触发器的信息 --查询触发器的信息 select name, --触发器名称 (select name from sys.objects where ob ...
- SQL Server 元数据分类
SQL Server 中维护了一组表用于存储 SQL Server 中所有的对象.数据类型.约束条件.配置选项.可用资源等信息,这些信息称为元数据信息(Metadata),而这些表称为系统基础表(Sy ...
- Sql Server专题二:数据库主要对象
存储过程 (1)减少网络通信量.调用一个行数不多的存储过程与直接调用sql语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行sql语句,那么其性能绝对比一条一条的调用sql语句要高得多. ...
- SQL Server元数据损坏(metadata corruption)修复
在升级一个SQL Server 2000的数据库时,遇到了一致性错误,其中有几个错误是元数据损坏(metadata corruption),特意研究了一下这个案例,因为以前也零零散散的遇到过一些一致性 ...
- Sql Server——查询(二)
上次写了查询里的一些简单的查询方法,如果说上次的是初级查询,那这次的就是高级查询了. 今天主要是聚合函数.分组查询.连接查询.联合查询.在我看来前三个挺简单的,稍微难理解点的也就最后一个,为什么呢?因 ...
- SQL Server事务(二)
事务的四大特性: 1.原子性:原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能 ...
随机推荐
- 机器学习中数据清洗&预处理
数据预处理是建立机器学习模型的第一步,对最终结果有决定性的作用:如果你的数据集没有完成数据清洗和预处理,那么你的模型很可能也不会有效 第一步,导入数据 进行学习的第一步,我们需要将数据导入程序以进行下 ...
- 基于jQuery消息提示框插件Tipso
今天要分享的这款jQuery消息提示框插件名叫Tipso,它的特点是可以定义提示框的显示位置,以及动态改变提示框的提示内容,应该说是一款相当灵活的jQuery消息提示框插件.效果图如下: 在线预览 ...
- python装饰器2:类装饰器
装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 本文是装饰器相关内容的第二篇,关于类装饰器. "类装饰器"有两种解读方式:用来装饰类的装饰器:类作为装饰器装饰其它东西.你 ...
- vue_drf之实现短信验证码
一.需求 1,需求 我们在做网站开发时,登录页面很多情况下是可以用手机号接收短信验证码,然后实现登录的,那我们今天就来做一做这一功能. 伪代码: 进入登录页面,点击短信登录 输入手机号码,点击获取验证 ...
- [Redux] redux的概述
redux 的概述 随着 javascript 单页应用的不断发展,javascript 需要管理比以往都要多的状态,管理不断变化的 state 非常困难,数据流动不断变的模糊不可预测,代码的开发与维 ...
- 在AspNetCore中扩展Log系列 - 介绍开源类库的使用(一)
转发时请注明原创作者及地址,否则追究责任. 原创:alunchen 当创建AspNetCore项目时 当我们创建一个AspNetCore项目时,需要我们手动添加Log: services.AddLog ...
- 使用Task异步执行方法_多线程_应用程序池
偶然遇到在执行登录的方法需要发送消息队列导致登录时间过长的问题,从网上查了一些方法,先将一个简单的异步处理程序的小例子展示出来,供大家参考: 备注:该方法是从应用程序程序所在的线程池中获取线程,第一次 ...
- JS_正则表达式_使用字符串创建的正则表达式_反斜杠也需要添加转义符
备注: 使用字符串创建的正则表达式:"\"也需要加转义符: var reg1=new RegExp("\\w+"); 这和 直接使用:var r ...
- EF 事务(转载)
事务简单用法 文章一:https://www.cnblogs.com/wujingtao/p/5407821.html 1EF事务 事务就是确保一次数据库操作,所有步骤都成功,如果哪一步出错了,整个操 ...
- 【CSS】小妙招,各种问题总结方法处理
1.实现div文字溢出自动省略号截取 overflow:hidden; /*超过部分不显示*/ text-overflow:ellipsis; /*超过部分用点点表示*/ white- ...