zoukankan      html  css  js  c++  java
  • SOFIRE v1.5 概念版—— XSQL

    Sofire Suite 是一套个人从 2009 年 08 月开始着手研发的套件。历经几年的不断优化改进,从最初的 V 套件到 Sofire2011 到目前的 Sofire.v1.5 概念版,Sofire 已经经历了许多项目的考验,并且出色的完成它的使命。现在,我将这套组件再次重构,尝试让它成为任意平台、框架、套件的的底层首选。秉着开源精神,希望这套组件在博友的讨论中不断成长、成熟。

    本文主要介绍是概念版的—— SOFIRE XML SQL,我们称之为 X-SQL。

    目录

    什么是 X-SQL?

    前两个礼拜,某个同事在公司内部,举办了一场小型培训会。他给大家绍 JAVA 的一个开源套件——MyBatis(百度百科) 。

    关于 Mybatis 含有一个非常重要的功能,就是 XML 化 T-SQL 语句(也成为动态 T-SQL)。它彻底的将 T-SQL 语句从代码层上剥离,最大程度的动态化,也提高了产品的可维护性。

    或许,这只是 Mybatis 的功能之一,我并没有对它的其他功能进行深入研究。不过我却对它的设计理念充满兴趣,培训会结束后,我便搜寻有基于 .NET 版的 Mybatis。

    Mybatis.NET,总体来说还算不错,但它有一些与 JAVA 版的 Mybatis 不同,比如在条件判断上他并不是采用 "test" 属性进行验证,而是通过条件 XML 元素(如 isNotNull XML 元素之类)进行判定。

    Mybatis for .NET 示例
        <insert id="InsertAccountDynamic" parameterClass="Account">
          INSERT INTO Accounts
          (Account_ID, Account_FirstName, Account_LastName, Account_Email)
          VALUES(#Id#, #FirstName#, #LastName#
          <dynamic prepend=",">
            <isNotNull prepend="," property="EmailAddress">
              #EmailAddress#
            </isNotNull>
            <isNull prepend="," property="EmailAddress">
              null
            </isNull>
          </dynamic>
          )
        </insert>
                        
    Mybatis for JAVA 示例
        <update id="updateStudent_if_set" parameterType="liming.student.manager.data.model.StudentEntity">
    	    UPDATE STUDENT_TBL
    	    <set>
    		    <if test="studentName != null and studentName != '' ">
    			    STUDENT_TBL.STUDENT_NAME = #{studentName},
    		    </if>
    	    </set>
    	    WHERE STUDENT_TBL.STUDENT_ID = #{studentId};	
        </update>
                        

    从上面的 XML 可以看出,Mybatis.NET 的 XML 表达式判定语法显得十分臃肿,在多条件(如“userid=1 or userid=2”)无法友好的展示。所以……我的臭毛病又爆发了——“造轮子”。

    好吧,我承认我的轮子已经造的过多了……

    X-SQL 支持什么功能?

    从整体功能方面,我尽可能的参考 Mybatis,但并不会失去 X-SQL 本身存在的特点(高效什么等,我就不扯蛋了):

    • X-SQL 元素包含:xsql、expression(表达式)、if-else、switch-case-default、foreach、include(引用)、trim(修剪)、parameters(手动定义参数)
    • 内置缓存机制(None、Names、Values、Forever)。
    • 生成 Sofire.Data.ExecuteCommand 对象(不理解此对象的可以参考 此篇文章)。
    • 支持参数绑定语法。拒绝拼接语法,参数化 T-SQL。当然,也支持非参数化参数绑定。这点与 Mybatis 完全不同。
    • 支持 test 表达式以及自定义函数(解释器是亮点):
      0、关键字(所有关键字、参数、函数均匹配大小写)
      	and、or、not、true、false、null、if、E(检查一下)
      1、基本数据类型(Integer、String、DateTime、Float、Boolean)
      2、支持
      					x:数字		s:字符串		d:日期		o:任意类型
      	数学函数	:Abs(x)、Acos(x)、Asin(x)、Atan(x)、Ceiling(x)、Cos(x)、Exp(x)、Floor(x)
      				:IEEERemainder(x1,x2)、Log(x1,x2)、Log10(x)、Pow(x1,x2)、Round(x1,x2)、Sign(x)
      				:Sin(x)、Sqrt(x)、Tan(x)、Truncate(x)、Max(x1,x2)、Min(x1,x2)、Floor(x)
      
      	字符串函数	:isEmpty(s)、len(s)、lower(s)、upper(s)
      				:trim(s)、ltrim(s)、rtrim(s)
      				:contains(s1,s2)、left(s1,s2)、right(s1,s2)
      				:indexOf(s1,s2,[index],[count])、lastIndexOf(s1,s2,[index],[count])
      				:substr(s1,index,[length])、remove(s1,index,[length])
      				:replace(s1,s2,s3)
      				:regexMatch(input,pattern,'[mir]')
      				:regexSplit(input,pattern,'[mir]')
      				:regexReplace(input,pattern,replacement,'[mir]')
      				:concat(arg1,arg2,arg...,argN)
      
      	日期函数	:date([year],[month],[day],[hour],[minute],[second])
      				:year(d)、month(d)、day(d)、hour(d)、minute(d)、second(d)、millisecond(d)
      				:dayOfWeek(d)、dateIn(d,beginDate,endDate)、dateAdd(d,x)
      
      	转换函数	:toDate(s)、toInteger(s)、toFloat(s)、toString(o,[format])、toBoolean(s)
      
      	其他函数	:newGuid('N/D/B/P')
      				:if(boolean,trueValue,falseValue)
      				:in(o,arg1,arg2,arg...,argN)
      				:isnull(o,defaultValue)
      
      3、支持参数/函数的(预)定义,字符串拼接(+),
      4、支持数字、浮点数、文本('string')、日期格式(#2012-01-01#)
      5、支持以下运算符(一元、二元、三元):
      		
      			!	 	!=	 	%	 	&&	 	&	
      			(	 	)	 	*	 	+	 	,	
      			-	 	/	 	:	 	<	 	<<	
      			<=	 	<>	 	=	 	==	 	>	
      			>=	 	>>	 	?	 	^	 	and	
      			not	 	or	 	|	 	||	 	~	
      		
      
    • 更多....
    X-SQL 元素
    本节针对 X-SQL 的各类元素,进行简单的讲解(注意,元素区分大小写,懒判断模式)。
    document 元素
    document 元素是一个 .xsql 文件的根级树节点。目前该元素没有任何的属性,因为目前我还没有想好什么全局配置。
    xsql 元素
    xsql 元素,是 document 元素下的的一个重要元素,表示一个动态的 T-SQL 生成节点。xsql 可以放在两个地方,表示不同的含义。
    1. document 元素下,表示一个 X-SQL 的生成函数。
    2. parameters 元素下,表示一个立即执行的 X-SQL 元素(这句话比较拗口,简单的说,通过一个 SQL 生成递增序列,添加到参数集合中)。
    <?xml version="1.0" encoding="utf-8" ?>
        <document>
            <xsql name="selectAllStudent" cache="forever">
            SELECT
                STUDENT_ID
                ,STUDENT_NAME
                ,STUDENT_SEX
                ,STUDENT_BIRTHDAY
                ,STUDENT_PHOTO
            FROM DEMO_STUDENT
            </xsql>
        </document>
                        
    expression 元素
    expression 元素是一个特殊的元素,它表示一段表达式的解释结果(结果可以是任意值,但对于 test 属性,应该是 false)。同样,expression 也可以放在两个不同的地方,代表不同的含义。
    1. document 元素下,表示一个可调用的全局表达式(尚未实现,主要是存在性能问题,也可能是设计思路还未成熟)。
    2. parameters 元素下,表示一个立即解释的表达式,并将解释后的值添加到参数集合中。
    if-else 元素
    if 元素是一个判定元素,当表达式结果为 true 时,则编译 if 元素下的 X-SQL 内容,否则编译 else 元素下的内容(如果有)。
    <?xml version="1.0" encoding="utf-8" ?>
        <document>
          <xsql name="selectAllStudent"
                cache="forever">
            SELECT
            STUDENT_ID
            ,STUDENT_NAME
            ,STUDENT_SEX
            ,STUDENT_BIRTHDAY
            ,STUDENT_PHOTO
            FROM DEMO_STUDENT
          </xsql>
          <xsql name="test_if">
            <include path="selectAllStudent" />
            <trim prefix="WHERE"
                  trim="AND|OR">
              <if test="studentID==1">
                AND STUDENT_ID IN (1,2)
              </if>
              <else>
                AND STUDENT_ID=#{studentID}
              </else>
              <if test="studentName != null">
                AND STUDENT_NAME=#{studentName}
              </if>
            </trim>
          </xsql>
        </document>
                    
    switch-case-default 元素
    同 if-else 元素一样,switch 解释与 case 之间的 test 结果(switch 也拥有 test 属性,但不一定要填写),根据判定条件编译 case 元素下的内容,否则编译 default 元素的内容。
    <?xml version="1.0" encoding="utf-8" ?>
        <document>
          <xsql name="selectAllStudent"
                cache="forever">
            SELECT
            STUDENT_ID
            ,STUDENT_NAME
            ,STUDENT_SEX
            ,STUDENT_BIRTHDAY
            ,STUDENT_PHOTO
            FROM DEMO_STUDENT
          </xsql>
          <xsql name="test_switch" cache="values">
            <include path="selectAllStudent" />
            <switch test="studentName">
              <case test="=='张三'">
                STUDENT_ID=1
              </case>
              <case test="=='李四'">
                STUDENT_ID=2
              </case>
              <case test="=='王五'">
                STUDENT_ID=3
              </case>
              <default>
                STUDENT_ID IS NOT NULL
              </default>
            </switch>
          </xsql>
        </document>
                        
    foreach 元素
    foreach 元素是一个非常强大的元素。它解释一个集合类型(array、list等皆可)的参数,并赋予两个“动态绑定参数”:index 和 var。根据 in 参数(集合)进行循环取出结果。注意,in 参数必须存在,如果不存在则会抛出异常(但可以在之前添加一个 if 元素)。
    <?xml version="1.0" encoding="utf-8" ?>
        <document>
          <xsql name="selectAllStudent"
                cache="forever">
            SELECT
            STUDENT_ID
            ,STUDENT_NAME
            ,STUDENT_SEX
            ,STUDENT_BIRTHDAY
            ,STUDENT_PHOTO
            FROM DEMO_STUDENT
          </xsql>
          <xsql name="test_foreach" cache="names">
            SELECT * FROM STUDENTS
            <trim prefix="WHERE"
                  trim="AND|OR">
              <if test="studentSex!=null">
                AND STUDENT_SEX=#{studentSex}
              </if>
              <if test="studentNames!=null">
                AND STUDENTNAME IN(
                <foreach var="studentName"
                         in="studentNames"
                         trim=",">
                  ,#{studentName}
                </foreach>
                )
              </if>
            </trim>
          </xsql>
        </document>
                        
    include 元素
    include 元素是文档中使用最频繁的元素之一,它将指定的 xsql 元素编译并添加到当前位置(注,是当前位置!)。关于示例,上面的内容已经有包含了。
    trim 元素
    trim 元素一般用于 where 语句和 set 语句,该元素如果在存在内容时,添加 prefix 属性值,并且自动过滤头尾 trim 属性存在的值。具体示例查看if-else 元素
    parameters 元素
    parameters 元素一般用于自定义参数的情景。例如:ORACLE 插入序列时,需要访问 seq_xxx.nextval 来获取参数序列,并且希望整体 xsql 编译并执行了以后,调用方可以获取到该参数。parameters 可以包含两个子元素:expression 和 xsql 元素。
      <xsql name="insert_XML">
        <parameters>
            <xsql name="student_id"
                cache="forever">select studentPKSequence.nextVal from dual</xsql>
            <expression name="student_id3">student_id+1</expression>
        </parameters>
        INSERT INTO STUDENTS(STUDENT_ID,STUDENT_NAME) VALUES(#{student_id,decimal},#{name,string})
        </xsql>
                        
    X-SQL 的实践

    我整理了 12 个实例。你可以通过以下 gif 小动画来查看效果。

    X-SQL 的实践

    虽然我只进行了简单的测试,但 X-SQL 的性能还是十分理想的。在 foreach(该元素最消耗性能) 2000 次测试下,采用缓存是 200~300 毫秒,非缓存效果下 500~600 毫秒(非最佳效果,采用 release,但是在VS 运行测试,而不是直接打开)。

    在大多数情况下,我们建议采用 names(根据参数集合长度、参数名进行缓存)以及 forever(永久缓存)。而不建议使用 values(根据参数值缓存)。

    其实不一定要采用缓存,通过上面的数据可以看出,缓存的后的性能只有一倍之差(缓存的性能损耗:Dict.TryGetValue,可见 X-SQL 的高性能),如果在非硬性要求下,除了 forever 缓存,其他缓存均不推荐。

    最后

    压力测试的必要性还是有的,能否经历的起大项目的高频率、多线程调用,我只能表示“我有信心”。

    目前我将主要精力集中在:如何实现功能。对于性能等其他的要求,我只能延后。

    关于源码

    我很犹豫要不要开放出去,其实从之前的文章大家可以看得出,我秉着开源原则,所以开源是必然,但文章发表后为什么不放上源码,主要有两个考虑:

    • 你需要这份源码吗?
    • 你会为这份源码提出建议吗?

    如果有兴趣的朋友很多的话,我会开放到 CodePlex。

    最后,对博友 blue1000hpze2000 以及其他朋友说一声抱歉,由于最近公司正在着手新产品的研发,我负责的文档太多了,所以一直耽搁下来了。

    但我很高兴地告诉你们,关于 Sofire.DataComm.Remoting 以及 Sofire.DataComm.Net.Async 模块已经完成,并且新增了许多功能!系列文章一定会写出来的。

    Sofire.DataComm下个版本计划(v2.0)
    1、检查高并发下是否存在死锁(理论上暂时不存在),但在万并发量出现死顿(怀疑是本地网络问题?)。
    2、增加 buffer 发送前和接收后的(加解密)和(解压缩)。

    ************************* 2012-07-18 *************************
    1、修复 ThreadPool.QueueUserWorkItem 在高频发线程发生阻塞的问题。
    2、增加属性【ServiceVersion】,表示服务契约的版本信息,减少客户端连接时返回契约数据。
    3、增加属性【SessionExpiration】,表示会话的最大超时时间。小于 0 则表示无超时,等于 0 表示不启用。大于 0 则表示指定的超时秒数。默认为“20”秒。
    4、优化内部代码。
    5、v1.5 版功能已完成。

    我写的很用心,如果您对这篇文章感兴趣的话,请推荐……感谢!

  • 相关阅读:
    ACCESS中默认值要填双引号
    错误一直找不到
    员工自行车的摆放处
    连接占线导致另一个hstmt
    去裕利面试
    路上又一见闻
    企业的形象
    骏泰面试感觉
    IE 标点符号输入不顺的原因
    C Primer Plus(十七)
  • 原文地址:https://www.cnblogs.com/sofire/p/sofire_xsql_1_5.html
Copyright © 2011-2022 走看看