TangYuan之组合SQL服务标签

作者: xsonorg | 来源:发表于2016-12-17 21:01 被阅读49次

    6.4 组合SQL服务标签


    之前6.1节简单的介绍了组合SQL服务的概念和定义,这节将详细的介绍组合SQL服务的功能和使用。

    1. sql-service标签的使用

    Schema设计图

    图片1

    sql-service节点属性说明

    属性名 用途及说明 必填 取值
    id 服务标识,需要唯一;作为辅助标签此项无意义,可省略 Y 用户定义
    dsKey 所使用的数据源标识,这里有以下几种情况:<br />1.此处设置数据源(A),内部服务未设置数据源,内部服务使用数据源(A)。<br />2.此处设置数据源(A),内部服务设置数据源(B),内部服务使用数据源(B)。<br />3.此处未设置数据源,内部服务设置数据源(B),内部服务使用数据源(B)。<br />4.在分库分表的情况下,此处未和内部服务均可不设置数据源,后面章节将会详细介绍此种设置。 N 用户定义
    txRef 所使用的事务定义标识,如果用户未指定,则根据setDefaultTransaction所定义的规则进行默认匹配,如果还未匹配上,系统则会跑出异常。 N 用户定义
    resultType 返回类型:默认xco N xco/map
    cacheUse 缓存使用,此项将在缓存一节详细说明 N 用户定义
    cacheClear 缓存使用,此项将在缓存一节详细说明 N 用户定义

    说明:

    组合SQL服务是一个服务集合,他可以包含selectSetselectOneselectVarupdatedeleteinsert这6中基本服务标签一个或者多个,但不能包含自身sql-service标签。

    2. 内部selectSet标签的使用

    示例1:

    <sql-service id="myService" dsKey="ds" txRef="tx_02">
        <selectSet resultKey="{users}">
            select * from user
        </selectSet>
        <return>
            <property value="{users}"/>
        </return>
    </sql-service>
    

    说明:

    上述示例中我们定义了一个组合SQL服务myService,其内部包含了了一个selectSet基本服务,当程序执行完selectSet服务后会将其结果List<XCO>以users为key,放入上下文中,最后通过return标签返回。具体的返回结果是一个XCO对象,其中包含一个List<XCO>元素,关于return标签和返回结果的设定我们将在其他章节讲述,这里不再细说,下面给出返回结果的XML格式。

    返回结果

    <?xml version="1.0" encoding="UTF-8"?>
    <X>
        <XL K="users">
            <X>
                <L K="user_id" V="1"/>
                <S K="user_name" V="李四"/>
                <B K="user_age" V="18"/>
                <A K="create_time" V="2016-10-20 21:30:58"/>
            </X>
            <X>
                <L K="user_id" V="2"/>
                <S K="user_name" V="张三"/>
                <B K="user_age" V="18"/>
                <A K="create_time" V="2016-10-20 21:31:58"/>
            </X>
            ......
        </XL>
    </X>
    

    上述示例中selectSet作为内部服务,或者说内部标签,其属性的使用发生了一下变化:

    selectSet节点属性和变化说明:

    属性名 用途及说明 必填 取值
    id 无意义 N 用户定义
    dsKey 所使用的数据源标识,在有如下几种情况(非分库分表):<br />1.如果用户没有设置此属性,则使用sql-service节点的数据源;<br />2.如果用户自行设置了此属性,则使用用户所设置的数据源。<br />关于在分库分表的应用场景下,此项的设置我们将在具体的章节来说明。 N 用户定义
    txRef 无意义 N 用户定义
    resultKey 当前查询操作返回结果的在上下文参数中的存放key N 用户定义
    resultType 无意义 N 用户定义
    resultMap 无意义 N 用户定义
    fetchSize 每次查询的最大获取条数,默认255 N 用户定义
    cacheUse 缓存使用,此项将在缓存一节详细说明 N 用户定义

    看到这里大家可能会疑问,和示例1中,为什么不直接用selectSet标签呢?因为之前已经给已经给大家介绍过sql-service所定义的服务是一个组合服务,其内部可以包含selectSetselectOneselectVarupdatedeleteinsert这些基本服务,在后面的教程中大家就可以感受到组合服务的强大功能了。

    2. 内部selectOne标签的使用

    示例2:

    <sql-service id="myService2" dsKey="ds" txRef="tx_02">
        <selectOne resultKey="{user}">
            select * from user where user_id = #{user_id}
        </selectOne>
        <return value="{user}"/>
    </sql-service>
    

    说明:

    示例2中我们定义了一个组合SQL服务myService2,其内部包含了了一个selectOne基本服务,执行后返回结果是一个XCO对象,XML格式如下:

    返回结果

    <X>
        <L K="user_id" V="1"/>
        <S K="user_name" V="李四"/>
        <B K="user_age" V="18"/>
        <A K="create_time" V="2016-10-20 21:30:58"/>
    </X>
    

    selectOne节点属性和变化说明:

    属性名 用途及说明 必填 取值
    id 无意义 N 用户定义
    dsKey 同selectSet.dsKey N 用户定义
    txRef 无意义 N 用户定义
    resultKey 当前查询操作返回结果的在上下文参数中的存放key N 用户定义
    resultType 无意义 N 用户定义
    resultMap 无意义 N 用户定义
    fetchSize 每次查询的最大获取条数,默认255 N 用户定义
    cacheUse 缓存使用,此项将在缓存一节详细说明 N 用户定义

    3. 内部selectVar标签的使用

    示例3:

    <sql-service id="myService3" dsKey="ds" txRef="tx_02">
        <selectVar resultKey="{userName}">
            select user_name from user where user_id = #{user_id}
        </selectVar>
        <return>
            <property name="{userName}" value="{userName}"/>
        </return>
    </sql-service>
    

    说明:

    示例3中我们定义了一个组合SQL服务myService3,其内部包含了了一个selectVar基本服务,执行后返回结果是一个XCO对象,其中包含了一个userName元素,XML格式如下:

    返回结果

    <?xml version="1.0" encoding="UTF-8"?>
    <X>
        <S K="userName" V="李四"/>
    </X>
    

    selectVar节点属性和变化说明:

    属性名 用途及说明 必填 取值
    id 无意义 N 用户定义
    dsKey 同selectSet.dsKey N 用户定义
    txRef 无意义 N 用户定义
    resultKey 当前查询操作返回结果的在上下文参数中的存放key N 用户定义
    cacheUse 缓存使用,此项将在缓存一节详细说明 N 用户定义

    4. 内部update标签的使用

    示例4:

    <sql-service id="myService4" dsKey="ds" txRef="tx_02">
        <update rowCount="{nCount}">
            update user set user_name = '张三' where user_id = #{user_id}
        </update>
        <exception test="{nCount} != 1" code="-1" message="用户更新失败"/>
    </sql-service>
    

    说明:

    示例4中我们定义了一个组合SQL服务myService4,其内部包含了了一个update基本服务,当程序执行完update服务后会将影响行数以nCount为key,放入上下文中,然后通过exception标签判断nCount的有效性,如果nCount不满足条件,则无服务将抛出服务异常,并回滚之前的操作。

    返回结果: 无

    update节点属性和变化说明:

    属性名 用途及说明 必填 取值
    id 无意义 N 用户定义
    dsKey 同selectSet.dsKey N 用户定义
    txRef 无意义 N 用户定义
    rowCount 当前更新操作的影响行数的在上下文参数中的存放key N 用户定义
    cacheClear 缓存使用,此项将在缓存一节详细说明 N 用户定义

    5. 内部delete标签的使用

    示例5:

    <sql-service id="myService5" dsKey="ds" txRef="tx_02">
        <delete rowCount="{nCount}">
            delete from user where user_id = #{delete_user_id}
        </delete>
        <exception test="{nCount} != 1" code="-1" message="用户删除失败"/>
    </sql-service>
    

    说明

    示例5中我们定义了一个组合SQL服务myService5,其内部包含了了一个delete基本服务,当程序执行完delete服务后会将影响行数以nCount为key,放入上下文中,然后通过exception标签判断nCount的有效性,如果nCount不满足条件,则无服务将抛出服务异常,并回滚之前的操作。

    返回结果: 无

    delete节点属性和变化说明:

    属性名 用途及说明 必填 取值
    id 无意义 N 用户定义
    dsKey 同selectSet.dsKey N 用户定义
    txRef 无意义 N 用户定义
    rowCount 当前更新操作的影响行数的在上下文参数中的存放key N 用户定义
    cacheClear 缓存使用,此项将在缓存一节详细说明 N 用户定义

    6. 内部insert标签的使用

    示例6:

    <sql-service id="myService6" dsKey="ds" txRef="tx_02">
        <insert incrementKey="{user_id}" rowCount="{nCount}">
            insert into user(user_name, user_age, create_time) values('李四', 26, #{create_time|now()});
        </insert>
        <return>
            <property value="{user_id}"/>
            <property value="{nCount}"/>
        </return>
    </sql-service>
    

    说明:

    示例6中我们定义了一个组合SQL服务myService6,其内部包含了了一个insert基本服务,当程序执行完insert服务后会作2个操作:第一,将insert语句自动生成的主键以user_id为key,放入上下文中;第二将影响行数以nCount为key,放入上下文中,然后通过return标签将其返回,XML格式如下:

    返回结果

    <?xml version="1.0" encoding="UTF-8"?>
    <X>
        <L K="user_id" V="10"/>
        <I K="nCount" V="1"/>
    </X>
    

    insert节点属性和变化说明:

    属性名 用途及说明 必填 取值
    id 无意义 N 用户定义
    dsKey 同selectSet.dsKey N 用户定义
    txRef 无意义 N 用户定义
    resultType 无意义 N 用户定义
    rowCount 当前更新操作的影响行数的在上下文参数中的存放key N 用户定义
    incrementKey 当前插入操作返回插入后的主键(数据库自动生成的)的在上下文参数中的存放key。<br />关于返回主键,有以下几种情况:<br />3.插入一条记录,返回单个主键,其结果类型视主键的数据库数据类型而定。<br />2. 插入多条记录,返回多个主键数组,数组元素类型视主键的数据库数据类型而定。 N 用户定义
    cacheClear 缓存使用,此项将在缓存一节详细说明 N 用户定义

    之前我们看到的示例都是一些很简单的组合SQL服务,下面我们看一个复杂的组合SQL服务示例。

    7. 组合SQL的使用

    示例7

    <sql-service id="myService7" dsKey="ds" txRef="tx_02">
        <selectSet resultKey="{users}">
                select * from user
        </selectSet>
        
        <selectOne resultKey="{user}">
            select * from user where user_id = #{user_id}
        </selectOne>
        
        <selectVar resultKey="{userName}">
            select user_name from user where user_id = #{user_id}
        </selectVar>
        
        <update rowCount="{nCount}">
            update user set user_name = '张三' where user_id = #{user_id}
        </update>
        <exception test="{nCount} != 1" code="-1" message="用户更新失败"/>
        
        <delete rowCount="{nCount}">
            delete from user where user_id = #{delete_user_id}
        </delete>
        <exception test="{nCount} != 1" code="-1" message="用户删除失败"/>    
            
        <insert incrementKey="{user_id}" rowCount="{nCount}">
            insert into user(user_name, user_age, create_time) values('李四', 26, #{create_time|now()});
        </insert>
        
        <return>
            <property value="{users}"/>
            <property value="{user}"/>
            <property value="{userName}"/>
            <property value="{user_id}"/>
        </return>            
            
    </sql-service>
    

    返回结果:

    <?xml version="1.0" encoding="UTF-8"?>
        <X>
            <XL K="users">
                <X>
                    <L K="user_id" V="1"/>
                    <S K="user_name" V="张三"/>
                    <B K="user_age" V="18"/>
                    <A K="create_time" V="2016-10-20 21:30:58"/>
                </X>
                <X>
                    <L K="user_id" V="2"/>
                    <S K="user_name" V="张三"/>
                    <B K="user_age" V="18"/>
                    <A K="create_time" V="2016-10-20 21:31:58"/>
                </X>
                ...
            </XL>
            <X K="user">
                <L K="user_id" V="1"/>
                <S K="user_name" V="张三"/>
                <B K="user_age" V="18"/>
                <A K="create_time" V="2016-10-20 21:30:58"/>
            </X>
            <S K="userName" V="张三"/>
            <L K="user_id" V="11"/>
        </X>
    

    说明:

    示例7其实就是整合之前的示例1到示例6,在一个服务中完成6个操作,并根据需要返回结果,就如同SQL中的存储过程,Java中的函数一般,这才是组合SQL服务的优势所在,通过一些基本服务的组合,和一些辅助标签,实现复杂的业务逻辑。使其开发人员即使不懂的JAVA也可完成大部分的服务开发工作。

    8. 自定义返回结果

    在组合SQL服务中可以通过return标签来定义返回内容。return标签的使用一般有下面两种情况:

    示例8:

    <sql-service id="myService" dsKey="ds" txRef="tx_02">
        <selectSet resultKey="{users}">
            select * from user
        </selectSet>
        <return>
            <property value="{users}"/>
        </return>
    </sql-service>
    

    说明:

    示例8中return标签表示返回一个封装后的对象(默认为XCO类型),此对象中包含一个名为users的属性,值为List<XCO>

    示例9:

    <sql-service id="myService" dsKey="ds" txRef="tx_02">
        <selectVar resultKey="{userName}">
            select user_name from user where user_id = #{user_id}
        </selectVar>
        <return value="{userName}" />
    </sql-service>
    

    说明:

    示例9中return标签表示直接返回userName所代表的值,此处为userName的类型为String

    上述两个示例说明了return标签的两种使用方式,一种是返回一个封装对象,然后通过property子标签定义其内部具体属性和属性值。另一种是直接通过return标签的value属性定义返回值,在这种情况下的返回类型由value属性中的变量所代表的值的类型来决定。注意,这两种方式不能混合使用,当然如果某个服务不需要返回类型,也可以不使用return标签,但是如果使用return标签,则只能有一个。

    Schema设计图

    图片2

    return节点属性说明:

    属性名 用途及说明 必填 取值
    value 需要直接返回的变量名称, 如value="{user}" N 用户定义

    property节点属性说明:

    属性名 用途及说明 必填 取值
    name 返回对象中的属性名称,可省略,默认为value中的变量名称 N 用户定义
    value 代表属性值的变量名称 Y 用户定义

    10. log标签的使用

    日志打印标签,用于在服务执行过程中的检测和日志的输出。

    示例10:

    <sql-service>
        <log message="更新用户:开始" level="info"/>
        <update rowCount="{nCount}">...</update>
        <log message="更新用户:结束"/>
        <log message="更新班级:开始"/>
        <update rowCount="{nCount}">...</update>
        <log message="更新班级:结束"/>
    </sql-service>
    

    说明:

    上述示例中使用4个log标签,分别在update操作前后,这样开发的时候可以方便的从日志中观察到服务的执行情况。

    Schema设计图

    图片3

    log节点属性说明:

    属性名 用途及说明 必填 取值
    message 日志内容,其中可使用变量;如:<log message="学生ID: {user_id}, 班级ID: {class_id}"/> Y 用户定义
    level 日志等级默认info,可参考log4j的日志等级 N error/warn/info/debug

    11. setvar标签的使用

    用途:变量设置标签,在XML中给一个变量赋值。

    示例11:

    <sql-service>
        <setvar key="{x}" value="0"/>
        <if test="{type} == 1">
            <selectOne resultKey="{x}">....</selectOne>
        </if>
        <return>
            <property value="{x}"/>
        </return>
    </sql-service>
    

    说明:

    上述示例中先将比变量x赋值为0,然后判断条件,如果type==1,则执行selectOne操作,将执行结果重新赋值给变量x,最后返回x.

    Schema设计图

    图片4

    setvar节点属性说明:

    属性名 用途及说明 必填 取值
    key 变量名称,如:key="{x}" Y 用户定义
    value 变量值 Y 用户定义
    type 变量的数据类型,默认将会根据根据用户输入变量值自动分析其类型;比如:<br />value="0",类型为int<br />value="1.3",类型为float<br />value="true",类型为boolean<br />value="xxx",类型为String<br />value="yyyy-MM-dd HH:mm:ss",类型为dateTime<br />value="yyyy-MM-dd",类型为date<br />value="HH:mm:ss",类型为time N int<br />long<br />float<br />double<br />short<br />boolean<br />byte<br />char<br />dateTime<br />date<br />time<br />

    12. transGroup标签的使用

    transGroup的作用就是启动一个新的事务,如果transGroup中的服务执行失败将不会影响之前的事务。

    示例12:

    <sql-service id="myService" dsKey="ds" txRef="tx_02">
        <update rowCount="{nCount}">
            update user set user_name = '张三' where user_id = #{user_id}
        </update>
        <transGroup txRef="tx_03">        <!-- (1) -->
            <insert incrementKey="{user_id}" rowCount="{nCount}">
                insert into user(user_name, user_age, create_time) values('李四', 26, #{create_time|now()});
            </insert>        
        </transGroup>                    <!-- (2) -->
        <update rowCount="{nCount}">    <!-- (3) -->
            update user set user_name = '李四' where user_id = #{user_id}
        </update>        
        <return>...</return>
    </sql-service>
    

    说明:

    上述示例中服务执行到(1)的时候,根据transGroup所使用事务定义tx_03,启动一个新事物Y,并将之前的事务X挂起,开始执行其内部的insert服务,如果顺利的执行到(2)的位置,则提交事物Y,并恢复之前的X,继续执行后面的操作;一旦在此期间发生异常,则回滚事物Y,恢复之前的事物X,从(3)的位置继续执行。

    注意:transGroup所使用的事务定义的传播属性必须是requires_new或者not_supported

    Schema设计图

    图片5

    transGroup节点属性说明:

    属性名 用途及说明 必填 取值
    txRef 所引用事务定义的id Y 用户定义

    13. call标签的使用

    服务内部调用标签,就是在一个组合服务内部调用其他服务,可以是基本服务,也可以是另一个组合服务。

    示例13A:

    <selectOne id="getUserById">
        SELECT * from user WHERE user_id = #{user_id}
    </selectOne>
    
    <sql-service id="myService" dsKey="ds" txRef="tx_02">
        <update rowCount="{nCount}">
            update user set user_name = '张三' where user_id = #{user_id}
        </update>
        <call service="demo2.getUserById" resultKey="{user}"/>
        <return>
            <property value="{user}"/>
        </return>
    </sql-service>    
    

    说明:

    上述示例中在myService内部调用了getUserById服务,调用指的是像JAVA函数之间的调用一样,有入参,有返回。当执行完call标签后,会将其执行结果以user为key放入参数上下文中。细心的同学可能会有疑问,getUserById服务是需要一个user_id参数的,如何获取其值呢?其实在上述示例中myService隐示的将自己的上下文和参数传递给getUserByIdmyService的参数中是存在user_id,所以getUserById服务可以顺利取到值。

    通过下面这种方式,我们还可以显示的给getUserById服务传递参数:

    示例13B:

    <call service="demo2.getUserById" resultKey="{user}">
        <property value="{user_id}"/>
    </call>
    

    在这中方式下,调用getUserById服务的时候仅仅给其传递了user_id一个参数。

    示例13C:

    <call service="demo2.getUserById" resultKey="{user}" mode="EXTEND" exResultKey="{ex}"/>
    

    说明:

    示例13C中call标签出现了mode属性和exResultKey属性,mode属性表示的是调用的模式,exResultKey属性表示的是当调用发生异常后,将异常信息的codemessage封装成一个新的对象(默认为XCO对象),以ex为key放入参数上下文中,供后续程序使用。

    注意: 要避免循环或递归调用。

    Schema设计图

    图片6

    call节点属性说明:

    属性名 用途及说明 必填 取值
    service 被调用的服务名称。格式为:命名空间+"."+服务id Y 用户定义
    resultKey 返回结果的key N 用户定义
    mode 调用模式,默认EXTEND<br />EXTEND:被调用方将继承调用方的上下文。<br />ALONE:被调用方有独立的上下文。<br />ASYNC:异步调用,被调用方有独立的上下文。 N EXTEND/ALONE/ASYNC
    exResultKey 调用过程中发生异常后,将异常信息封装成对象codemessage所存放的key N 用户定义

    property节点属性说明:

    属性名 用途及说明 必填 取值
    name 参数名,默认为value的变量名 N 用户定义
    value 参数值 Y 用户定义

    14. exception标签的使用

    异常标签,当满足其检测条件的时候会抛出服务异常ServiceException

    示例14:

    <sql-service id="myService4" dsKey="ds" txRef="tx_02">
        <update rowCount="{nCount}">......</update>
        <exception test="{nCount} != 1" code="-1" message="用户更新失败"/>
        ......
    </sql-service>
    

    说明:

    对于exception标签的使用之前已经有过很多示例,这里我们着重介绍一些服务异常抛出后相关的处理,一般有以下几种情况:

    1. 当前上下文中运行这一个事务,对于这种情况tangyuan框架捕捉到异常后会先回滚当前事务,然后在将此异常继续上抛给调用方。对于调用方捕获到服务异常后可通过ServiceException对象的getErrorCode和getErrorMessage拿到错误码和错误描述。
    2. 当前上下文中存在挂起的事务,也就是说当前操作运行在一个独立的事务中,在这种情况下框架捕捉到异常后会先回滚当前事务,然后恢复最近挂起的服务,并继续执行。

    Schema设计图

    图片7

    exception节点属性说明:

    属性名 用途及说明 必填 取值
    test 逻辑表达式,同if标签的test属性。 Y 用户定义
    code 当抛出服务异常时所携带的错误码。 N 用户定义
    message 当抛出服务异常时所携带的错误描述。 N 用户定义

    到此,第六章节的内容就结束了,感兴趣的朋友可以关注TangYuan项目。

    相关文章

      网友评论

        本文标题:TangYuan之组合SQL服务标签

        本文链接:https://www.haomeiwen.com/subject/jmhamttx.html