resultMap包含的元素:

<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识" type="映射的pojo对象">
  <id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
  <result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
  <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
    <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/>
    <result  column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
  </association>
  <!-- 集合中的property须为oftype定义的pojo对象的属性-->
  <collection property="pojo的集合属性" ofType="集合中的pojo对象">
    <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
    <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />  
  </collection>
</resultMap>

如果collection标签是使用嵌套查询,格式如下:

<collection column="传递给嵌套查询语句的字段参数" property="pojo对象中集合属性" ofType="集合属性中的pojo对象" select="嵌套的查询语句" > 
 </collection>

 注意:<collection>标签中的column:要传递给select查询语句的参数,如果传递多个参数,格式为column= ” {参数名1=表字段1,参数名2=表字段2} ;

mybatis的selectKey作用:

SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题,他可以很随意的设置生成主键的方式。

 使用mybatis的selectKey就可以得到sequence的值,同时也会将值返回。不过对于不同的数据库有不同的操作方式。

属性 描述
keyProperty selectKey 语句结果应该被设置的目标属性。
resultType 结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。
order 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用。
statementType 和前面的相 同,MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 语句的映射类型,分别代表 PreparedStatement 和CallableStatement 类型。

SelectKey需要注意order属性,像MySQL一类支持自动增长类型的数据库中,order需要设置为after才会取到正确的值。

上面xml的传入参数是map,selectKey会将结果放到入参数map中。用POJO的情况一样,但是有一点需要注意的是,keyProperty对应的字段在POJO中必须有相应的setter方法,setter的参数类型还要一致,否则会报错。

  对于oracle: 
      <insert id="insertUser" parameterClass="XXX.User"> 
          <selectKey resultClass="long" keyProperty="id"order="BEFORE"> 
              select SEQ_USER_ID.nextval as id from dual 
          </selectKey> 
           insert into user  (id,name,password) 
          values (#{id},#{name},#{password}) 
      </insert> 
       这句话会在插入user之前执行(order="BEFORE"),该句话执行完之后,会生成一个ID,传进来的参数User对象里的id字段就会被赋值成sequence的值。 

     对于mysql 
     <insert id="insertUser" parameterClass="XXX.User"> 
          insert into user (name,password) 
         values (#{id},#{name},#{password}) 
          <selectKey resultClass="long" keyProperty="id" order="after">  
             SELECT LAST_INSERT_ID() AS ID  
        </selectKey>  
      </insert> 
       将selectKey放在insert之后,通过LAST_INSERT_ID() 获得刚插入的自动增长的id的值。插入之后获得ID赋值到传进来的对象中(对象中必须有相应的属性)。

在mybatis 配置文件中增加对序列的取值赋值到ID上 (resultType="java.lang.Integer" 是id的类型 在插入时实现递增)

<insert id="insert" parameterType="com.zpark.entity.UserEntity">
       <selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="id">
           SELECT 序列名 FROM DUAL
       </selectKey>
   INSERT INTO User(
   id,userName,password)
   VALUES
   ( #{id,jdbcType=DECIMAL},#{userName,jdbcType=VARCHAR},#{password,jdbcType=VARCHAR})
</insert>

mybatis插入Oracle数据库中日期型数据

mybatis 在xml文件中获取当前时间的sql
在Service等地方获取当前时间:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 注意大写HH是24小时制                                                                                                             
 //小写hh是12小时制
df.format(new Date()) ;//当前时间


 1     /**
 2      * 新增用户
 3      *
 4      * @param user
 5      * @return
 6      */
 7     @Override
 8     public boolean insertUser(User user) throws ParseException {
 9         //将日期格式化
10         try {
11             SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
12             Date date = formatter.parse(user.getBirth().trim() + ":.803+08:00");
13             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
14             String sDate = sdf.format(date);
15 
16             user.setBirth(sDate);
17             System.out.println(sDate);
18         } catch (Exception e) {
19         }
20 
21         return iRegisterMapper.insertUser(user) > 0;
22     }

修改完毕后调用mapper文件的插入方法

1 <insert id="insertUser" parameterType="User">
2        insert into tb_user(id,uname,pwd,sex,birth,nickname,email,regtime)
3        values(Sequence_User_Id.NEXTVAL,#{uname},#{pwd},#{sex},to_date('${birth}','yyyy-mm-dd hh:mi:ss'),#{nickname},#{email},to_date('${birth}','yyyy-mm-dd hh:mi:ss'))
4     </insert>

mybatis —— 动态sql之if条件判断各种使用方式

<?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">
<!--namespace的值=dao层接口的全路径-->
<mapper namespace="com.freesky.dao.TccOrderHeadBackupDao">
    <resultMap id="BaseResultMap" type="TccOrderHeadBackup">

        <result property="VId" column="V_ID" />
        <result property="VOrderid" column="V_ORDERID" />
        <result property="VSequence" column="V_SEQUENCE" />
        <result property="VStatusname" column="V_STATUSNAME" />
        <result property="VCustomerid" column="V_CUSTOMERID" />
        <result property="VCustomername" column="V_CUSTOMERNAME" />
        <result property="DOrdertime" column="D_ORDERTIME" />
        <result property="VCreatorid" column="V_CREATORID" />
        <result property="VCreatorname" column="V_CREATORNAME" />
        <result property="VOrdertypename" column="V_ORDERTYPENAME" />
        <result property="VChannelname" column="V_CHANNELNAME" />
        <result property="VCreatordepartmentid" column="V_CREATORDEPARTMENTID" />
        <result property="VCreatordepartmentname" column="V_CREATORDEPARTMENTNAME" />
        <result property="VOrdersubtypename" column="V_ORDERSUBTYPENAME" />
        <result property="VLocation" column="V_LOCATION" />
        <result property="NAmount" column="N_AMOUNT" />
        <result property="DCreatortime" column="D_CREATORTIME" />
        <result property="NRecompenseamount" column="N_RECOMPENSEAMOUNT" />
        <result property="NCardissuingfeeamount" column="N_CARDISSUINGFEEAMOUNT" />
        <result property="NAramount" column="N_ARAMOUNT" />
        <result property="NQuantity" column="N_QUANTITY" />
        <result property="VRefundmentorderid" column="V_REFUNDMENTORDERID" />
        <result property="DSendtime" column="D_SENDTIME" />
        <result property="DInserttime" column="D_INSERTTIME" />

    </resultMap>


    <!--查询所有数据 id=接口中的方法名-->
    <select id="selectList" resultMap="BaseResultMap">
        select * from cc.tcc_order_head_backup
    </select>




    <insert id="addResource2" parameterType="TccOrderHeadBackup">
<!--作为唯一标识-->
        <selectKey resultType="String" keyProperty="VId" order="BEFORE">
            select sys_guid() from dual
        </selectKey>

        insert into cc.tcc_order_head_backup
        (V_ID,V_ORDERID,V_SEQUENCE,V_STATUSNAME,V_CUSTOMERID,V_CUSTOMERNAME,D_ORDERTIME,V_CREATORID,V_CREATORNAME,V_ORDERTYPENAME,V_CHANNELNAME,
         V_CREATORDEPARTMENTID,V_CREATORDEPARTMENTNAME,V_ORDERSUBTYPENAME,V_LOCATION,N_AMOUNT,D_CREATORTIME,
         N_RECOMPENSEAMOUNT,N_CARDISSUINGFEEAMOUNT,N_ARAMOUNT,N_QUANTITY,V_REFUNDMENTORDERID,D_SENDTIME,D_INSERTTIME)
        values
        ( <if test="VId!=null" >#{VId},</if>
          <if test="VOrderid!=null">#{VOrderid},</if>
        <if test="VSequence!=null">#{VSequence},</if>
        <if test="VStatusname!=null">#{VStatusname},</if>
        <if test="VCustomerid!=null">#{VCustomerid},</if>
        <if test="VCustomername!=null">#{VCustomername},</if>
        <if test="DOrdertime!=null">#{DOrdertime},</if>
        <if test="VCreatorid!=null">#{VCreatorid},</if>
        <if test="VCreatorname!=null">#{VCreatorname},</if>
        <if test="VOrdertypename!=null">#{VOrdertypename},</if>
        <if test="VChannelname!=null">#{VChannelname},</if>
        <if test="VCreatordepartmentid!=null">#{VCreatordepartmentid},</if>
        <if test="VCreatordepartmentname!=null">#{VCreatordepartmentname},</if>
        <if test="VOrdersubtypename!=null">#{VOrdersubtypename},</if>
        <if test="VLocation!=null">#{VLocation},</if>
        <if test="NAmount!=null">#{NAmount},</if>
        <if test="DCreatortime!=null">#{DCreatortime},</if>
        <if test="NRecompenseamount!=null">#{NRecompenseamount},</if>
        <if test="NCardissuingfeeamount!=null">#{NCardissuingfeeamount},</if>
        <if test="NAramount!=null">#{NAramount},</if>
        <if test="NQuantity!=null">#{NQuantity},</if>
        <if test="VRefundmentorderid!=null">#{VRefundmentorderid},</if>
        <if test="DSendtime!=null">#{DSendtime},</if>
        <if test="DInserttime!=null">#{DInserttime}</if>)
    </insert>
</mapper>

mybatis的if判断语句其实跟el表达式的if条件判断有些类似。

例如: <if test="id != null"> </if>

1 如果参数为数字类型的时候没有特俗需求的情况只需要判断是否为null即可。

例如:<if test="id != null"></if>

 如果有特俗需求,例如判断是否大于某个数的时候才行。只需要加上对应的条件判断即可

例如:<if test='id != null and id > 28'></if>

 mybatis对于这种大于小于等等还有另一种形式。

例如:<if test='id != null and id gt 28'></if>

对应关系:

---------------------------------------

    gt            对应             >

    gte         对应              >=

    lt             对应              <(会报错  相关联的 "test" 属性值不能包含 '<' 字符)

    lte          对应               <=(会报错  相关联的 "test" 属性值不能包含 '<' 字符)

---------------------------------------

2 如果为字符串类型

2.1 如果不需要过滤空串的情况 仅仅判断null即可

例如:<if test="username != null"></if>

2.2 如果需要过滤空串,添加空串判断即可  不支持 &&   所以这里用 and  or  || 来做逻辑与或的判断 

例如:<if test="username != null and '' != username"></if> 或者 <if test="username != null and ''  neq username"></if>

2.3 如果判断字符串是否已某个特俗字符开头,结尾等。直接调用String的对应方法即可

例如:<if test="username != null and username.indexOf('ji') == 0"> </if> <!-- 是否以什么开头 -->
    <if test="username != null and username.indexOf('ji') >= 0"> </if> <!-- 是否包含某字符 -->
    <if test="username != null and username.lastIndexOf('ji') > 0"></if>  <!-- 是否以什么结尾 -->

2.4 是否是某个特定字符串,某些业务有此需要。

例如:<if test="username != null and 'hello' == username"></if> 或者<if test="username != null and 'hello' eq username"></if>

注意:

<if test="username != null and 'hello' == username"></if>这种形式的写法在参数类型是字符串的时候是没有问题的,

但是参数类型为非字符串类型的时候就需要写成 <if test="username != null and 'hello'.toString() == username.toString()"></if>

仅仅写成<if test="username != null and 'hello'.toString() == username"></if>也会有很大可能会挂。

也许你会说非字符串的为什么要写成这样。这就要看特俗需要了。

例如:某一个sql片段是公用的,

<if test="username != null"></if>
<if test="password != null"></if>

该片段更新条件也用,但是当你需要将某一个字段更新成null的时候怎么办。

这个时候就可以通过传入一个特定的字符串来弄。当传入的字符串为特定字符串的时候就更新该字符串为null。

<if test="username != null and 'hello'.toString() == username.toString()">xxx=null</if>

当然这样子貌似date型会挂。

通过 2.2 也可以看出mybatis对于字符串的相等不相等的判断也是有对应的特俗操作符的。

-------------------------------------------------------

eq                  对应                ==

neq               对应                 !=

------------------------------------------------------

当然还可以看出来if的条件判断test是支持对象自身方法调用的,即使是自己写的方法,可以自己尝试。当然下面会有例子。

例如:里面可以用‘xxxx’.equals(xxxx) 字符串的比较两个字符串方法

    xxxx.indexOf('ss') 判断字符串里面是否包含某个字符等等  

 3 判断list是否为空

上面说过,if条件判断可以直接调用对象自身的方法进行逻辑判断,所以list判空。可以调用.size()>0或者.isEmpty()

例如:<if test="userList != null and userList.isEmpty()"></if> , <if test="userList != null and userList.size()>0"></if>

4 map参数同同理  取值的话 map.key(map中的key名字)即可

Mybitis参数类型:

首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。

#{property,javaType=int,jdbcType=NUMERIC} 

像 MyBatis 的剩余部分一样,javaType 通常可以从参数对象中来去确定,前提是只要对象不是一个 HashMap。那么 javaType 应该被确定来保证使用正确类型处理器。

NOTE 如果 null 被当作值来传递,对于所有可能为空的列,需要设置参数的jdbcType。你可以自己通过阅读预处理语句的 setNull() 方法的 JavaDocs 文档来研究这种情况。

为了以后定制类型处理方式,你也可以指定一个特殊的类型处理器类(或别名),比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

尽管看起来配置变得越来越繁琐,但实际上是很少去设置它们。

对于数值类型,还有一个小数保留位数的设置,来确定小数点后保留的位数。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最后,mode 属性允许你指定 IN,OUT 或 INOUT 参数。

如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像你在获取输出参数时所期望的那样。如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 来映射结果集到参数类型。要注意这里的 javaType 属性是可选的,如果左边的空白是 jdbcType 的 CURSOR 类型,它会自动地被设置为结果集。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高级的数据类型,比如结构体,但是当注册 out 参数时你必须告诉它语句类型名称。比如(再次提示,在实际中要像这样不能换行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

尽管所有这些强大的选项很多时候你只简单指定属性名,其他的事情 MyBatis 会自己去推断,最多你需要为可能为空的列名指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

字符串替换

默认情况下,使用#{}格式的语法会导致 MyBatis 创建预处理语句属性并安全地设置值(比如?)。这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:

ORDER BY ${columnName}

这里 MyBatis 不会修改或转义字符串。

NOTE 以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

3.1 #{}与${}

注意以下两个符号的使用:

#{}(ibatis为:##):MyBatis创建预处理语句属性从而设置安全的值(比如?)。常用作查询条件的值,例如:where name=#{value}。 
该参数可以指定一个确切的数据类型,例如: #{property,javaType=int,jdbcType=NUMERIC}. 
${}(ibatis为:$$): MyBatis不会修改或转义字符串,将会直接在SQL语句中插入一个不改变的字符串,常用于拼凑sql的实体部分,
例如:select * from ${tableName}

在执行SQL时MyBatis会自动通过对象中的属性给SQL中参数赋值,它会自动将Java类型转换成数据库的类型。而一旦传入的是null它就无法准确判断这个类型应该是什么,就有可能将类型转换错误,从而报错。
要解决这个问题,需要针对这些可能为空的字段,手动指定其转换时用到的类型。

一般情况下,我们没有必要按个字段去识别/判断它是否可以为空,而是将所有的字段都当做可以为空,全部手动设置转换类型。

<insert id="save"  
        parameterType="com.tarena.entity.Cost">  
        insert into cost values(  
            cost_seq.nextval,  
            #{name,jdbcType=VARCHAR},  
            #{base_duration,jdbcType=INTEGER},  
            #{base_cost,jdbcType=DOUBLE},  
            #{unit_cost,jdbcType=DOUBLE},  
            #{status,jdbcType=CHAR},  
            #{descr,jdbcType=VARCHAR},  
            #{creatime,jdbcType=TIMESTAMP},  
            #{startime,jdbcType=TIMESTAMP},  
            #{cost_type,jdbcType=CHAR}  
        )  
    </insert>  

JSON解析

{
	"requestId": "61701564-ab07-4039-b751-52548c3e315c",
	"success": true,
	"data":{
		"total":2,
		"detail": [{
			"id": 1,
			"name": "小明",
			"age": "15"
		}, {
			"id": 2,
			"name": "小刚",
			"age": "18",
		}]
	}
}

 如:上图中蓝框中的数据格式就是json对象,而其中红框中的数据格式又是json数组。

在将其中所有json信息解析出来,具体参考下方代码:

package com.zhicall.ladder.esb.service;
 
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.collections.bag.SynchronizedSortedBag;
 
public class JsonParserTest {
 
    public static void main(String[] args) {
        String json = "{\n" +
                "\t\"requestId\": \"61701564-ab07-4039-b751-52548c3e315c\",\n" +
                "\t\"success\": true,\n" +
                "\t\"data\":{\n" +
                "\t\t\"total\":2,\n" +
                "\t\t\"detail\": [{\n" +
                "\t\t\t\"id\": 1,\n" +
                "\t\t\t\"name\": \"小明\",\n" +
                "\t\t\t\"age\": \"15\"\n" +
                "\t\t}, {\n" +
                "\t\t\t\"id\": 2,\n" +
                "\t\t\t\"name\": \"小刚\",\n" +
                "\t\t\t\"age\": \"18\",\n" +
                "\t\t}]\n" +
                "\t}\n" +
                "}";
        parseJsonInfo(json);
    }
 
    public static void parseJsonInfo(String json) {
        System.out.println("====开始解析====");
        JSONObject jsonObject = JSONObject.fromObject(json);
        String requestId = jsonObject.getString("requestId");
        System.out.println("\"requestId\" = " + requestId);
        String success = jsonObject.getString("success");
        System.out.println("\"success\" = " + success);
        String total = jsonObject.getJSONObject("data").getString("total");
        System.out.println("\"total\" = " + total);
        JSONArray jsonArray = jsonObject.getJSONObject("data").getJSONArray("detail");
        for(int i =0;i<jsonArray.size();i++){
            JSONObject jsonObject1 = jsonArray.getJSONObject(i);
            String id = jsonObject1.getString("id");
            System.out.println("\"id\" = " + id);
            String name = jsonObject1.getString("name");
            System.out.println("\"name\" = " + name);
            String age = jsonObject1.getString("age");
            System.out.println("\"age\" = " + age);
        }
        System.out.println("====解析结束====");
    }
}

 输出结果:

====开始解析====
"requestId" = 61701564-ab07-4039-b751-52548c3e315c
"success" = true
"total" = 2
"id" = 1
"name" = 小明
"age" = 15
"id" = 2
"name" = 小刚
"age" = 18
====解析结束====

注意以上导包都是net.sf.json,不要搞错了。

getJSONObject()为获取json对象数据;

getJSONArray()为获取json数组数据;

获取指定格式数据后,getString()获取指定key对应的value值即可。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐