mybatis 学习笔记
2018-06-03 本文已影响0人
泛空秋慕
1.mybatis返回主键的值:{
<insert id="XXX">
insert into sys_user(
id,user_name,user_password,user_email,
user_info,head_img,create_time
)
values(
#{id},#{userName},#{userPassword},#(userEmail),
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbdType=TIMESTAMP}
)
</insert>
·Mysql:{
1)适用于主键值自增(数据库主键数据类型为int或者Long){
·修改配置文件
<insert id="XXX" useGeneratedKeys="true",keyProperty="id">
insert into sys_user(
id,user_name,user_password,user_email,
user_info,head_img,create_time
)
values(
#{id},#{userName},#{userPassword},#(userEmail),
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbdType=TIMESTAMP}
)
</insert>
·在对应的接口中将方法的返回值设定为对应的返回值。
}
2)适用于所有的情况:{
·修改配置文件
<insert id="XXX">
insert into sys_user(
id,user_name,user_password,user_email,
user_info,head_img,create_time
)
values(
#{id},#{userName},#{userPassword},#(userEmail),
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbdType=TIMESTAMP}
)
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>
·在对应的接口中将方法的返回值设定为对应的返回值即可
}
}
Oracle:{
·修改配置文件
<insert id="XXX">
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE">
SELECT SEQ_ID.nextval from dual
</selectKey>
insert into sys_user(
id,user_name,user_password,user_email,
user_info,head_img,create_time
)
values(
#{id},#{userName},#{userPassword},#(userEmail),
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbdType=TIMESTAMP}
)
</insert>
·在对应的接口中将方法的返回值设定为对应的返回值即可
}
注意:类似于Mysql第二种方式,或者是Oracle的返回主键值的方式<selectKey>标签执行的顺序仅仅和改标签配置的
order属性值相关,和它在insert语句的前后顺序无关;
其他一些支持逐渐自增数据库配置selectKey中回写主键的sql可查阅《Mybatis从入门到精通 刘增辉著》第二章,p42.
}
2.使用map或者@Param注解来解决多个接口参数的问题{
·当接口对应的方法中只有一个参数时,Mybatis并不关心参数叫什么名字就会把这个唯一的参数值拿来使用;
·当接口对应的方法中有多个入参时,若没有使用@Param注解来标识参数名,那么Mybatis默认可用的参数名只有
[0,1,param1,param2]
·当多接口参数中使用了@Param注解来标识参数名,那么Mybatis便可识别对应在注解中标识的参数.
}
3.mybatis 模糊查询(like):{
·普通SQL
<select id="XXX">
select *
from sys_user u
where u.user_name like concat('%',#{userName},'%')
and u.user_email=#{userEmail}
</select>
·动态SQL
<select id="XXX">
select *
from sys_user u
where 1=1
<if test="userName !=null and userName!='' ">
and u.user_name like concat('%',#{userName},'%')
</if>
<if test"userEmail!=null and userEmail!='' ">
and u.user_email = #{userEmail}
</if>
</select>
}
4.动态SQL:{
1)if{
·在where子句中使用if(例如上述笔记的like模糊查询)
·在UPDATE中使用if{
<update id="XXX">
update sys_user
set
<if test="userName!=null and userName!='' ">
user_name = #{userName},
</if>
<if test="userPassword!=null and userPassword!='' ">
user_password = #{userPassword},
</if>
<if test="userEmail!=null and userEmail!='' ">
user_email = #{userEmail},
</if>
<if test="userInfo!=null and userInfo!='' ">
user_info = #{userInfo},
</if>
<if test="headImg!=null">
head_img = #{headImg,jdbcType=BLOB},
</if>
id = #{id}
where id=#{id}
</update>
}
·在INSERT动态插入中使用if:{
<insert id="XXX" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(
id,user_name,user_password,
<if test="userEmail!=null and userEmail!=''">
user_email,
</if>
user_info,head_img,create_time
)
values(
#{id},#{userName},
<if test="userEmail!=null and userEmail!=''">
#(userEmail),
<if>
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbdType=TIMESTAMP}
)
</insert>
}
}
2)choose提供if...else、if...else...的逻辑:{
需求:当参数id有值的时候优先使用id进行查询,当id没有值的时候就判断userName是否有值,如果用户名有值
就使用用户名查询,如果用户名也没有值那就使SQL查询无结果。
<select id="XXX">
select *
from sys_user u
where 1=1
<choose>
<when test="id !=null">
and id= #{id},
</when>
<when test="userName !=null and userName!=''">
and user_name= #{userName},
</when>
<otherwise>
and 1=2
</otherwise>
</choose>
</select>
}
3)where、set、trim{
1)where{
<select id="xxx">
select *
from sys_user
<where>
<if test="userName!=null and userName!=''">
and user_name = #{userName}
</if>
<if test="userEmail!=null and userEmail!=''">
and user_email = #{userEmail}
</if>
</where>
</selcet>
注意:使用<where>标签,当所有的if条件都不满足的时候,最终生成的SQL语句中不会出现where子句,这就保证了
程序中永远不会出现where 1= 1 这样的情况;
where元素内容就是以and开头的条件,where会自动去掉开头的and.
}
2)set{
<update id="xxx">
update sys_user
<set>
<if test="userName!=null and userName!=''">
user_name = #{userName},
</if>
<if test="userPassword!=null and userPassword!=''">
user_name = #{userName},
</if>
<if test="userEmail!=null and userEmail!=''">
user_email = #{userEmail},
</if>
<if test="userInfo!=null and userInfo!=''">
user_info = #{userInfo},
</if>
id = #{id}
</set>
where id =#{id}
</updae>
注意:如果set标签包含的元素有返回值,就插入一个set;
如果set后面的字符串是以逗号结尾的,就将这个逗号剔除;
如果set中的元素没有内容,那么生成的SQL还是会有SQL语法错误,故此类似id=#{id}这样的赋值任然还有必要保留
}
3)trim{
<trim prefix="WHERE" prefixOverrides="AND |OR">
...
</trim>
trim标签有如下的属性:
prefix:当trim元素内包含内容时,会给内容增加prefix指定的前缀。
prefixOverrides:当trim元素包含内容时,会把内容中匹配的前缀字符串去掉。
suffix:当trim元素内包含内容时,会给内容增加suffix指定的后缀。
suffixOverrides:当trim元素包含内容时,会把内容中匹配的后缀字符串去掉。
}
}
4)foreach{
foreach实现in集合:{
<select id="xxx">
select *
from sys_user
where id in
<foreach collection="list" open="(" close=")" separator="," item="id" index="i">
#{id}
</foreach>
</select>
}
注意:
·当只有一个数组参数或者一个结婚参数的时:
当参数类型为集合(Collection)类型时,默认在Mybatis底层会将其转换为Map类型,并添加
一个key为collection的值;
当参数是一个list集合类型时,也会默认转换成map类型,默认的key为list;
当参数类型为数组时,也会默认转换成map类型,默认的key为array.
·有多个参数:
使用@Param注解来给每个参数指定一个名字,将collection的值设置为@Param指定的注解的名称即可.
·参数是Map类型:
使用Map类型和使用@Param注解的情形类似只要将map的key的值绑定给collection的属性即可;
如果要循环所输入的Map,推荐使用@Param注解指定名字,此时可以将collection的值设置为@Param注解指定的名字即可,如果不想指定名字,则使用_parameter.
·参数是一个对象:
这种情况下指定collection属性值为对象的属性名即可,当使用对象内多层嵌套的对象时,使用属性.属性(集合和数组可以使用下标取值),可以指定深层次的属性值.
foreach实现批量插入:{
<insert id="XXX" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(
user_name,user_password,user_email,
user_info,head_img,create_time
)
values
<foreach collection="list" item="user" separator=",">
(
#{userName},#{userPassword},#{userEmail},
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP}
)
</foreach>
</insert>
}
foreach实现动态update:{
<update id="xxx">
update sys_user
set
<foreach collection="_parameter" item="val" index="key" separator=",">
${key}= #{val}
</foreach>
</update>
注意:当参数为map类型时,foreach标签的index属性值对应的不是索引值,而是map中的key;
如上以map的key作为列名,对应的值作为该列的值,通过foreach将需要更新的字段拼接在SQL语句中。
}
}
5)bind用法:{
·bind可以使用OGNL创建一个变量并将其绑定到上下文中;
·例子:修改之前的like模糊查询:{
未修改之前:{
<if test="userName!=null and userName!=''">
and user_name like concat('%',#{userName},'%')
</if>
}
在未修改之前的版本中为使用like模糊查询,使用了concat函数来实现字符串拼接,在MySql中这个函数支持多个参数,但是在Oracle中这个函数
只支持两个参数;由于不同数据库之间语法的差异,如果更换数据库,有些SQL语句就可能需要重写,针对这种情况可以使用bind标签来避免由于
更换数据库而带来的麻烦。
修改后:{
<if test="userName!=null and userName!='' ">
<bind name="userNameLike" value="'%'+userName+'%'"/>
and user_name like #{userNameLike}
</if>
注意:bind标签的两个属性都是必选项,name为绑定到上下文的变量名,value为OGNL表达式。
}
}
}
}
5.mybatis二级缓存配置:{
}
6.mybatis高级映射:{
1)mybatis单表查询:{
·单表查询时可以使用字段别名来实现查询返回结果集和JavaBean的映射;
·可以通过配置resultMap来实现映射;
·如果数据库字段和JavaBean符合转驼峰规则,通过在mybatis中配置全局属性:
<settings>
<!--
通过将该属性配置为true可以自动将以下划线方式命名的数据列映射到Java对象的驼峰式命名属性中,
该属性默认值为false,如果想要使用该功能,需要手动指配其值为true。
-->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!--其他配置-->
</settings>
}
2)一对一映射:{
eg:{
package com.hsun.mybatis.model.SysUser;
public class User{
private String userName;
private String userPassword;
private SysRole role;//SysRole是一个实体类
//setter、getter
}
·使用别名映射
<select id="xxx">
selcet
u.user_name,
u.user_password,
r.id "role.id",
r.role_name "role.roleName"
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where u.id = #{id}
</selcet>
注意:上述方法中sys_role 查询列的别名都是"role."前缀,通过这种方式,将role的属性都映射到了
SysUser的role属性上。
·使用resultmap映射
<resultMap id="userAndRoleResultMap" type="com.hsun.mybatis.model.SysUser">
<id property="id" column="id" />
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<!--sys_role相关属性-->
<result property="role.id" column="role_id" />
<result property="role.roleName" column="role_name" />
</resultMap>
注意:该种配置在property属性中使用“role."前缀,column部分为了避免不同表中存在相同的列,所有可能重名
的列都加了"role_"前缀,使用这种配置的时候还要在查询时使用不同的别名。查询语句如下:
<select id="xxx" resultMap="userAndRoleResultMap">
selcet
u.user_name,
u.user_password,
r.id role_id,
r.role_name
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where u.id = #{id}
</selcet>
·使用resultMap标签的association标签来配置一对一映射
<!--userResultMap仅仅配置了user的属性不包含role属性-->
<resultMap id="userAndRoleWithAssociationResultMap" extends="userResultMap"
type="com.hsun.mybatis.model.SysUser">
<id property="id" column="id" />
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<association property="role" javaType="com.hsun.mybatis.model.SysRole"
columnPrefix="role_">
<!--sys_role相关属性-->
<result property="id" column="role_id" />
<result property="roleName" column="role_name" />
</association>
</resultMap>
注意:
·property:实体类中的属性名,必选项,
·javaType:属性对应的Java类型。
·resultMap:可以使用现有的resultMap,而不需要在association标签中配置result
·columnPrefix:查询列的前缀,配置前缀后,在子标签result的column可以省略前缀。
但是在查询时,role对应的查询列都要使用别名并且别名必须是以此处配置的前缀开头的。
·在mybatis中不同命名空间下的resultMap也是可以引用的,引用时需要加上”命名空间.resultMap的id属性“
例如:有关role的属性全部配置到RoleMapper.xml 文件中,其中有一个resultMap的id为roleMap,那么在
UserMapper.xml文件中引用的方式如下:
<resultMap id="userAndRoleWithAssociationResultMap" extends="userResultMap"
type="com.hsun.mybatis.model.SysUser">
<id property="id" column="id" />
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<association property="role" resultMap="com.hsun.mybatis.model.RoleMapper.roleMap"
columnPrefix="role_" />
</resultMap>
}
·association标签嵌套查询:{
·association标签的嵌套查询常用的属性如下:{
select:另一个映射查询的id,mybatis会额外执行这个查询获取嵌套对象的结果.
column: 列名(或别名),将主查询中列的结果作为嵌套查询的参数,配置方式如:
column={prop1=col1,prop2=col2},prop1,prop2将作为嵌套查询的参数.
·fetchType:数据加载方式,可选值为lazy和eager,分别为延迟加载和积极加载,这个配置
会会覆盖全局的lazyLoadingEnabled配置。
<resultMap id="xxx" extends="userMap" type="com.hsun.mybatis.model.User">
<association property="role"
fetchType="lazy"
selcet="com.hsun.mybatis.mapper.RoleMapper.selcetRoleById"
column="id={role_id}">
</association>
<resultMap/>
}
}
}
3)一对多映射:{
使用collection集合的嵌套映射:
<resultMap id="userRoleListMap" extends="userResultMap"
type="com.hsun.mybatis.model.SysUser">
<id property="id" column="id" />
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<collection property="roleList" ofType="com.hsun.mybatis.model.SysRole"
columnPrefix="role_">
<!--sys_role相关属性-->
<result property="id" column="role_id" />
<result property="roleName" column="role_name" />
</collection>
</resultMap>
或者:
<resultMap id="userRoleListMap" extends="userResultMap"
type="com.hsun.mybatis.model.SysUser">
<id property="id" column="id" />
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<collection property="roleList" ofType="com.hsun.mybatis.model.SysRole"
columnPrefix="role_" resultMap="com.hsun.mybatis.mapper.SysRoleMapper.roleMap">
</collection>
</resultMap>
}
}
7.mybatis 部分常用settings配置:{
<settings>
<!--
通过将该属性配置为true可以自动将以下划线方式命名的数据列映射到Java对象的驼峰式命名属性中,
该属性默认值为false,如果想要使用该功能,需要手动指配其值为true。
-->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!--指定使用LOG4J来支持mybatis的日志-->
<setting name="logImpl" value="LOG4J" />
<!--
mybatis 二级缓存全局开关,默认为开启状态,mybatis的二级缓存是和命名空间绑定的,即二级缓存需要配置在Mapper.xml、
文件中或者配置在Mapper.java接口中。配置在xml文件中,命名空间就是xml根节点mapper的namespace属性。在mapper接口中,
命名空间就是接口的全限定名称。
-->
<setting name="cacheEnabled" value="true" />
<!--
·该属性是控制mybatis带有延迟加载属性的对象的完整加载或者延迟加载;
·当改该属性的值为true时,会使得对任意延迟属性的调用会使带有延迟加载属性的对象完整加载:
·当该属性的值为false时,会对带有延迟加载属性的对象按需加载;
·该属性的默认值是true,故而要使用mybatis的延迟加载属性需要手动在<settings>标签中将该值配置为false;
·mybatis的延迟加载是通过动态代理实现的,在与spring集成时,要确保带有延迟加载的属性的对象的获取在
service层。当结果从service层返回controller层时,如果获取延迟加载的属性值,会因为SqlSession已经关闭而抛出异常.
-->
<setting name="agressivelazyLoading" value="false" />
</settings>
}