精华内容
下载资源
问答
  • T-SQL动态查询(4)——动态SQL

    万次阅读 2015-12-09 09:38:17
    接上文:T-SQL动态查询(3)——静态SQL 前言: 前面说了很多关于动态查询内容,本文将介绍使用动态SQL解决动态查询...动态SQL尤其自己缺点,是否使用需要进行评估分析:动态SQL优点:动态SQL提供了强大


    接上文:T-SQL动态查询(3)——静态SQL

     

    前言:


    前面说了很多关于动态查询的内容,本文将介绍使用动态SQL解决动态查询的一些方法。

     

    为什么使用动态SQL:


    在很多项目中,动态SQL被广泛使用甚至滥用,很多时候,动态SQL又确实是解决很多需求的首选方法。但是如果不合理地使用,会导致性能问题及无法维护。动态SQL尤其自己的优缺点,是否使用需要进行评估分析:

    本文出处:http://blog.csdn.net/dba_huangzj/article/details/50202371

    动态SQL优点:

    • 动态SQL提供了强大的扩展功能,能够应付复杂的需求,即使在需求增加时也能应对,并且不会因为需求的增加而导致代码的线性增长。
    • 执行计划可以缓存查询字符串,意味着大部分查询条件可以重用执行计划缓存而不会导致不必要的重编译。

    动态SQL缺点:

    • 不合理的编码会导致代码的维护陷入困境。
    • 动态SQL是用于应对较高级的问题,对于简单问题,会变得大材小用。
    •  动态SQL的测试显然比其他代码困难,特别是对最终执行的语句的获取,同时容易因为编码的不规范导致语法错误。
    • 相对于前面的OPTION(RECOMPILE),动态SQL需要加入对权限控制的考虑。
    • 动态SQL的计划缓存并不总是你想象的那样,有时候因为输入的参数值而导致不同的计划生成。

    静态SQL其实可以应对大部分的日常需求,但是随着需求的增加,静态SQL会变得越来越复杂,同时可能带来过多的重编译,此时应该考虑动态SQL。

     

    动态SQL简介:


    概述:


    在SQL Server中,动态SQL可以由三种方式实现:

    1. T-SQL存储过程
    2. CLR存储过程
    3. 客户端语句

    本文着重介绍T-SQL中的存储过程。针对用户的输入,有两种方式进行处理:

    • 把参数通过字符串拼接实现,如:' AND col = ' + convert(varchar, @value)'
    • 使用sp_executesql进行参数化查询,可以把上面的参数变成:' AND col = @value'

    基于很多理由,在日常使用中,推荐使用第二种方法也就是sp_executesql。但是需要提醒的是上面提到的三种实现动态SQL的方式没有本质上的好和坏,只有根据实际情况而定才是最有效的。本文将使用静态SQL篇中的需求作为演示,即针对不同的查询条件、不同的排序甚至不同的汇总需求演示。

     本文出处:http://blog.csdn.net/dba_huangzj/article/details/50202371

    权限:


    对于存储过程中使用静态SQL,权限问题并无大碍。只要存储过程的调用者和表的拥有者是相同的,由于所有权链(ownership chaining,https://msdn.microsoft.com/zh-cn/library/ms188676.aspx),可以无障碍地执行存储过程。但是动态SQL中不存在所有权链,即使把它们放在存储过程中也一样,因为动态SQL有自己的权限范围。

    如果在客户端程序或CLR存储过程中创建动态SQL,还需要额外授予用户具有查询中涉及到的表、视图、自定义函数上的SELECT权限。根据客户端程序和CLR存储过程的不同,权限链可能会非常混乱和失控。但是可以使用下面两种方式来应付:

    1. 创建一个证书,对存储过程使用这个证书进行签名。然后使用证书创建一个用户,并由于用户所需的SELECT权限。
    2. 在存储过程中添加EXECUTE AS ‘用户’。然后授予SELECT权限。

     

    动态SQL的参数化查询形式:


    本部分使用第一篇中提到的模版进行改造演示,为了能清晰地描述,使用博客自带的行号来标号:

    USE [AdventureWorks2008R2]																		
    GO                                                                                              
    CREATE PROCEDURE [dbo].[sp_Get_orders]                                                          
         @salesorderid    int           = NULL,                                                     
         @fromdate        datetime      = NULL,                                                     
         @todate          datetime      = NULL,                                                     
         @minprice        money         = NULL,                                                     
         @maxprice        money         = NULL,                                                     
         @custid          int           = NULL,                                                     
         @custname        nvarchar(40)  = NULL,                                                     
         @prodid          int           = NULL,                                                     
         @prodname        nvarchar(40)  = NULL,                                                     
         @employeestr     varchar(MAX)  = NULL,                                                     
         @employeetbl     intlist_tbltypeREADONLY,                                                  
         @debug           bit           =0                                                          
    AS                                                                                              
                                                                                                    
        DECLARE @sql        nvarchar(MAX),                                                          
               @paramlist  nvarchar(4000),                                                          
               @nl         char(2) = char(13) + char(10)                                            
                                                                                                    
        SELECT @sql='                                                                               
           SELECT o.SalesOrderID, o.OrderDate, od.UnitPrice,od.OrderQty,                            
                 c.CustomerID, per.FirstName as CustomerName,p.ProductID,                           
                 p.Name as ProductName, per.BusinessEntityID as EmpolyeeID                          
           FROM  Sales.SalesOrderHeader o                                                           
           INNER JOIN   Sales.SalesOrderDetail od ON o.SalesOrderID= od.SalesOrderID                
           INNER JOIN   Sales.Customer c ON o.CustomerID =c.CustomerID                              
           INNER JOIN   Person.Person per onc.PersonID=per.BusinessEntityID                         
           INNER JOIN   Production.Product p ON p.ProductID =od.ProductID                           
           WHERE 1=1'+@nl                                                                           
                                                                                                    
        IF @salesorderidIS NOT NULL                                                                 
           SELECT @sql+= ' AND o.SalesOrderID=@SalesOrderID'+                                       
                         ' ANDod.SalesOrderID=@SalesOrderID'+@nl                                    
                                                                                                    
        IF @fromdateIS NOT NULL                                                                     
           SELECT @sql+= ' AND o.OrderDate >= @fromdate'+@nl                                        
                                                                                                    
        IF @todateIS NOT NULL                                                                       
           SELECT @sql+= ' AND o.OrderDate <= @todate'+@nl                                          
                                                                                                    
        IF @minpriceIS NOT NULL                                                                     
           SELECT @sql += 'AND od.UnitPrice >= @minprice' + @nl                                     
                                                                                                    
        IF @maxpriceIS NOT NULL                                                                     
           SELECT @sql += 'AND od.UnitPrice <= @maxprice' + @nl                                     
                                                                                                    
        IF @custidIS NOT NULL                                                                       
           SELECT @sql += 'AND o.CustomerID = @custid' +                                            
                        ' AND c.CustomerID = @custid' +@nl                                          
                                                                                                    
        IF @custnameIS NOT NULL                                                                     
            SELECT@sql += ' AND per.FirstName LIKE @custname + ''%''' + @nl                         
                                                                                                    
        IF @prodidIS NOT NULL                                                                       
           SELECT@sql += ' AND od.ProductID = @prodid' +                                            
                        ' AND p.ProductID = @prodid' +@nl                                           
                                                                                                    
        IF @prodnameIS NOT NULL                                                                     
           SELECT@sql += ' AND p.Name LIKE @prodname + ''%''' + @nl                                 
                                                                                                    
        IF @employeestrIS NOT NULL                                                                  
           SELECT@sql += ' AND per.BusinessEntityID IN' +                                           
                        ' (SELECT number FROM dbo.intlist_to_tbl(@employeestr))'+ @nl               
                                                                                                    
        IF EXISTS(SELECT * FROM @employeetbl)                                                       
           SELECT@sql += ' AND per.BusinessEntityID IN (SELECT val FROM @employeetbl)'+ @nl         
                                                                                                    
        SELECT @sql+= ' ORDER BYo.SalesOrderID' + @nl                                               
                                                                                                    
        IF @debug= 1                                                                                
           PRINT @sql                                                                               
                                                                                                    
        SELECT @paramlist=  '@salesorderid    int,                                                  
                          @fromdate   datetime,                                                     
                          @todate     datetime,                                                     
                          @minprice   money,                                                        
                          @maxprice   money,                                                        
                          @custid     nchar(5),                                                     
                          @custname   nvarchar(40),                                                 
                          @prodid     int,                                                          
                          @prodname   nvarchar(40),                                                 
                          @employeestr varchar(MAX),                                                
                          @employeetbl intlist_tbltype READONLY'                                    
                                                                                                    
        EXEC sp_executesql@sql, @paramlist,@salesorderid, @fromdate, @todate, @minprice,            
                       @maxprice,  @custid, @custname,@prodid, @prodname, @employeestr, @employeetbl


     

    代码分析:


    在上面代码中的第18行,定义了一个变量@sql,用于存储查询字符串。由于sp_executesql要求参数必须为NVARCHAR,所以这里使用NVARCHAR(MAX),以便足够存放所有最终字符串。

    在第20行,使用了一个变量@nl,通过赋值char(13)+char(10)实现Windows上的换行符功能。虽然它是变量,但是在存储过程中实际上是一个常量。

    在第22 到31行,包含了动态SQL的核心部分,并存放在@sql变量中。通过后续的参数拼接实现整个动态SQL查询。注意代码中均使用了两部命名(即架构名.表名),因为由于性能原因,SQL Server在编译和优化时需要精确定位对象,如果表A存在dbo.A和Sales.A这两个架构名,那么SQL Server需要花时间去判断究竟使用的是哪个表,这会带来不小的开销,注意,即使只有几十毫秒,但是对于一个频繁被执行的存储过程或语句,整体性能会被明显拉低,所以不管基于性能还是编程规范的考虑,都应该带上架构名,当然如果你的系统只有dbo这个默认架构,不带也行,但是建议还是要规范化编程提高可读性和可维护性。这里再插一句,在本人优化的代码中,经常看到很多语句中,表名使用了别名,但是在ON、WHERE中又没有带上别名前缀,咋一看上去很难知道字段来自于哪个表,要一个一个相关表去检查,花了不该花的时间,为了维护代码的人,你们就行行好吧。

    在第31行是一句“WHERE 1=1”,类似编程语言中的占位符,使WHERE语句即使单独存在也不会报错,下面会介绍为什么也要加上@nl。

    在第33行开始,针对所有单值查询参数进行检查,如果参数不为NULL,则添加到最终的SQL字符串的对应列中。从这里开始就要注意对单引号、双引号的使用,同时留意在每次拼接后面都加上了@nl。

    在第67 行,对@employeestr参数进行处理,处理方式和上一篇静态SQL一样。其他剩余部分相对简单,不做过多解释。

    在第72行,添加了一个参数@debug,默认为0,当用户调用传入1时,输出SQL字符串,这在调试和检查错误时非常有用,因为动态SQL往往很难直接从代码中看出最终语句,如果在开发过程没有注意引号、空格、类型转换等问题时,都会在后续调用过程中报错。通过@debug参数,可以在未执行语句(即还不至于报错停止之前)就把需要执行的语句打印出来,注意顺序很重要,如果在执行报错后你再想打印就不一定能打印出来了。

    对于几乎每行后面都添加的@nl,当然是有意图的,如果不加换行符,代码可能会变成单行很长的字符串,print出来不直观。甚至看起来很痛苦,虽然现在有格式化工具,但是不是每次都破解成功,对单串字符串的美化还是比较浪费时间的。

    最后,通过sp_executesql执行SQL字符串,这是一个系统存储过程,需要提供两个固定参数,第一个是SQL字符串,第二个是参数列。这些参数必须是nvarchar类型。在这个例子中,调用语句在存储过程内部。你也可以在外部调用存储过程。但是需要记住的是动态SQL不能得知任何调用参数。

    注意存储过程最后的参数列@paramlist,是静态的,也就是参数集是固定的,即使有些参数并不是每次都会使用到。

     

    测试:

    可以使用下面语句对存储过程进行测试:

    EXEC [sp_Get_orders]@salesorderid = 70467
    EXEC [sp_Get_orders]@custid  = 30097
    EXEC [sp_Get_orders]@prodid  = 936
    EXEC [sp_Get_orders]@prodid  = 936, @custname = 'Carol'
    EXEC [sp_Get_orders]@fromdate = '2007-11-01 00:00:00.000', @todate = '2008-04-18 00:00:00.000'
    EXEC [sp_Get_orders]@employeestr = '20124,759,1865', @custid = 29688
     
    DECLARE @tbl intlist_tbltype
    INSERT @tbl(val) VALUES(20124),(759),(1865)
    EXEC [sp_Get_orders]@employeetbl = @tbl, @custid = 29688
    对于这类情况,需要对所有参数进行测试,最好是能知道实际使用中哪些参数的使用频率最高。
    本文出处:http://blog.csdn.net/dba_huangzj/article/details/50202371

    动态SQL的编译和缓存:


    每当用户以相同查询参数集进行调用这个存储过程时,执行计划会被重用。如果调用上一章的存储过程sp_get_orders_1时,如:

    EXEC sp_get_orders_1@salesorderid = 70467
    EXEC sp_get_orders_1@salesorderid = 70468
    EXEC sp_get_orders_1@salesorderid = 70469

    由于OPTION(RECOMPILE),所以不缓存任何执行计划并且每次都重编译。但是对于本文中的存储过程:

    EXEC [sp_Get_orders]@salesorderid = 70467
    EXEC [sp_Get_orders]@salesorderid = 70468
    EXEC [sp_Get_orders]@salesorderid = 70469

    只会针对第一次调用进行编译并缓存执行计划,后续两次调用将使用第一的执行计划进行直接运行。但是当调用的参数变化时,如:

    EXEC [sp_Get_orders]@salesorderid = 70467,@prodid  = 870

    会发生新的编译并产生新的缓存条目,但原有的用于查询SalesOrderID的执行计划不受影响。

     

    特殊的查询条件:


    在上一篇静态SQL中,已经展示了如何用静态SQL实现某些特殊的查询条件,本部分将演示用动态SQL来完成这些工作,前面提到过,静态SQL针对简单的查询条件,足以应付自如,但是当需求数量和复杂度逐步增加时,静态SQL将变得不可控。此时就需要考虑动态SQL。

     

    数据分布不均的情况:


    在很多系统中,常见的一类情况是,订单表上有一个状态列Status,里面有4个值:N(新订单)、P(处理中)、E(异常订单)、C(已处理订单),同时几乎99%的数据都是为C。

    这种情况下可以使用对该列中C值的过滤索引/筛选索引(filterindex)来过滤不必要的数据或需要经常查询的数据。但是如果在动态SQL中这样写:

    IF @status IS NOT NULL
      SELECT @sql += ' AND o.Status = @status'

    由于动态SQL的执行计划是针对所有情况进行优化的,所以这种写法是不会专门针对过滤索引起效,需要额外制定一些操作逻辑来“指示”优化器使用这个过滤索引,如:

    IF @status IS NOT NULL
       SELECT @sql += ' AND o.Status = @status' +
                      CASE WHEN @status <> 'C' 
                           THEN ' AND o.Status <> ''C'''
                           ELSE ''
                      END
    这种情况是针对单值参数,如果@status为多值,即用户需要筛选某些类型的数据,则需要按这种方式添加更多的处理逻辑。

    自定义排序:

    在动态SQL中,很常见的应用常见是使用自定义的排序规则,通过用户前端输入的排序条件进行结果集排序,比如:

    @sql += ' ORDER BY ' + @sortcol

    这种写法可以满足多列排序。比如’SalesOrderID, OrderTime Desc’。虽然对于满足功能来说,已经足够了,但是由于客户端不知道查询本身,可能导致传入的参数不属于相关的表或其他因素导致报错,特别是ORDER BY在T-SQL的逻辑处理中属于接近最后部分,SELECT语句可能把原始列进行重命名、运算等,导致前端无法得知SELECT的最终列名。另外即使是使用了正确的名字,但是在后续可能因为表结构的变更、列名变更等因素又带来报错。这种情况其实很难避免,不过多考虑一下问题可能就没有那么严重,比如可以用下面的方式来预处理:

    SELECT @sql += ' ORDER BY ' + 
                   CASE @sortcol WHEN 'OrderID'      THEN 'o.OrderID'
                                 WHEN 'EmplyoeeID'   THEN 'o.EmployeeID'
                                 WHEN 'ProductID'    THEN 'od.ProductID'
                                 WHEN 'CustomerName' THEN 'c.CompanyName'
                                 WHEN 'ProductName'  THEN 'p.ProductName'
                                 ELSE 'o.OrderID'
                   END + CASE @isdesc WHEN 0 THEN ' ASC' ELSE ' DESC' END

    备用表:


    在上一章备用表中,提到了关于不同参数访问不同表的情况,这种情况在动态SQL中实现也不难,可以把FROM部分改写成:

    ROM dbo.' + CASE @ishistoric
                      WHEN 0 THEN 'Orders'
                      WHEN 1 THEN 'HistoricOrders'
                 END + ' o
    JOIN dbo.' + CASE @ishistoric
                      WHEN 0 THEN '[Order Details]'
                      WHEN 1 THEN 'HistoricOrderDetails'
                 END + ' od

    但是为了避免SQL注入的风险,不建议通过前端程序传入表名,而是传入某些标识参数然后在存储过程内部进行表名选择。

     本文出处:http://blog.csdn.net/dba_huangzj/article/details/50202371

     

    缓存问题:


    参数化动态SQL的其中一个优势是可以通过计划重用而减少编译次数。但是缓存并不总是好的,比如在上一章基础技能部分提到的:

    1. exec sp_Get_orders_1@fromdate='20050701',@todate ='20050701'  
    2. exec sp_Get_orders_1@fromdate='20050101',@todate ='20051231'  

    虽然参数集相同,但是当值不同的时候,如果这些不同的值的数据分布严重不均匀,会导致执行计划无法高效支持所有查询。这种情况在动态SQL和静态SQL中都比较常见,下面来介绍一下处理方法:

    OPTION(RECOMPILE):

    对,你又见到它了。在上面提到的特定情况下,如果查询条件是@fromdate和@todate,添加OPTION(RECOMPILE):

    IF (@fromdate IS NOT NULL OR @todate IS NOT NULL)
       SELECT @sql += ' OPTION(RECOMPILE)' + @nl

    通常来说,当你发现查询条件上有合适的索引,并且选择度非常依赖于实际值的输入,那么可以添加OPTION(RECOMPILE),以便你总能通过编译得到关于当前统计信息的最佳执行计划。但是显然这种方式会添加一部分不必要的编译,比如两次执行的值完全一样时,依旧还会编译。

     

    索引提示和其他提示:

    有时候可以尝试使用“提示,hints”,可以通过CASE WHEN 判断需要传入什么参数,并且对这些参数额外指定需要走的索引。但是正如前面提到过的,提示要慎用,特别是索引提示,除非你确保索引名永不变更:

    FROM   dbo.Orders o ' + CASE WHEN @custid IS NOT NULL AND
                                      (@fromdate IS NOT NULL OR
                                      @todate IS NOT NULL) 
                                 THEN 'WITH (INDEX = CustomerID) '
                                 ELSE ''
                             END


    另外一种提示是使用OPTIMIZE FOR。如果你希望执行计划总是使用占用最多的情况来编译,比如前面提到的status类型中的C,那么可以添加:

    IF @status IS NOT NULL
       @sql += ' OPTION (OPTIMIZE FOR (@status = ''C''))'

    如果你不想优化器通过嗅探参数来产生执行计划,可以使用:

    IF @fromdate IS NOT NULL AND @todate IS NOT NULL
       @sql += ' OPTION (OPTIMIZE FOR (@fromdate UNKNOWN, @todate UNKNOWN))'

    这样优化器就不会使用标准假设,即10%左右来编译查询。

     本文出处:http://blog.csdn.net/dba_huangzj/article/details/50202371

     

    总结:


    动态SQL很强大,但是如果读者归纳能力比较强的话,可以看到,动态SQL的问题主要是在不能很好地利用计划缓存或使用的是不合适的执行计划,导致性能问题。

    对于这类情况,有很多方法可以使用,而且如果可以,不妨考虑非数据库层面的其他技术。但是我们的目的还是一个:保证执行计划针对任何参数,最起码绝大部分参数都是最佳的,并且能够尽可能重用。

    最后,需要提醒的是,任何技术、技巧,都应该在尽可能贴近实际环境的测试环境中做充分的测试,以便得到你希望的结果。

     本文出处:http://blog.csdn.net/dba_huangzj/article/details/50202371

     

    展开全文
  • PL/SQL 动态 SQL

    2015-03-08 20:44:51
    它是运行时才动态拼接和执行 SQL。相对于静态 SQL,它最大优势就是灵活,可以执行 DDL 语句。缺点是它没有经过预编译,运行时可能由于拼接错误、权限等问题失败。我们可以通过下面两种方式执行动态 SQL。 ...

    -- Start

    什么是动态 SQL 呢?它是运行时才动态拼接和执行的 SQL。相对于静态 SQL,它最大的优势就是灵活,可以执行 DDL 语句。缺点是它没有经过预编译,运行时可能由于拼接错误、权限等问题失败。我们可以通过下面两种方式执行动态 SQL。

    EXECUTE IMMEDIATE

    -- 创建测试表  
    CREATE TABLE student  
    (  
      id number(10),  
      name varchar2(20)  
    );  
      
    -- 创建测试存储过程  
    CREATE OR REPLACE PROCEDURE insert_student  
    (  
        id IN OUT student.id%TYPE,  
        name student.name%TYPE  
    ) IS  
        max_id student.id%TYPE;  
    BEGIN  
        select max(id) into max_id from student;  
      
        if id <= max_id then  
          id := max_id + 1;  
        end if;  
      
        insert into student values (id, name);  
    END;  
      
    -- 测试动态 SQL  
    DECLARE  
      id number(10);  
      name varchar2(20);  
        
      TYPE name_list IS TABLE OF student.name%TYPE;  
      names name_list := name_list();
      
      studentCur  SYS_REFCURSOR;
    
    BEGIN  
      -- 无绑定变量  
      EXECUTE IMMEDIATE 'delete from student';  
        
      -- 输入绑定变量  
      id := 1;  
      name := 'Shang Bo';  
      EXECUTE IMMEDIATE 'insert into student values (:a, :b)' USING id, name;  
      EXECUTE IMMEDIATE 'insert into student values (:x, :y)' USING 2, 'Zhang San';  
        
      -- RETURNING INTO  
      EXECUTE IMMEDIATE 'update student set name = :a where id = :b returning name into :name' USING 'Wang wu', 1 RETURNING INTO name;  
      DBMS_OUTPUT.PUT_LINE('name = ' || name);  
        
      -- RETURNING BULK COLLECT INTO  
      EXECUTE IMMEDIATE 'update student set name = :a returning name into :names' USING 'Wang wu' RETURNING BULK COLLECT INTO names;  
      FOR i IN names.FIRST()..names.LAST() LOOP      
        DBMS_OUTPUT.PUT_LINE(i || '-' || names(i));      
      END LOOP;  
        
      -- select 返回一行  
      id := 1;  
      name := '';  
      EXECUTE IMMEDIATE 'select name from student where id = :b' INTO name USING id;  
      DBMS_OUTPUT.PUT_LINE('name = ' || name);  
        
      -- select 返回多行
      EXECUTE IMMEDIATE 'select name from student' BULK COLLECT INTO names;  
      FOR i IN names.FIRST()..names.LAST() LOOP      
        DBMS_OUTPUT.PUT_LINE(i || '-' || names(i));      
      END LOOP;
      
      -- select 返回多行
      OPEN studentCur FOR 'select name from student';
      LOOP
        FETCH studentCur INTO name;
        EXIT WHEN studentCur%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE('name = ' || name);
      END LOOP;
      CLOSE studentCur;
        
      -- 调用存储过程,输入输出绑定变量  
      id := 1;  
      EXECUTE IMMEDIATE 'BEGIN insert_student(:a, :b); END;' USING IN OUT id, 'Li Si';  
      DBMS_OUTPUT.PUT_LINE('id = ' || id);  
    END;  


    DBMS_SQL

    下面是一个简单的例子,有关更多如果使用它的例子请参考 “Oracle Database PL/SQL Packages and Types Reference”

    DECLARE
      cursor_name INTEGER;
      rows_processed INTEGER;
    BEGIN
      -- 第一步:打开游标
      cursor_name := dbms_sql.open_cursor;
      
      -- 第二步:解析游标
      DBMS_SQL.PARSE(cursor_name, 'DELETE FROM employees WHERE salary > :x',DBMS_SQL.NATIVE);
      
      -- 第三步:绑定变量
      DBMS_SQL.BIND_VARIABLE(cursor_name, ':x', 9999);
      
      -- 第四步:执行
      rows_processed := DBMS_SQL.EXECUTE(cursor_name);
      
      -- 第五步:关闭游标
      DBMS_SQL.CLOSE_CURSOR(cursor_name);
      
      -- 异常处理部分
      EXCEPTION
        WHEN OTHERS THEN
          DBMS_SQL.CLOSE_CURSOR(cursor_name);
    END;

    --更多参见:Oracle PL/SQL 精萃

    -- 声明:转载请注明出处

    -- Last Edited on 2015-06-02

    -- Created by ShangBo on 2015-03-08

    -- End


    展开全文
  • Mybatis动态Sql核心

    2019-05-16 16:24:50
    Mybatis动态Sql核心 目录 Mybatis动态Sql核心 1.MybatisXML配置文件解析 Mybatis 缺点总结 1.必须传是类型或者Map集合 无法传入单值 否则报错 2.当使用set必须保证有一个条件成立 否则sql语法异常(...

                                     Mybatis动态Sql核心

    目录

                                     Mybatis动态Sql核心

    1.Mybatis的XML配置文件解析

    Mybatis 缺点总结

    1.必须传的是类型或者Map集合  无法传入单值   否则报错

    2.当使用set必须保证有一个条件成立 否则sql语法异常(有一定的局限性)

    3.当使用trim标签必须保证有一个条件成立 否则sql语法异常(有一定的局限性)

    2.Demo接口测试代码



    1.Mybatis的XML配置文件解析

    Mybatis 缺点总结

    1.必须传的是类型或者Map集合  无法传入单值   否则报错

    <select id="findAllUsers_if"
    	        resultMap="user_map"
    	        parameterType="User">
    		<include refid="select_user"></include>
    		where address='北京'
    		<if test="name != null">
    		   and username =#{name}
    		</if>
    	</select>
    	<!-- choose when otherwise -->
    	<select id="findAllUsers_choose"
    	        resultMap="user_map"
    	        parameterType="java.util.Map">
    		<include refid="select_user"></include>
    		where address='北京'
    		<choose>
    			<when test="uname !=null">
    				and username =#{uname}
    			</when>
    			<!-- <otherwise>
    			    and userpassword like '%%'
    			</otherwise> -->
    		</choose>
    	</select>

    2.当使用set必须保证有一个条件成立 否则sql语法异常(有一定的局限性)

    	<!-- update标签 
    	第一个if条件成立,第二条件不成立,会自动去掉后面的逗号
    	如果两个条件都不成立,set不会出现,但是会报异常,sql语法异常
    	至少有一个条件要成立    
    	-->
    	<update id="updateUser_set"
    	        parameterType="java.util.Map">
    		update t_user
    		<set>
    		   <if test="uname!=null">username=#{uname},</if>
    		   <if test="upwd!=null">userpassword=#{upwd}</if>
    		</set>
    		where id=#{uid}
    	</update>

    3.当使用trim标签必须保证有一个条件成立 否则sql语法异常(有一定的局限性)

    <!-- 用trim 替换set
    	prefix="SET"  前缀为set
    	suffixOverrides="," 后缀覆盖
    	第一个if成立,第二 if不成立会去掉后面的逗号
    	至少有一个if要成立,否者会语法异常
    	 -->
    	<update id="updateUser_trim2"
    	        parameterType="java.util.Map">
    		update t_user
    		<trim prefix="SET" suffixOverrides=",">
    		   <if test="uname!=null">username=#{uname},</if>
    		   <if test="upwd!=null">userpassword=#{upwd}</if>
    		</trim>
    		where id=#{uid}
    	</update>

    2.Demo接口测试代码

    ​
    package com.tarena.dao;
    
    import java.security.acl.Group;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import com.tarena.entity.User;
    
    public interface UserMapper {
    	public int addUser(User user);
    	public int deleteUser(Integer id);
    	public int updateUser(User user);
    	
    	public User findUserById(Integer id);
    	public List<User> findAllUsers();
    	
    	//动态sql
    	public List<User> findAllUsers_if(User user); //不能放单值
    	public List<User> findAllUsers_choose(Map data);//Map
    	public List<User> findAllUsers_where(Map data);
    	public int updateUser_set(Map data);
    	public List<User> findAllUsers_trim1(Map data);
    	public int updateUser_trim2(Map data);
    	public List<User> findAllUsers_foreach(ArrayList ids);
    	
    	public User findUserById_association(int id);
    	public Group findGroupById_collection(int id);
    }
    
    ​

    3.单元测试小案例

    package com.tarena.test;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import com.tarena.dao.UserMapper;
    import com.tarena.entity.Group;
    import com.tarena.entity.User;
    import com.tarena.util.MyBatisUtil;
    
    public class TestUserMapperClass {
    	@Test
    	public void testFindUserById(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			//用UserMaper接口利用jdk动态代理生成接口儿子代理类,用代理生成代理对象
    			//用代理对象调用目标方法,实际上执行的是InvocationHandler中的invoke方法
    			//在invoke方法中调用selectOne等原生api方法,来做增删改查
    			// 接口类型    jdk动态代理对象=sqlSession.getMapper(接口类型.class);
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			User user=userMapper.findUserById(7);
    			System.out.println(user);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}
    		
    	}
    	@Test
    	public void testFindAllUsers(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			List<User> users=userMapper.findAllUsers();
    			for(User  user : users)
    			System.out.println(user);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testAddUser(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			User user=new User();
    			user.setName("ff");
    			user.setAddress("ff");
    			user.setPassword("ff");
    			int rowAffect=userMapper.addUser(user);
    			System.out.println(rowAffect);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testDeleteUser(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			
    			int rowAffect=userMapper.deleteUser(2);
    			System.out.println(rowAffect);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testUPdateUser(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			User user=new User();
    			user.setId(7);
    			user.setName("ff");
    			user.setAddress("ff");
    			user.setPassword("ff");
    			int rowAffect=userMapper.updateUser(user);
    			System.out.println(rowAffect);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindAllUser_if(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			User user=new User();
    			//user.setName("eee");
    			List<User> users=userMapper.findAllUsers_if(user);
    			for(User u : users){
    				System.out.println(u);
    			}
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindAllUser_choose(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			Map data=new HashMap();
    			//data.put("uname", "eee");
    			List<User> users=userMapper.findAllUsers_choose(data);
    			for(User u : users){
    				System.out.println(u);
    			}
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindAllUser_where(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			Map data=new HashMap();
    			//data.put("uname", "eee");
    			data.put("uaddress", "北京");
    			List<User> users=userMapper.findAllUsers_where(data);
    			for(User u : users){
    				System.out.println(u);
    			}
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testUpdateUser_Set(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			Map data=new HashMap();
    			data.put("uid", new Integer(8));
    			//data.put("uname", "ffff");
    			//data.put("upwd", "ffff");
    			int rowAffect=userMapper.updateUser_set(data);
    			System.out.println(rowAffect);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindAllUser_trim1(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			Map data=new HashMap();
    			//data.put("uname", "eee");
    			//data.put("uaddress", "北京");
    			List<User> users=userMapper.findAllUsers_trim1(data);
    			for(User u : users){
    				System.out.println(u);
    			}
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testUpdateUser_trim2(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			Map data=new HashMap();
    			data.put("uid", new Integer(8));
    			//data.put("uname", "f");
    			//data.put("upwd", "ffff");
    			int rowAffect=userMapper.updateUser_trim2(data);
    			System.out.println(rowAffect);
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindAllUser_foreach(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			ArrayList ids=new ArrayList();
    			ids.add(4);
    			ids.add(6);
    			ids.add(7);
    			List<User> users=userMapper.findAllUsers_foreach(ids);
    			for(User u : users){
    				System.out.println(u);
    			}
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindUserById_association(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			
    			User user=userMapper.findUserById_association(8);
    			
    			System.out.println(user);
    			
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    	@Test
    	public void testFindUserById_collection(){
    		SqlSession sqlSession=null;
    		try{
    			sqlSession=MyBatisUtil.getSession();
    			UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    			
    			Group group=userMapper.findGroupById_collection(1);
    			
    			System.out.println(group);
    			
    			sqlSession.commit();
    		}catch(Exception e){
    			e.printStackTrace();
    			sqlSession.rollback();
    		}finally{
    			sqlSession.close();
    		}		
    	}
    }
    

     

     

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.tarena.dao.UserMapper">
    <!-- namespace必须为包名.接口名 -->
        <!-- resultMap标签 -->
        <resultMap type="User" id="user_map">
        	<!-- 主键 -->
        	<id property="id" column="id"/>
        	<!-- 非主键 -->
        	<result property="name" column="username"/>
        	<result property="password" column="userpassword"/>
        	<result property="address" column="address"/>
        </resultMap>
        <!-- sql标签 -->
        <sql id="select_user" >
            select 
    		    id,
    		    username,
    		    userpassword,
    		    address
    		from
    		t_user
        </sql>
        <!-- 根据id查询一个对象
        id="findUserById"   必须接口中的方法名称
        parameterType="java.lang.Integer"  必须对应接口方法参数类型
        resultType="User"  必须对应接口中的方法的返回类型
         -->
    	<select id="findUserById"
    	        parameterType="java.lang.Integer"
    	        resultMap="user_map" >
    		<include refid="select_user"></include>
    		   where id=#{id}    
    	</select>
    	<!-- 查询多个 -->
    	<select id="findAllUsers"
    	        resultMap="user_map">
    		<include refid="select_user"></include>
    	</select>
    	<insert id="addUser"
    	        parameterType="com.tarena.entity.User">
    	    insert into t_user
    	    (
    	    	username,
    	    	userpassword,
    	    	address
    	    )    
    	    values
    	    (
    	    	#{name},
    	    	#{password},
    	    	#{address}
    	    )
    	</insert>
    	<!-- 删除用户  -->
    	<delete id="deleteUser"
    	        parameterType="java.lang.Integer">
    		delete from t_user where id=#{id}
    	</delete>
    	<!-- 更新用户信息 -->
    	<update id="updateUser"
    	        parameterType="com.tarena.entity.User">
    		update t_user set
    		   username=#{name},
    		   userpassword=#{password},
    		   address=#{address}
    		where 
    		   id=#{id}
    	</update>
    	<!-- 动态sql的开始 -->
    	<!-- if标签
    	 parameterType="User"  要求是实体对象和map
    	 if条件成立连接sql条件
    	 -->
    	<select id="findAllUsers_if"
    	        resultMap="user_map"
    	        parameterType="User">
    		<include refid="select_user"></include>
    		where address='北京'
    		<if test="name != null">
    		   and username =#{name}
    		</if>
    	</select>
    	<!-- choose when otherwise -->
    	<select id="findAllUser s_choose"
    	        resultMap="user_map"
    	        parameterType="java.util.Map">
    		<include refid="select_user"></include>
    		where address='北京'
    		<choose>
    			<when test="uname !=null">
    				and username =#{uname}
    			</when>
    			<otherwise>
    			    and userpassword like '%%'
    			</otherwise>
    		</choose>
    	</select>
    	<!-- where 标签 
    	if的条件,第一个不成,第二成立
    	  where and address=#{uaddress}
    	  如果mybatis检测到where 后and,则去除and关键字
    	   如果if条件都不成立    where关键会去掉
    	-->
    	<select id="findAllUsers_where"
    	        resultMap="user_map"
    	        parameterType="java.util.Map">
    		<include refid="select_user"></include>
    		<where>
    			<if test="uname !=null">
    				username=#{uname}
    			</if>
    		    <if test="uaddress !=null">
    		    	and address=#{uaddress}
    		    </if>
    		</where>
    		
    	</select>
    	<!-- update标签 
    	第一个if条件成立,第二条件不成立,会自动去掉后面的逗号
    	如果两个条件都不成立,set不会出现,但是会报异常,sql语法异常
    	至少有一个条件要成立        Mybatis底层写的还是不太好
    	-->
    	<update id="updateUser_set"
    	        parameterType="java.util.Map">
    		update t_user
    		<set>
    		   <if test="uname!=null">username=#{uname},</if>
    		   <if test="upwd!=null">userpassword=#{upwd}</if>
    		</set>
    		where id=#{uid}
    	</update>
    	<!-- 用trim标签替换where标签 
    	  prefix="WHERE" prefix:前缀   where
    	  prefixOverrides="AND|OR"    prefixOverrides:前缀覆盖
    	  第一个if不成立,第二if成立,会prefixOverrides中设置的值去覆盖
    	  都不成立where前缀会去掉
    	-->
    	<select id="findAllUsers_trim1"
    	        resultMap="user_map"
    	        parameterType="java.util.Map">
    		<include refid="select_user"></include>
    		<trim prefix="WHERE" prefixOverrides="AND|OR">
    		 	<if test="uname !=null">
    				username=#{uname}
    			</if>
    		    <if test="uaddress !=null">
    		    	and address=#{uaddress}
    		    </if>
    		</trim>
    	</select>
    	<!-- 用trim 替换set
    	prefix="SET"  前缀为set
    	suffixOverrides="," 后缀覆盖
    	第一个if成立,第二 if不成立会去掉后面的逗号
    	至少有一个if要成立,否者会语法异常
    	 -->
    	<update id="updateUser_trim2"
    	        parameterType="java.util.Map">
    		update t_user
    		<trim prefix="SET" suffixOverrides=",">
    		   <if test="uname!=null">username=#{uname},</if>
    		   <if test="upwd!=null">userpassword=#{upwd}</if>
    		</trim>
    		where id=#{uid}
    	</update>
    	<!-- foreach标签 -->
    	<select id="findAllUsers_foreach"
    	        parameterType="java.util.ArrayList"
    	        resultMap="user_map">
    		<include refid="select_user"></include>
    		where id in
    		<foreach collection="list"
    		         item="id"
    		         open="("
    		         separator=","
    		         close=")">
    			#{id}
    		</foreach>   
    	</select>
    	<!-- 动态sql的结束 -->
    	<!-- mybatis的关联映射查询开始 -->
    	<!-- 对一关联 查用户信息 -->
    	<resultMap type="User" id="userMap">
    		<id property="id" column="uid"/>
    		<result property="name" column="username"/>
    		<result property="password" column="userpassword"/>
    		<result property="address" column="address"/>
    		<association property="group" javaType="Group">
    			<id property="id" column="gid"/>
    			<result property="name" column="groupname"/>
    			<result property="loc" column="grouploc"/>
    		</association>
    	</resultMap>
    	<select id="findUserById_association"
    	        parameterType="java.lang.Integer"
    	        resultMap="userMap">
    	   select 
    	       u.id uid,
    	       u.username,
    	       u.userpassword,
    	       u.address,
    	       g.id gid,
    	       g.groupname,
    	       g.grouploc 
    	   from 
    		   (
    		   select * from t_user where id=#{id}
    		   ) u
    	   left join t_group g
    	   on u.group_id=g.id
    	   
    	</select>
    	<!--对多关联 查组信息 -->
    	<resultMap type="User" id="tempUserMap">
    		<id property="id" column="uid"/>
    		<result property="name" column="username"/>
    		<result property="password" column="userpassword"/>
    		<result property="address" column="address"/>
    	</resultMap>
    	<resultMap type="Group" id="groupMap">
    		<id property="id" column="gid"/>
    		<result property="name" column="groupname"/>
    		<result property="loc" column="grouploc"/>
    		<collection property="users"
    		            ofType="User"
    		            javaType="java.util.List"
    		            resultMap="tempUserMap">
    			
    		</collection>
    	</resultMap>
    	<select id="findGroupById_collection"
    	        parameterType="java.lang.Integer"
    	        resultMap="groupMap">
    		select 
    			g.id gid,
    			g.groupname,
    			g.grouploc,
    			u.id uid,
    			u.username,
    			u.userpassword,
    			u.address
    		from
    		   (
    		      select * from t_group where id=#{id}
    		   ) g
    		left outer join t_user u
    		   on g.id=u.group_id
    	</select>
    	<!-- mybatis的关联映射查询结束 -->
    </mapper>

     

    展开全文
  • SQL与ORM缺点

    千次阅读 2018-05-18 11:28:39
    相对来说,ORM的缺点就是SQL的优势地方,而优点也是SQL的劣势地方。优点方便的使用面向对象,语句清晰防注入『这个其实不算ORM的核心,因为比如Phalcon的SQL形式写法也可以防注入』方便动态构造语句,对于不同的表的...

    相对来说,ORM的缺点就是SQL的优势地方,而优点也是SQL的劣势地方。

    • 优点
      • 方便的使用面向对象,语句清晰
      • 防注入『这个其实不算ORM的核心,因为比如Phalcon的SQL形式写法也可以防注入』
      • 方便动态构造语句,对于不同的表的相同操作采用多态实现更优雅
      • 一定程度方便重构数据层『比如改表名,字段名等』
      • 设置钩子函数
    • 缺点
      • 不太容易处理复杂查询语句
      • 性能较直接用SQL差

    如何选择

    尽量使用ORM,除了含子查询的复杂语句『不过大流量下的网站最好不要写这种复杂SQL』,当然这也只是一个原则,所以反过来说也可以,不过以下几个场景用ORM的好处是很明显的

    • Model对象不确定的时候,使用多态的方式去处理不同实例的相同操作
    • 语句结构不确定的时候,比如根据不同的情况Where子句不一样的时候,采用if的代码结构去控制ORM方法的使用比拼接SQL语句要清晰的多
    • 设置钩子函数,比如分页里面,拿分页数据同时要count数据,那么就可以在Model里面插入这个算count的钩子函数(包括缓存逻辑)



    展开全文
  •  缺点:如果仅仅是第二个条件满足导致sql语句出错(故使用if+where) 1 <select id="select1" resultType="com.zhiyou.clg.bean.User"> 2 select *from user 3 <if test="name...
  • 动态SQL和静态sql的缺点 --通过动态sql来具体说明 MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保...
  • iBatis动态Sql解决In子句替代方法

    千次阅读 2012-12-12 11:01:11
    在iBatis中,对于in子句的标准做法是采用动态sql来解决的。具体方法大致是:Java代码传入一个List或者数组,然后在sqlMapConfig映射中使用iterate循环取这个变量,动态地生成sql语句。 这个标准解法的缺点是,使用...
  • 动态的SQL语句,就是指在运行时候,根据Mapper.xml中语句,来决定方法传入参数使用。 使用 <if test=""></if>标签 Mapper.xml中配置 if 判断 参数传入值,判断是否可以使用,再执行SQL语句, ...
  • 在写SQL语句时,往往会有一些查询条件,但这些查询条件有时候有,有时候没有,那么mybatis提供的动态SQL可以解决这类问题。 如:根据条件查询用户列表,如果用户名不为空,则返回名字为参数用户列表,如果为空则...
  • 一、不用where 1=1 在多条件查询中困扰 举个例子,如果您做查询页面,并且,可查询选项有多个,同时,还让用户自行选择并输入查询关键词,那么,按平时查询语句的动态构造,代码大体如下: 代码如下: ...
  • 一.MyBatis接口映射 MyBatis接口映射这个机制是通过面向接口...基于XML:优点是可维护性、可拓展性高,SQL改动不需要动源代码,改配置文件即可,缺点是编写配置文件较为繁琐,需要定义大量节点标签。 基于注解:...
  • SQL Server 2005中使用synonyms缺点 http://tech.ddvip.com 2008年09月10日 社区交流 关键字:DataGuard checkpoint 动态查询 synonyms 卸载SQL 2
  • 2019-8-30 大纲 ...1.动态sql语句(即sql语句拼接) 1.1 if标签(属性:test(判断条件)) 缺点:如果仅仅是第二个条件满足导致sql语句出错(使用if+where) <select id="select1" resultType=...
  • SQL语句动态传入表名

    2020-05-02 20:10:20
    在ssm框架中,由于sql语句是动态编译,所以会在传入字符串加入“ ‘’ ”,而表名是不允许有,起初我想用trim去除,发现不管用,后来发现有statementType函数,一共有三种属性我就不一一列举了。 直接解决办法...
  • 优点:  可以在SQL语句中调用,直接使用返回值,从而可以形成复杂SQL应用。 缺点:  能在函数中使用语句有严格限制: 不支持create、ALTER、drop等...不支持动态SQL; 不支持“不确定”函数,比如常用g...
  • 使用了 MyBatis 之后,只需要提供 SQL 语句就好,基于java持久层框架。 持久层: 可以将业务数据存储到磁盘,具备长期存储能力,只要磁盘不损坏,在断电或者其他情况下,重新开启系统仍然可以读取到这些数据。 ...
  • SpringDataJPA学习记录(四)--使用QueryDSL标签(空格分隔): springJPA1.问题提出最近再看公司项目中有如下代码,看了后...这个就无法直观得知.sql中复杂关系导致不可维护,每一个接手人都要研究sql半天该种动...
  • SQL 动态行变列转换

    2013-07-25 17:30:49
    SQL中有一类需求,需要行遍... Pivot方法能够同动态行变列,但还是有个缺点,只能出一个指标,比如demo只有分数一个指标,假如还有多个指标话,需要多个SQL拼接也倒是可行。   问题: 对于动态的转换有一个相对
  • 一 : 返回主键 (一) selectKey ...(三) 优缺点 : 数据库是否可以自动生成主键无所谓(主键自增) useGeneratedKeys : 要求数据库本身是支持自动生成主键(主键自增) 二 : sql片段 三 : 分页查询 (一) 官方文档 ...
  • Mybaits 缺点

    2020-09-24 22:35:14
    XML 中提供了动态 SQL 标签,方便根据条件拼接 SQL 提供了 XML、注解与 Java 对象映射机制 与 Spring 集成比较方便 缺点: 字段较多、关联表多时,编写 SQL 工作量较大 SQL 语句依赖了数据库特性,会导致...
  • 1、原生sql方式(Dto里数据来自同一个数据库,缺点是Dto里要是有从其他模块call到数据,若是用此字段排序,则不能实现排序和分页) 2、List工具类方式(缺点是必须先查出全部符合数据,才能再进行分页和排序)...
  • mybatis缺点

    2017-05-05 15:40:43
    mybatis缺点 优点: 1. 易于上手和掌握。 2. sql写在xml里,便于统一管理和优化。...6. 提供xml标签,支持编写动态sql缺点: 1. sql工作量很大,尤其是字段多、关联表多时,更是如此。 2. sql依
  • Mybatis缺点

    2020-05-09 17:16:13
    提供XML标签,支持编写动态SQL 提供映射标签,支持对象与数据库ORM字段关系映射 2.缺点: SQL语句编写工作量大,熟练度要高 数据库移植性差,比如mysql移植到Orecle,SQL语句会有差异从而引起err ...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 307
精华内容 122
关键字:

动态sql的缺点