mybatis
一. Mybatis预备知识
(1)标签
标签分为:闭合标签和空标签
标签属性格式
键名="值" <--!标签属性-->
闭合标签
<标签名 标签属性 标签属性......><--!开始标签--> <--!标签内容--> </标签名><--!结束标签-->
空标签(空标签没有内容但可以有属性,在开始标签中自动闭合)
<标签名 标签属性 标签属性....../>
xml文件内容的注释: <!--注释内容-->
(2)jdbc(java database connectivity的缩写)
jdbcType 与 javaType 存在对应关系
(3)XML
在 xml 文件中出现 “<” , “>” ,双引号 等特殊字符时可以使用XML 文件转义标签(XML 自身的)
<![CDATA[特殊字符]]>
二. Mybatis配置
1.resource xml文件配置修改,需要重启服务才能生效。
2. resultMap:适合使用返回值是自定义实体类的情况
(resultType适合使用返回值得数据类型是非自定义的,即jdk的提供的类型)
<resultMap id="标识名" type="类名"> <id column="类主键名" jdbcType="jdbcType类型(大写)" property="类的主键属性" /> <result column="类字段名" jdbcType="jdbcType类型(大写)" property="类的属性"/> <association property="关联对象属性名" javaType="关联对象类名"> <id column="主键字段名" jdbcType="jdbcType类型(大写)" property="关联对象的主键属性"/> <result column="类字段名" jdbcType="jdbcType类型(大写)" property="关联对象的属性"/> </association> <collection property="关联集合属性名" ofType="集合中对象类名"> <id column="集合中对象对应的表的主键字段" jdbcType="jdbcType类型(大写)" property="集合中对象的主键属性" /> <result column="集合中对象对应表的任意字段" jdbcType="jdbcType类型(大写)" property="集合中对象的属性" /> </collection> </resultMap>
3. 关联的嵌套查询(在collection中添加select属性)
如果collection标签是使用嵌套查询,格式如下:
<collection column="传递给嵌套查询语句的字段参数" property="pojo对象中集合属性" ofType="集合属性中的pojo对象" select="嵌套的查询语句" > </collection>
例子:
<resultMap id="BasePlusResultMap" type="com.meikai.shop.entity.TShopSku"> <id column="ID" jdbcType="BIGINT" property="id" /> <result column="SKU_NAME" jdbcType="VARCHAR" property="skuName" /> <result column="CATEGORY_ID" jdbcType="BIGINT" property="categoryId" /> <collection column="{skuId=ID}" property="attributes" ofType="com.meikai.shop.entity.TShopAttribute" select="getAttribute" > </collection> </resultMap>
collection的select会执行下面的查询属性语句:
<resultMap id="AttributeResultMap" type="com.meikai.shop.entity.TShopAttribute"> <id column="ID" jdbcType="BIGINT" property="id" /> <result column="ATTRIBUTE_NAME" jdbcType="VARCHAR" property="attributeName" /> </resultMap>
<select id="getAttribute" resultMap="AttributeResultMap"> select a.ID,s.ATTRIBUTE_NAME from t_shop_attribute a where a.ID = #{skuId,jdbcType=BIGINT}; </select>
BasePlusResultMap包含了属性查询语句的Collection
所以通过下面的查询商品语句就可获得商品以及其包含的属性集合:
<select id="getById" resultMap="BasePlusResultMap"> select s.ID,s.SKU_NAME,s.CATEGORY_ID from t_shop_sku s where s.ID = #{id,jdbcType =BIGINT}; </select>
三. Mybatis 传参
parameterType属性:用于指定参数类型,可以省略不写,但结果类型不能省略。(自查得)
jdbcType属性:指定参数需要转换成的jdbc类型,查询时建议加上。更新或插入时必须加上,当传入的参数为name为空时不会使程序出现问题,否则当参数为空时,mybatis不知道具体要转换成什么jdbcType类型,有些特殊情况会报错。
0.#{}和${}的区别
相同点:都可以获取map中的值或者pojo对象属性的值。
不同点:
#{}是预编译处理,Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值,使用#{}可以有效的防止SQL注入,提高系统安全性。
${}是字符串替换,Mybatis在处理${}时,就是把${}替换成变量的值。
大多情况下,我们去参数的值都应该去使用#{},只有在原生jdbc不支持占位符的地方(比如比如字段名、【分】表名),我们才使用${}进行取值。
按照年份分表: select * from ${year}_salary where xxx;
排序: select * from tbl_employee order by ${f_name} ${order}
1.单个参数
2.按顺序传参
注意:没有使用parameterType属性,早期版本用#{0},#{1}
3.使用@Param注解(支持多类型参数)
4.Map传参(支持多种类型参数)
5. 实体对象传参
6. List传参
7.数组传参
四. Mybatis的insert、update、delete操作
1. 默认返回被操作记录条数。mybatis的insert、update、delete语句,默认是不返回被操作记录主键的,而是返回被操作记录条数(由mysql驱动返回给mybatis)。
2. 获取到记录主键id。<insert useGeneratedKeys="true" keyProperty="你的实体类id" keyColumn="你的表id"></insert>
useGeneratedKeys:必须设置为true,否则无法获取到主键id。
keyProperty:设置为POJO对象的主键id属性名称。
keyColumn:设置为数据库记录的主键id字段名称。
3. 批量更新和插入(此种效率比循环插入要高10倍)
<insert id="insertBatch"> INSERT INTO t_user (id, name, del_flag) VALUES <foreach collection ="list" item="user" separator =","> (#{user.id}, #{user.name}, #{user.delFlag}) </foreach > </insert>
<update id="updateBatch" parameterType="java.util.List"> update mydata_table <trim prefix="set" suffixOverrides=","> <trim prefix="status =case" suffix="end,"> <foreach collection="list" item="item" index="index"> when id=#{item.id} then #{item.status} </foreach> </trim> </trim> where id in <foreach collection="list" index="index" item="item" separator="," open="(" close=")"> #{item.id,jdbcType=BIGINT} </foreach> </update> <trim>
当然这是最简单的批量更新实现,有时候可能需要更新多个字段,那就需要将
<trim prefix="status =case" suffix="end,"> <foreach collection="list" item="item" index="index"> when id=#{item.id} then #{item.status} </foreach> </trim>
复制拷贝多次,更改prefix和when...then...的内容即可.
五.Mybatis的select操作
1. include空标签和其属性refid(引用唯一标识)
<include refid="Base_Column_List" />
2. foreach标签和其属性
foreach元素的属性主要有collection,index,item,open,separator,close。【类似PHP:foreach ($array as $key => $value)】
collection[必填]: 1. 要做foreach的对象,作为入参时,List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键。当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效。
2. 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = "ids".如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id"。
item[选填]:集合中元素迭代时的别名。
index[选填]:在list和数组中,index是元素的序号,在map中,index是元素的key。
open[选填]:foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。
separator[选填]:元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。
close[选填]: foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.
针对最后一条,我们来看一下官方说法: 注意 你可以将一个 List 实例或者数组作为参数对象传给 MyBatis,当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以“list”作为键,而数组实例的键将是“array”。
所以,不管是多参数还是单参数的list,array类型,都可以封装为map进行传递。如果传递的是一个List,则mybatis会封装为一个list为key,list值为object的map,如果是array,则封装成一个array为key,array的值为object的map,如果自己封装呢,则colloection里放的是自己封装的map里的key值。
int insertRecoverWriteOffBatch(@Param("list") List<RecoverWriteOff> recoverWriteOffList); <insert id="insertRecoverWriteOffBatch" parameterType="java.util.List"> insert into t_recover_write_off (write_off_batch_no, merchant_no, flow_no, deduct_amount, create_time, update_time) values <foreach collection="list" item="recoverWriteOff" separator=","> (#{recoverWriteOff.writeOffBatchNo,jdbcType=VARCHAR}, #{recoverWriteOff.merchantNo,jdbcType=VARCHAR}, #{recoverWriteOff.flowNo,jdbcType=VARCHAR}, #{recoverWriteOff.deductAmount,jdbcType=DECIMAL}, #{recoverWriteOff.createTime,jdbcType=TIMESTAMP}, #{recoverWriteOff.updateTime,jdbcType=TIMESTAMP}) </foreach> </insert> int updateRecoverFundFlowByPrimaryKeyBatch(@Param("list") List<RecoverFundFlow> list); <update id="updateRecoverFundFlowByPrimaryKeyBatch" parameterType="java.util.List" > <foreach collection="list" item="item" index="index" open="" close="" separator=";"> update t_recover_fund_flow <set > <if test="item.matchStatus != null" > match_status = #{item.matchStatus,jdbcType=VARCHAR}, </if> <if test="item.recoverBalance != null" > recover_balance = #{item.recoverBalance,jdbcType=DECIMAL}, </if> <if test="item.updateTime != null" > update_time = #{item.updateTime,jdbcType=TIMESTAMP}, </if> <if test="item.writeOffAmount != null" > write_off_amount = #{item.writeOffAmount,jdbcType=DECIMAL}, </if> </set> where id = #{item.id,jdbcType=BIGINT} </foreach> </update>