精华内容
下载资源
问答
  • mybatis 动态sql和参数

    2017-07-28 10:27:44
    mybatis 动态sql 名词解析 OGNL表达式 OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对Java对象图进行...

    mybatis 动态sql

    名词解析

    OGNL表达式

    OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对Java对象图进行导航。

    OGNL表达式的基本单位是"导航链",一般导航链由如下几个部分组成:

    1. 属性名称(property) 
    2. 方法调用(method invoke) 
    3. 数组元素

    所有的OGNL表达式都基于当前对象的上下文来完成求值运算,链的前面部分的结果将作为后面求值的上下文。例如:names[0].length()。


     mybatis 的动态sql语句基于OGNL表达式的。可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:
      1. if 语句 (简单的条件判断)
      2. choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似.
      3. trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)
      4. where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误)
      5. set (主要用于更新时)
      6. foreach (在实现 mybatis in 语句查询时特别有用)
    下面分别介绍这几种处理方式

    1. mybaits if 语句处理

     
    	<sql id="Base_Column_List" >
        		NAME,	
    			NAME_QRY,	
    			SCHOOL,	
    			REMARK,	
    			DEL_FLAG,	
    			CREATE_BY,	
    			CREATE_TIME,	
    			MODIFY_BY,	
    			MODIFY_TIME,	
    			MAJOR_ID, 
    			(SELECT NAME FROM ec_info_school ot WHERE ot.school_id=SCHOOL) SCHOOL_NAME
    
      	</sql><!-- 列表 -->
    	<select id="datalistPage" parameterType="page" resultType="pd">
    		select
    			<include refid="Base_Column_List" />
    		from 
    			EC_INFO_MAJOR a
    		where 1=1
    		<if test="pd.NAME != null and pd.NAME != ''">
    			and NAME = #{pd.NAME,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.NAME_QRY != null and pd.NAME_QRY != ''">
    			and NAME_QRY = #{pd.NAME_QRY,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.SCHOOL != null and pd.SCHOOL != ''">
    			and SCHOOL = #{pd.SCHOOL,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.REMARK != null and pd.REMARK != ''">
    			and REMARK = #{pd.REMARK,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.DEL_FLAG != null and pd.DEL_FLAG != ''">
    			and DEL_FLAG = #{pd.DEL_FLAG,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.CREATE_BY != null and pd.CREATE_BY != ''">
    			and CREATE_BY = #{pd.CREATE_BY,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.CREATE_TIME != null and pd.CREATE_TIME != ''">
    			and CREATE_TIME = #{pd.CREATE_TIME,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.MODIFY_BY != null and pd.MODIFY_BY != ''">
    			and MODIFY_BY = #{pd.MODIFY_BY,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.MODIFY_TIME != null and pd.MODIFY_TIME != ''">
    			and MODIFY_TIME = #{pd.MODIFY_TIME,jdbcType=VARCHAR}
    		</if>
    		<if test="pd.SEARCH != null and pd.SEARCH != ''">
    			and (NAME LIKE CONCAT( #{pd.SEARCH,jdbcType=VARCHAR},'%' ) OR NAME LIKE  CONCAT('%',#{pd.SEARCH,jdbcType=VARCHAR},'%' ) OR NAME LIKE CONCAT('%',#{pd.SEARCH,jdbcType=VARCHAR} ) )
    		</if>
    	</select>
     

     

    解析

      如果你提供了title参数,那么就要满足title=#{title},同样如果你提供了Content和Owner的时候,它们也需要满足相应的条件,之后就是返回满足这些条件的所有Blog,这是非常有用的一个功能。

      以往我们使用其他类型框架或者直接使用JDBC的时候, 如果我们要达到同样的选择效果的时候,我们就需要拼SQL语句,这是极其麻烦的,比起来,上述的动态SQL就要简单多了。

     

    2. choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似

     
      <select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
            select * from t_blog where 1 = 1 
            <choose>
                <when test="title != null">
                    and title = #{title}
                </when>
                <when test="content != null">
                    and content = #{content}
                </when>
                <otherwise>
                    and owner = "owner1"
                </otherwise>
            </choose>
        </select>
     

      when元素表示当when中的条件满足的时候就输出其中的内容,跟JAVA中的switch效果差不多的是按照条件的顺序,当when中有条件满足的时候,就会跳出choose,即所有的when和otherwise条件中,只有一个会输出, 当所有的我很条件都不满足的时候就输出otherwise中的内容。所以上述语句的意思非常简单, 当title!=null的时候就输出and titlte = #{title},不再往下判断条件,当title为空且content!=null的时候就输出and content = #{content},当所有条件都不满足的时候就输出otherwise中的内容。

     

    3.trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)

     
       <select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
            select * from t_blog 
            <trim prefix="where" prefixOverrides="and |or">
                <if test="title != null">
                    title = #{title}
                </if>
                <if test="content != null">
                    and content = #{content}
                </if>
                <if test="owner != null">
                    or owner = #{owner}
                </if>
            </trim>
        </select>
     

     

      trim元素的主要功能是可以在自己包含的内容前加上某些前缀也可以在其后加上某些后缀, 与之对应的属性是prefix和suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是 prefixOverrides和suffixOverrides;正因为trim有这样的功能,所以我们也可以非常简单的利用trim来代替where 元素的功能

     

    4. where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or 条件

     
      <select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
            select * from t_blog 
            <where>
                <if test="title != null">
                    title = #{title}
                </if>
                <if test="content != null">
                    and content = #{content}
                </if>
                <if test="owner != null">
                    and owner = #{owner}
                </if>
            </where>
        </select>
     

     

      where元素的作用是会在写入where元素的地方输出一个where,另外一个好处是你不需要考虑where元素里面的条件输出是什么样子的,MyBatis 会智能的帮你处理,如果所有的条件都不满足那么MyBatis就会查出所有的记录,如果输出后是and 开头的,MyBatis会把第一个and忽略,当然如果是or开头的,MyBatis也会把它忽略;此外,在where元素中你不需要考虑空格的问 题,MyBatis会智能的帮你加上。像上述例子中,如果title=null, 而content != null,那么输出的整个语句会是select * from t_blog where content = #{content},而不是select * from t_blog where and content = #{content},因为MyBatis会智能的把首个and 或 or 给忽略。

     

    5.set (主要用于更新时) 

     
        <update id="dynamicSetTest" parameterType="Blog">
            update t_blog
            <set>
                <if test="title != null">
                    title = #{title},
                </if>
                <if test="content != null">
                    content = #{content},
                </if>
                <if test="owner != null">
                    owner = #{owner}
                </if>
            </set>
            where id = #{id}
        </update>
     

     

      set元素主要是用在更新操作的时候,它的主要功能和where元素其实是差不多的,主要是在包含的语句前输出一个set,然后如果包含的语句是以逗号结束的话将会把该逗号忽略,如果set包含的内容为空的话则会出错。有了set元素我们就可以动态的更新那些修改了的字段

     

    6. foreach (在实现 mybatis in 语句查询时特别有用)
      foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。

    • item表示集合中每一个元素进行迭代时的别名
    • index指定一个名字,用于表示在迭代过程中,每次迭代到位置
    • open表示该语句以什么开始
    • separator表示在每次进行迭代之间以什么符号作为分隔符
    • close表示以什么结束

      在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:

    • 如果传入的是单参数参数类型是一个List的时候,collection属性值为list
    • 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
    • 如果传入的参数是多个的 时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如 果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入 的List或array对象在自己封装的map里面的key

    6.1.单参数List的类型

     
      <select id="dynamicForeachTest" resultType="Blog">
            select * from t_blog where id in
            <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
                #{item}
            </foreach>
        </select>
     

     

    上述collection的值为list,对应的Mapper是这样的

    public List<Blog> dynamicForeachTest(List<Integer> ids); 

     

    测试代码

     
      @Test
        public void dynamicForeachTest() {
            SqlSession session = Util.getSqlSessionFactory().openSession();
            BlogMapper blogMapper = session.getMapper(BlogMapper.class);
            List<Integer> ids = new ArrayList<Integer>();
            ids.add(1);
            ids.add(3);
            ids.add(6);
            List<Blog> blogs = blogMapper.dynamicForeachTest(ids);
            for (Blog blog : blogs)
                System.out.println(blog);
            session.close();
        }
     

     

      

    6.2.数组类型的参数

     
    <select id="dynamicForeach2Test" resultType="Blog">
            select * from t_blog where id in
            <foreach collection="array" index="index" item="item" open="(" separator="," close=")">
                #{item}
            </foreach>
        </select>
     

     

    对应mapper

    public List<Blog> dynamicForeach2Test(int[] ids);  

     

     

    6.3. Map 类型的参数

     
     <select id="dynamicForeach3Test" resultType="Blog">
            select * from t_blog where title like "%"#{title}"%" and id in
            <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
                #{item}
            </foreach>
        </select>
     

     

    mapper 应该是这样的接口:

    public List<Blog> dynamicForeach3Test(Map<String, Object> params); 

     

       通过以上方法,就能完成一般的mybatis 的 动态SQL 语句.最常用的就是  if where foreach这几个,一定要重点掌握.

     

     

     

     

    MyBatis传入参数与parameterType

    Mybatis的Mapper文件中的select、insert、update、delete元素中有一个parameterType属性,用于对应的mapper接口方法接受的参数类型。

    可以接受的参数类型有基本类型和复杂类型。

    mapper接口方法一般接受一个参数,可以通过使用@Param注释将多个参数绑定到一个map做为输入参数。

    1. 简单数据类型

    mapper接口方法:

    User selectByPrimaryKey(Integer id);

    sql映射:

    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select
      <include refid="Base_Column_List" />
      from base.tb_user
      where id = #{id,jdbcType=INTEGER}
    </select>

    对于简单数据类型,sql映射语句中直接#{变量名}这种方式引用就行了,其实这里的”变量名”可以是任意的。mapper接口方法传递过来的值,至于其叫什么名字其实是不可考也没必要知道的。
    而且JAVA反射只能获取方法参数的类型,是无从得知方法参数的名字的。

    比如上面这个示例中,使用#{id}来引用只是比较直观而已,使用其他名字来引用也是一样的。所以当在if元素中test传递的参数时,就必须要用_parameter来引用这个参数了。像这样:

     
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
      select
      <include refid="Base_Column_List" />
      from tb_user
      <if test="_parameter != 0">
      where id = #{id,jdbcType=INTEGER}
      </if>
    </select>
     

    如果test测试条件中使用id就会提示错误,因为这个参数其实没有名字,只是一个值或引用而已,只能使用_parameter来引用。

    1. 对象类型

    传入JAVA复杂对象类型的话,sql映射语句中就可以直接引用对象的属性名了,这里的属性名是实实在在的真实的名字,不是随意指定的。
    mapper接口方法:

    int insert(User user);

    sql映射:

    <insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
      insert into tb_user (name, sex)
      values (#{name,jdbcType=CHAR}, #{sex,jdbcType=CHAR})
    </insert>

    虽然可以明确的引用对象的属性名了,但如果要在if元素中测试传入的user参数,仍然要使用_parameter来引用传递进来的实际参数,因为传递进来的User对象的名字是不可考的。如果测试对象的属性,则直接引用属性名字就可以了。

    测试user对象:

    <if test="_parameter != null">

    测试user对象的属性:

    <if test="name != null">
    1. map类型

    传入map类型,直接通过#{keyname}就可以引用到键对应的值。使用@param注释的多个参数值也会组装成一个map数据结构,和直接传递map进来没有区别。

    mapper接口:

    int updateByExample(@Param("user") User user, @Param("example") UserExample example);

    sql映射:

     
    <update id="updateByExample" parameterType="map" >
      update tb_user
      set id = #{user.id,jdbcType=INTEGER},
      ...
      <if test="_parameter != null" >
        <include refid="Update_By_Example_Where_Clause" />
      </if>
    </update>
     

    注意这里测试传递进来的map是否为空,仍然使用_parameter

    1. 集合类型

    You can pass a List instance or an Array to MyBatis as a parameter object. When you do, MyBatis will automatically wrap it in a Map, and key it by name. List instances will be keyed to the name “list” and array instances will be keyed to the name “array”.

    可以传递一个List或Array类型的对象作为参数,MyBatis会自动的将List或Array对象包装到一个Map对象中,List类型对象会使用list作为键名,而Array对象会用array作为键名。

    集合类型通常用于构造IN条件,sql映射文件中使用foreach元素来遍历List或Array元素。

    mapper接口:

    User selectUserInList(List<Interger> idlist);
     

    sql动态语句映射:

     
    <select id="selectUserInList" resultType="User">
      SELECT *
      FROM USER
      WHERE ID in
      <foreach item="item" index="index" collection="list"
          open="(" separator="," close=")">
            #{item}
      </foreach>
    </select>
    
    	<delete id="deleteAll" parameterType="String">
    		delete from EC_INFO_MAJOR
    		where 
    			MAJOR_ID in
    		<foreach item="item" index="index" collection="array" open="(" separator="," close=")">
    			#{item}
    		</foreach>
    	</delete>
     
    1. 对象类型中的集合属性

    对于单独传递的List或Array,在SQL映射文件中映射时,只能通过list或array来引用。但是如果对象类型有属性的类型为List或Array,则在sql映射文件的foreach元素中,可以直接使用属性名字来引用。
    mapper接口:

    List<User> selectByExample(UserExample example);

    sql映射文件:

    <where >
      <foreach collection="oredCriteria" item="criteria" separator="or" >
        <if test="criteria.valid" >
    </where>

    在这里,UserExample有一个属性叫oredCriteria,其类型为List,所以在foreach元素里直接用属性名oredCriteria引用这个List即可。

    item=”criteria”表示使用criteria这个名字引用每一个集合中的每一个List或Array元素

    展开全文
  • sql 动态写入数据库字段 最有效的数据库优化之一是批处理写入。 批处理写入受大多数现代数据库和JDBC标准的一部分支持,并且受... 批处理写入有两种形式,动态和参数化的。 参数化是最常见的方法,通常可以带来...

    sql 动态写入数据库字段

    最有效的数据库优化之一是批处理写入。 批处理写入受大多数现代数据库和JDBC标准的一部分支持,并且受大多数JPA提供程序支持。

    普通数据库访问包括在单独的数据库/网络访问中将每个DML(插入,更新,删除)语句发送到数据库。 每个数据库访问都有一定的开销,并且数据库必须独立处理每个语句。 批处理写入有两种形式,动态的和参数化的。 参数化是最常见的方法,通常可以带来最大的好处,因为动态可能存在解析问题。

    要了解批处理编写,您必须首先了解参数化SQL。 SQL执行由两部分组成,即解析和执行。 解析包括将字符串SQL表示形式转换为数据库表示形式。 执行包括在数据库上执行已解析SQL。 数据库和JDBC支持绑定参数,因此SQL(数据)的参数不必嵌入SQL中。 这避免了将数据转换为文本的成本,并允许重复执行同一SQL语句,并执行多次。 这允许单个解析和多个执行,也称为“参数化SQL”。 大多数JDBC DataSource实现和JPA提供程序都支持参数化SQL和语句缓存,这可以有效避免在运行的应用程序中进行解析。

    动态SQL示例

    INSERT INTO EMPLOYEE (ID, NAME) VALUES (34567, "Bob Smith")

    参数化SQL示例

    INSERT INTO EMPLOYEE (ID, NAME) VALUES (?, ?)

    参数化批处理编写涉及执行单个DML语句,但是具有用于多个同质语句的一组绑定参数,而不是用于单个语句的绑定参数。 这有效地允许数据库和网络将大批同质的插入,更新或删除作为单个操作而不是n个操作来处​​理。 数据库只需要执行最少的工作,因为只有一条语句,因此最多只有一个解析。 它也与语句缓存兼容,因此根本不需要进行语句解析。 限制是所有语句SQL必须相同。 因此,说插入1,000个Orders确实非常有用,因为每个Order的插入SQL是相同的,只有bind参数不同。 但这对插入1个订单或插入1个订单,1个OrderLine和1个客户没有帮助。 同样,所有语句必须是同一数据库事务的一部分。

    动态批处理编写包括将一堆异构的动态SQL语句链接到一个块中,然后通过单个数据库/网络访问将整个块发送到数据库。 这样做的好处是只有一个网络访问权限,因此,如果数据库是远程的或通过慢速的网络访问,则可能会有很大的不同。 缺点是不允许参数绑定,并且数据库必须在接收到此庞大SQL块时对其进行解析。 在某些情况下,解析成本可能超过网络收益。 另外,动态SQL与语句缓存不兼容,因为每个SQL都不相同。

    JDBC通过其Statement和PrepareStatement批处理API(从JDBC 2.0开始,很早以前就是JDK 1.2)标准化了批处理写入。 JDBC批处理API需要不同的JDBC代码,因此,如果您使用的是原始JDBC,则需要重写代码以在批处理和非批处理API之间切换。 现在,大多数JDBC驱动程序都支持这些API,但实际上并没有将DML批量发送给数据库,它们只是模拟API。 那么,如何知道您是否真的开始批量编写? 唯一真正的方法是对其进行测试,并衡量性能差异。

    JPA规范没有标准化批写配置,但是大多数JPA提供程序都支持它。 通常,通过持久性单元属性在JPA中启用批处理写入,因此打开或关闭它是一个简单的配置问题,并且不需要更改编码。 一些JPA提供程序在使用开放式锁定时可能不支持批处理写入,并且可能不对SQL进行重新排序以使其能够进行批处理,因此即使启用了批处理写入,您仍可能无法进行批处理写入。 始终在打开和关闭批处理写入的情况下测试您的应用程序,并测量差异以确保其实际运行。

    EclipseLink支持参数化和动态批处理编写(自EclipseLink 1.0起)。 在EclipseLink中,通过"eclipselink.jdbc.batch-writing"持久性单元属性启用了批处理写入。 EclipseLink提供了三个选项: "JDBC""Buffered""Oracle-JDBC" 应始终使用"JDBC"选项。

    "Buffered"用于不支持批量写入的JDBC驱动程序,并将动态SQL语句链接到单个块中。 "Buffered"不支持参数化SQL,因此不建议使用。

    "Oracle-JDBC"使用早于JDBC标准API的Oracle数据库JDBC API,现在已过时。 在EclipseLink 2.5之前,此选项允许在使用开放式锁定时进行批处理写入,但是现在常规的"JDBC"选项支持开放式锁定。

    EclipseLink 2.5支持在所有(兼容)数据库平台上进行乐观锁定的批处理写入,而以前仅在选定的数据库平台上才支持。 EclipseLink 2.5还提供了一个"eclipselink.jdbc.batch-writing"查询提示,以禁止无法写入的本机查询(例如DDL或某些数据库平台上的存储过程)的批量写入。

    EclipseLink通过"eclipselink.jdbc.bind-parameters""eclipselink.jdbc.cache-statements"持久单元属性来支持参数化SQL。 但是,通常不需要设置这些参数,因为参数绑定是默认设置,因此您只需将属性设置为禁用绑定即可。 默认情况下,语句缓存未启用,如果使用EclipseLink的连接池,则仅与EclipseLink相关;如果使用的是JDBC或Java EE DataSource,则必须在DataSource配置中配置语句缓存。

    在EclipseLink中启用批量写入时,默认情况下它是参数化的批量写入。 要启用动态批处理写入,必须禁用参数绑定。 这与启用缓冲批写入相同。

    支持批处理写入并不是很难,大多数JPA提供程序都支持这一点,对SQL进行排序以使其可以被批处理是困难的部分。 在提交或刷新操作期间,EclipseLink会自动按表对SQL进行分组,以确保可以批处理同类SQL语句(同时仍保持引用完整性约束并避免死锁)。 大多数JPA提供程序都不这样做,因此,即使它们支持批处理写入,SQL在很多时候也无法从批处理中受益。

    要在EclipseLink中启用批处理写入,请将以下内容添加到持久性单元属性;

    "eclipselink.jdbc.batch-writing"="JDBC"

    您还可以使用"eclipselink.jdbc.batch-writing.size"持久性单元属性来配置批处理大小。 默认大小为100。

    "eclipselink.jdbc.batch-writing.size"="1000"

    批处理非常依赖数据库,并且依赖JDBC驱动程序。 因此,我对与哪些数据库,它使用的驱动程序以及好处有兴趣。 我进行了两次测试,一个进行了50次插入操作,一个进行了100次更新操作(使用乐观锁定)。 我尝试了所有批处理写入选项,以及不使用任何批处理。

    请注意,这不是数据库基准,我不是在相互比较数据库,而只是对自己进行比较

    每个数据库都在不同的硬件上运行,有些是本地的,有些是跨网络的,因此不要将一个数据库与另一个数据库进行比较。 感兴趣的数据是使批写入相对于不使用批写入所带来的百分比收益。 对于插入测试,我还测量了使用参数化SQL与动态SQL以及不使用语句缓存的参数化SQL之间的差异。 结果是在10秒内处理的事务数(运行5次,并且平均),因此,较大的数目是更好的结果。

    驱动程序:MySQL-AB JDBC驱动程序版本:mysql-connector-java-5.1.22

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 483 0%
    动态SQL,无批次 499 3%
    参数化SQL,无语句缓存 478 -1%
    动态SQL,批处理 499 3%
    参数化SQL,批处理 509 5%

    更新测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL 245 0%
    动态SQL,批处理 244 0%
    参数化SQL,批处理 248 1%

    因此,结果似乎表明批处理写入没有任何影响(5%在方差内)。 这真正的意思是,MySQL JDBC驱动程序实际上并不使用批处理,它只是模拟JDBC批处理API,并在其下逐个执行语句。

    尽管MySQL确实具有批处理支持,但它只需要不同SQL。 MySQL JDBC驱动程序确实支持此功能,但是需要设置rewriteBatchedStatements=true JDBC连接属性。 可以通过修改您的连接URL轻松地进行设置,例如;

    jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true

    MySQL:rewriteBatchedStatements = true

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 504 0%
    动态SQL,无批次 508 0%
    参数化SQL,无语句缓存 483 -4%
    动态SQL,批处理 1292 156%
    参数化SQL,批处理 2181 332%

    更新测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL 250 0%
    动态SQL,批处理 669 167%
    参数化SQL,批处理 699 179%

    因此,如果正确配置(看来JDBC驱动程序默认情况下不执行此操作,我不知道),那么批处理写入确实会在MySQL中产生很大的不同。 参数化的批处理写入效果最佳,插入速度快332%,更新速度快179%。 动态批处理写入效果也很好。 有趣的是,MySQL上的动态SQL和参数化SQL之间似乎没有什么区别(我猜想MySQL解析的速度确实更快,或者对准备好的语句几乎没有优化)。

    PostgreSQL 8.4 JDBC4

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 479 0%
    动态SQL,无批次 418 -12%
    参数化SQL,无语句缓存 428 -10%
    动态SQL,缓冲 1127 135%
    动态SQL,批处理 1127 135%
    参数化SQL,批处理 2037 325%

    更新测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL 233 0%
    动态SQL,批处理 395 69%
    参数化SQL,批处理 707 203%

    结果表明,批处理编写在PostgreSQL上有很大的不同。 参数化批处理写入性能最佳,插入速度快325%,更新速度快203%。 动态批处理写入效果也很好。 对于PostgreSQL,我还评估了EclipseLink的缓冲批处理写入的性能,该性能与动态JDBC批处理写入的性能相同,因此我假设驱动程序在做相同的事情。 参数化SQL优于动态SQL约10%,但是不带语句缓存的参数化SQL与动态SQL相似。

    Oracle JDBC驱动程序版本:11.2.0.2.0

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 548 0%
    动态SQL,无批次 494 -9%
    参数化SQL,无语句缓存 452 -17%
    动态SQL,缓冲 383 -30%
    动态SQL,批处理 489 -10%
    参数化SQL,批处理 3308 503%

    更新测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL 282 0%
    动态SQL,批处理 258 -8%
    参数化SQL,批处理 1672 492%

    结果表明,参数化批处理写入对Oracle产生了很大的影响,插入速度快503%,更新速度快492%。 动态批处理写入没有任何好处,这是因为Oracle的JDBC驱动程序仅模拟动态批处理并逐个执行语句,因此它具有与动态SQL相同的性能。 缓冲批写入实际上比根本不批处理具有更差的性能。 这是因为巨大的动态SQL块的解析成本,这在不同的配置中可能会有所不同,如果数据库是远程的或跨慢速的网络,则我会看到这样做的好处。

    带有语句缓存的参数化SQL比动态SQL提供约10%的收益,并指出要从参数化中受益,您需要使用语句缓存,否则性能可能会比动态SQL差。 粗略地讲,参数化SQL还有其他好处,因为它从服务器中删除了CPU处理,这在单线程情况下可能无济于事,但在数据库是瓶颈的多线程情况下,可能会产生很大的不同。

    (本地)

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 3027 0%
    动态SQL,无批次 24 -99%
    参数化SQL,无语句缓存 50 -98%
    动态SQL,批处理 24 -99%
    参数化SQL,批处理 3252 7%

    更新测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL 1437 0%
    动态SQL,批处理 6 -99%
    参数化SQL,批处理 2172 51%

    结果表明,参数化批处理写入对Derby有所不同,插入速度快7%,更新速度快51%。 由于我的数据库是本地数据库,因此结果差异不如其他数据库那么大。 对于网络数据库,这将是一个更大的差异,但这确实表明,即使对于本地数据库,批处理写入也可以带来好处,因此,这不仅仅是网络优化。 Derby真正有趣的结果是动态和非缓存语句的可怕性能。 这表明Derby具有巨大的解析成本,因此,如果您使用的是Derby,则将带参数SQL与语句缓存一起使用非常重要。

    用于JDBC和SQLJ的IBM数据服务器驱动程序版本:4.0.100

    结果基本上与Oracle类似,因为参数化的批处理编写具有很大的性能优势。 动态批处理写入的性能较差,因此无法使用参数化SQL进行批处理,而动态SQL和未使用语句缓存的参数化SQL会导致性能下降。

    Microsoft SQL Server JDBC驱动程序2.0版本:2.0.1803.100

    结果类似于PostgreSQL,显示参数化和动态批处理编写均提供了显着的好处。 参数化批处理编写性能最佳,参数化SQL优于动态SQL,并且没有语句缓存。

    **更新**

    有人要求我也测试H2和HSQL,所以这里是结果。

    (本地)

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 4757 0%
    动态SQL,无批次 3210 -32%
    参数化SQL,无语句缓存 4757 0%
    动态SQL,缓冲 1935年 -59%
    动态SQL,批处理 3293 -30%
    参数化SQL,批处理 5753 20%

    结果表明,通过参数化批处理写入,H2的执行速度提高了20%。 H2是一个内存数据库(由持久日志文件支持),因此预期不会因为没有网络而受益。 动态批处理编写和动态SQL执行的参数化SQL更差。 有趣的是,将参数缓存与参数化SQL一起使用不会造成任何影响。 我的假设是H2始终在其连接中缓存准备好的语句,因此用户不需要自己进行语句缓存。

    (本地)

    插入测试

    选项 平均结果 与未批次的差异百分比
    参数化SQL,无批处理 7319 0%
    动态SQL,无批次 5054 -30%
    参数化SQL,无语句缓存 6776 -7%
    动态SQL,批处理 5500 -24%
    参数化SQL,批处理 9176 25%

    结果表明,通过参数化批处理编写,HSQL的执行速度提高了25%。 HSQL是一个内存数据库(由持久日志文件支持),因此期望它受益于不涉及任何网络的情况。 动态批处理编写和动态SQL执行的参数化SQL更差。


    翻译自: https://www.javacodegeeks.com/2013/09/batch-writing-and-dynamic-vs-parametrized-sql-how-well-does-your-database-perform.html

    sql 动态写入数据库字段

    展开全文
  • ibatis动态获取执行SQL和参数

    千次阅读 2016-05-19 17:14:28
    动态SQL的最好做法是在日志中记录一下执行的SQL,如下为在执行过程中获取SQL和参数的方案 /** * 查询总条数 */ public int queryCountByScriptSQL(Map, String> parmMap) throws LasBusinessException { try {

    动态SQL的最好做法是在日志中记录一下执行的SQL,如下为在执行过程中获取SQL和参数的方案

        /**
         * 查询总条数
         */
        public int queryCountByScriptSQL(Map<String, String> parmMap)
                throws LasBusinessException {
            try {
                // debug("queryCountByScriptSQL in");
                List res = getSqlMapClientTemplate().queryForList(
                        "valAdded.queryCountByScriptSQL", parmMap);
                SqlMapExecutorDelegate delegate = ((ExtendedSqlMapClient) (getSqlMapClientTemplate()
                        .getSqlMapClient())).getDelegate();
                MappedStatement ms = delegate
                        .getMappedStatement("valAdded.queryCountByScriptSQL");
                Sql sql = ms.getSql();
                RequestScope requestScope = new RequestScope();
                requestScope.setStatement(ms);
                String sqlStr = sql.getSql(requestScope, parmMap);
                // ParameterMap p = sql.getParameterMap(requestScope, parmMap);
                Object[] sqlParam = sql.getParameterMap(requestScope, parmMap)
                        .getParameterObjectValues(requestScope, parmMap);
                System.out.println("----------->" + sqlStr);
                for (int i = 0; i < sqlParam.length; i++) {
                    System.out.println("----参数[" + (i + 1) + "]------->" + sqlParam[i]);
                }
                // System.out.println("----------->"+p.toString());
                return Integer.parseInt(res.get(0).toString());
            } catch (DataAccessException e) {
                if (e.getErrorCode().equals(DB_LOCK_NOWAIT_CODE)) {
                    throw new LasBusinessException(DB_LOCK_NOWAIT_MESSAGE, e);
                } else {
                    throw new LasAppException("ElisLas系统异常", e);
                }
            } catch (Exception e) {
                throw new LasAppException("ElisLas系统异常", e);
            }
        }
    展开全文
  • 1.可以将要传入的几个参数封装成一个实体类,然后将实体类作为一个参数传入到相应的方法中,这时候就需要这sqlMapper.xml文件中对传入的字段利用<if test="">标签进行判断 但是要主要where那点的条件的写法...

    1.可以将要传入的几个参数封装成一个实体类,然后将实体类作为一个参数传入到相应的方法中,这时候就需要这sqlMapper.xml文件中对传入的字段利用<if test="">标签进行判断

     但是要主要where那点的条件的写法where 1=1;用一个横有条件的语句;

    2.可以不要封装这几个参数,利用可变参数个数的方法将这些参数传入到相应的方法中,但是要主要三点:

      A.只能出现在参数列表的最后; 

      B....位于变量类型和变量名之间,前后有无空格都可以;

      C.调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中一数组的形式访问可变参数。

    以上是对动态传入参数个数的方法简介,如需详解,请给我留言

    转载于:https://www.cnblogs.com/yj716716yj/p/5488566.html

    展开全文
  • 动态sql和分页

    2020-11-27 11:29:10
    动态sql和分页mybatis动态sql模糊查询(3种方式)查询返回结果集 mybatis动态sql 1.1 if 1.2 trim 1.3 foreach 遍历集合,批量查询、通常用于in关键字 1.4 其他 choose/set/where 模糊查询(3种方式) 注: 1) ...
  • 当需要根据外部输入的参数来决定要执行的SQL语句时,常常需要动态来构造SQL查询语句,个人觉得用得比较多的地方就是分页存储过程执行... 在SQL Server中有两种方式来执行动态SQL语句,分别是execsp_executes...
  • 跟踪ibatis 3 代码,找到获取运行期的动态sql和参数 [color=red][b]在其它框架的dao实现,如hibernate或jdbc,可以把sql(hql)集中交给ibatis处理。基于动态sql,使得你的sql(hql)不再在代码中使用String拼接,且...
  • 使用MyBatis执行动态sql查询,传入参数报错:Parameter index out of range (2 > number of parameters, which is 1) SQL语句: SELECT id,name,birth,phone from emp <if test="gender !=null">where ...
  • 当需要根据外部输入的参数来决定要执行的SQL语句时,常常需要动态来构造SQL查询语句,个人觉得用得比较多的地方就是分页存储过程...在SQL Server中有两种方式来执行动态SQL语句,分别是execsp_executesql。sp_exe...
  • springboot mybatis整合: mapper定义的是数据库的操作方法: @Mapper public interface UserMapper {} 单参数的处理: @Select("select * from t_user") @Results({ @Result(property = "...
  • 本文转自:http://www.cnblogs.com/hnsdwhl/archive/2011/07/23/2114730.html当需要根据外部输入的参数来决定要执行的SQL语句时,常常需要动态来构造SQL查询语句,个人觉得用得比较多的地方就是分页存储过程执行...
  • mybatis动态sql中的两个内置参数(_parameter_databaseId) <!--mybatis动态sql的两个内置参数 不只是方法传递过来的参数可以被用来判断,取值 mybatis默认还有两个内置参数 _parameter:代表整个参数 ...
  • mybatis动态sql和分页

    2020-10-08 14:42:24
    目录1.mybatis动态sql2.模糊查询(3种方式)3.查询返回结果集4.分页查询 1.mybatis动态sql 1.1 if 1.2 trim 1.3 foreach(遍历集合,批量查询、通常用于in关键字) 1.4 choose/set/where 2.模糊查询(3种方式) 2.1 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,602
精华内容 1,040
关键字:

动态sql和参数