MyBatis增删改查的用法
sql映射文件
sql映射文件中的顶级元素说明
元素 | 说明 |
---|---|
mapper | sql映射文件的根元素, 只有一个属性namespace,用于区分不同的mapper,必须全局唯一。 |
cache | 为给定命名空间配置缓存 |
cache-ref | 引用其他命名空间的缓存配置 |
resultMap | 用于描述查询结果集中的字段荷Java实体类属性的对应关系 |
sql | 定义可重用的sql语句块,可以在其他语句映射中引用 |
insert | 映射insert语句 |
update | 映射update语句 |
delete | 映射delete语句 |
select | 映射select语句 |
使用规则
1,sql映射文件与该mapper接口同名(实体类名+mapper),并放置在同意包路径下。
2,要以映射的mapper接口的完全限定名(包名+类名)作为namespace属性的值。
3,接口中的方法名与映射文件中sql语句映射的ID一一对应。
4,在不同的sql映射文件中,子元素的id可以相同。
myBatis框架的缓存
缓存分类
一级缓存 | 基于PerperualCache的HashMap本地缓存,默认是SQL Session级别的缓存, 在SQL Session的一个生命周期中有效。 MyBatis框架的一级缓存默认是开启的。 |
二级缓存 | 二级缓存是SQL Session Factory级别的,其缓存中的数据可以被所有SQL session共享。 MyBatis框架的二级缓存**默认是关闭的。**使用时需要在其核心配置文件中设置开启。 |
二级缓存的使用方法
1>在核心配置文件中设置全局开启二级缓存
<settings>
<setting name="cacheEnabled" value="true" />
</settings>
2>根据需要在sql映射文件中配置缓存,为当前namespace启用二级缓存
<!--在mapper标签内-->
<!--缓存设置-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true" />
cache元素中各种属性的作用
eviction | 选择缓存回收策略 LRU:默认选项,最近最少回收,移除最长时间不被使用的缓存对象。 FIFO:先进先出,按照对象缓存的顺序来移除他们。 SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。 WEAK:弱引用,更积极的移除基于来及回收器和若以用规则的对象。 |
flushInterval | 设定缓存刷新间隔,以ms为单位设定多久自动刷新一次缓存 默认不自动刷新 |
size | 设定缓存中最多存放的对象数, 默认1024 |
readOnly | 设定缓存是否只读。 默认false,表示缓存数据会用于读写操作 true:表示缓存数据值用于读操作。 |
3>在sql映射文件中配置支持二级缓存后,如需对个别查询进行调整,可在select元素中单独设置
<select id="selectAll" resultType="SysUser"
useCache="true">
....
</select>
myBatis框架的新增
新增,使用insert元素来映射插入语句。
//接口中的方法
/**
* 新增的方法
* @param smbmsUser smbmsUser对象
* @return 返回受影响的行数
*/
int insertUserInfo(SmbmsUser smbmsUser);
<!--对应的mapper标签-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<insert id="insertUserInfo" parameterType="com.pojo.SmbmsUser">
<!--sql语句中 #{xxx} 中xxx均为实体类中的属性名一致-->
insert into smbms_user (userName,userPassword,userCode)values (#{userName},#{userPassword},#{userCode})
</insert>
myBatis框架的更新
//接口中的方法
/**
* 更新信息的方法
* @param smbmsUser smbmsUser对象
* @return 返回受影响的行数
*/
int updateUserInfo(SmbmsUser smbmsUser);
<!--对应的mapper标签-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<update id="updateUserInfo" parameterType="com.pojo.SmbmsUser">
<!--sql语句中 #{xxx} 中xxx均为实体类中的属性名一致-->
Update smbms_user set userName=#{userName} where id=#{id}
</update>
myBatis框架的删除
//接口中的方法
/**
* 根据id删除的方法
* @param id 要删除的id
* @return 返回受影响的行数
*/
int deleteUserInfoById(@Param("id")int id);
<!--对应的mapper标签-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<delete id="deleteUserInfoById" parameterType="int">
<!--此时#{xxx}参数中xxx可以不与对应Mapper类方法中的形参一直-->
delete from smbms_user where id=#{id}
</delete>
注意总结
1>对于增删改这类操作,数据库本身默认返回执行sql所影响的行数,所以DAO层的Mapper接口方法的返回值一般设置为int类型。
2>insert , update, delete元素中均没有resultType/resultMap属性。
myBatis框架的简单查询
基本数据类型—实现单一条件查询
//接口中的方法
/**
* 根据用户名模糊查的方法
* @param userName 用户名
* @return 集合
*/
List<SmbmsUser> listByUserName(String userName);
<!--对应的mapper标签-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<!--属性resultType的值为返回结果的类型,要使用完全限定名或别名(这里用了完全限定名) -->
<select id="listByUserName" parameterType="string" resultType="com.pojo.SmbmsUser">
<!--此时#{xxx}参数中xxx可以不与对应Mapper类方法中的形参一直-->
SELECT u.*,r.`roleName` FROM smbms_user AS u INNER JOIN `smbms_role` AS r ON
u.`userRole`=r.`id` WHERE userName LIKE CONCAT('%',#{param},'%')
</select>
select标签中的parameterType属性 ,表示为向sql语句传入的参数类型,使用完全限定名(包名+类名)或别名,支持基础数据类型和复杂数据类型。
被映射的sql语句中,参数的表示方法为*#{参数名},此参数名不需要**和Mapper接口中方法的形参刻意匹配,因为myBatis框架将映射的sql语句自动转换成 “?” 占位符的sql语句并实现赋值。*
mybatis框架内建的部分别名与java数据类型的映射关系
映射类型 | 别名 | 映射类型 | 别名 |
---|---|---|---|
Boolean | boolean | String | string |
Byte | byte | BigDecimal | bigdecimal或decimal |
Long | long | Date | date |
Short | short | Map | map |
Integer | int或integer | HashMap | hashmap |
Double | double | List | list |
Float | float | ArrayList | arraylist |
基本数据类型—实现多条件查询
使用@Param注解实现多参数入参
//接口中的方法
/**
* 根据商品名和id查询商品通过注解的方式
* @param name 商品名
* @param id id
* @return 返回一个商品对象
*/
SmbmsProvider getByNameAndIdInNote(@Param("proName")String name,@Param("id")int id);
//注解中的参数名,将用于Sql映射文件中的对应select标签的sql语句中的参数值
<!--对应的mapper标签中-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<!--属性resultType的值为返回结果的类型,要使用完全限定名或别名(这里用了完全限定名) -->
<select id="getByNameAndIdInNote" resultType="com.pojo.SmbmsProvider">
select * from smbms_provider where proName like CONCAT('%',#{proName},'%') and id=#{id}
</select>
注意:
1,当输入的参数类型为基本数据类型时,select标签中的parameterType属性可省略(无论单参还是多参)
2,注解中定义的参数名称要和sql语句占位符中的参数名称一致
实现多条件查询
将查询条件封装成java对象作为入参
//接口中的方法
/**
* 根据输入参数查询商品信息
* @param provider 对象
* @return 商品对象
*/
List<SmbmsProvider> getAll(SmbmsProvider provider);
<!--对应的mapper标签中-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<!--属性resultType的值为返回结果的类型,要使用完全限定名或别名(这里用了完全限定名) -->
<select id="getAll" resultType="com.pojo.SmbmsProvider" parameterType="com.pojo.SmbmsProvider">
<!--sql中的#{xxx}中的xxx要和实体类中的属性名一致-->
select * from smbms_provider where proName like CONCAT('%',#{proName},'%')
</select>
将查询条件封装成Map对象作为入参
//接口中的方法
/**
* 根据商品名和id查询商品的方法
* @param map map集具体合对象中存有商品名和id的值
* @return 返回一个具体对象
*/
SmbmsProvider getByNameAndId(Map<String,Object> map);
<!--对应的mapper标签中-->
<!--属性id的值为对应的Mapper接口中的方法名 ,属性parameterType的值为此方法形参的类型 -->
<!--属性resultType的值为返回结果的类型,要使用完全限定名或别名(这里用了完全限定名) -->
<select id="getByNameAndId" parameterType="map" resultType="com.pojo.SmbmsProvider">
<!--sql中的#{xxx}中的xxx要和map集合中的key一致-->
select * from smbms_provider where proName like CONCAT('%',#{proName},'%') and id=#{id}
</select>
//测试类中
@Test
void getByNameAndId() {
SqlSession session= MyBatisUtil.getSqlSession();
ProviderMapper providerMapper=session.getMapper(ProviderMapper.class);
Map<String,Object> map=new HashMap<>() ;
//注意添加的key
map.put("proName","北京");
map.put("id",6);
SmbmsProvider smbmsProvider= providerMapper.getByNameAndId(map);
System.out.println(smbmsProvider.getProName());
}
使用Map类型传递多个参数,绑定的sql语句中使用#{Map的key}来取得参数值。使用Map传参的方式更加灵活,不受域模型(实体类)设计的限制,可以更加灵活的组织查询所需的条件。
MyBatis框架的结果映射
使用resultMap元素定义结果映射,对名称不同的结果集字段和实体类属性进行映射。
resultMap元素包含的属性
名称 | 说明 |
---|---|
id | 映射规则集的唯一标识,可以被select元素中的resultMap属性引用,便于找到对应规则集。 |
type | 映射的结果类型。 |
resultMap元素包含的子元素
名称 | 说明 |
---|---|
id | 指定和数据表主键字段对应的标识属性。 可提高框架的性能,特别是应用缓存和嵌套结果映射的时候。 |
result | 指定结果集字段和实体类属性的映射关系。 |
eg:
<!--使用resultMap元素定义结果映射-->
<resultMap id="userWithRoleName" type="com.pojo.SmbmsUser">
<id property="id" column="id"></id>
<result property="userRoleName" column="roleName"></result>
</resultMap>
<!--使用resultMap元素定义的规则封装查询结果-->
<select id="listByUserName" parameterType="string" resultMap="userWithRoleName">
SELECT u.*,r.`roleName` FROM smbms_user AS u
INNER JOIN `smbms_role` AS r ON u.`userRole`=r.`id`
WHERE userName LIKE CONCAT('%',#{userName},'%')
</select>
注意
1,select元素中的resultMap属性的值要与resultMap元素中id属性的值一致。
2,select元素中的parameterType属性的值要与resultMap元素中type属性的值一致。
3,resultMap元素中的id子元素是数据表主键字段的列, 其中property属性是相应实体类中的对应属性,其中column属性是结果集中列的名称。
4,resultMap元素中的result子元素是用来映射其他的列, 其中property属性是相应实体类中的对应属性,其中column属性是结果集中列的名称。
resultMap的自动映射行为
可以在核心配置文件中进行设置
<settings>
<!-- 设置自动映射行为 -->
<setting name="autoMappingBehavior" value="FULL"/>
</settings>
其上value的值有3种
值 | 说明 |
---|---|
NONE | 禁用自动映射,仅为手工映射的属性赋值。 |
PARTIAL | 默认行为,没嵌套的resultMap使用自动映射,有嵌套的则不使用。 |
FULL | 全部使用自动映射,有嵌套的也会使用自动映射。 |
自动映射行为对resultType和resultMap的影响
自动映射行为 | resultType(不支持嵌套映射) | 没有嵌套映射的resultMap | 有嵌套映射的resultMap |
---|---|---|---|
NONE | 失效 | 手工映射 | 手工映射 |
PARTUAL | 自动映射 | 自动映射 | 手工映射 |
FULL | 自动映射 | 自动映射 | 自动映射 |
注意
1, resultType不支持嵌套映射,无论autoMappingBehavior设置为PARTIAL还是FULL,实体类都会自动映射,而实体类中的关联属性都不会被初始化,始终未null.
2,resultType完全依赖自动映射,如果autoMappingBehavior设置为NONE,resultType会失效,无法初始化实体类对象而返回null,此时返回 查询只能使用resultMap手工映射。
嵌套结果映射
1,association元素
------------此元素用来处理‘’has-one‘’类型的关系(复合类型)。
处理:多对一或一对一
association元素包含的属性
名称 | 说明 |
---|---|
property | 实体类中用来映射查询结果子集的属性 |
javaType | property指定的属性的数据类型,可以使用java完全限定类名或别名。 如果property指定的属性是javaBean,则框架能自行检测出。 如果property指定的属性是HashMap,则应通过javaType属性明确指定其数据类型。 |
resultMap | 引用外部resultMap |
association元素包含的子元素
名称 | 说明 |
---|---|
id | 指定和数据表主键字段对应的标识属性。 |
result | 指定结果集字段和实体类属性的映射关系。 |
eg:
//用户实体类中,添加一个角色类型的属性
private SmbmsRole smbmsRole;//系统角色实体类类型的属性
public SmbmsRole getSmbmsRole() {
return smbmsRole;
}
public void setSmbmsRole(SmbmsRole smbmsRole) {
this.smbmsRole = smbmsRole;
}
//接口中添加相应的查询方法
/**
* 根据roleId查找信息--使用嵌套方式
* @param roleId
* @return
*/
List<SmbmsUser> listByRoleId(@Param("roleId")Long roleId);
<!--相应的mapper文件中-->
<resultMap id="showRoleName" type="com.smbms.pojo.SmbmsUser">
<id property="id" column="id"/>
<!---->
<association property="smbmsRole" javaType="com.smbms.pojo.SmbmsRole">
<id property="id" column="rid" />
<result property="roleName" column="roleName"/>
<result property="roleCode" column="roleCode"/>
</association>
</resultMap>
<select id="listByRoleId" parameterType="long" resultMap="showRoleName">
SELECT u.*,r.id AS rid,r.`roleName`,r.`roleCode`
FROM `smbms_user` AS u
INNER JOIN `smbms_role` AS r ON u.`userRole`=r.id
</select>
//测试类
@Test
void listByRoleId() {
List<SmbmsUser> list=userMapper.listByRoleId(3L);
for (SmbmsUser smbmsUser : list) {
System.out.println(smbmsUser.getUserName()+"\t"+
smbmsUser.getSmbmsRole().getRoleName());
}
//结果---
赵燕 普通员工
赵敏 打工人
ss 打工人
注意:
1,因为结果映射的需要,要确保所有列名都是唯一的。
2,id子元素在嵌套结果映射中扮演了重要的角色。最好选择尽量少的属性来表示唯一结果。
对上述Mapper文件可修改为
<!--相应的mapper文件中-->
<!--把其单独提取出来,便于重用-->
<resultMap id="showRoleInfo" type="com.smbms.pojo.SmbmsRole">
<id property="id" column="rid" />
<result property="roleName" column="roleName"/>
<result property="roleCode" column="roleCode"/>
</resultMap>
<resultMap id="showRoleName" type="com.smbms.pojo.SmbmsUser">
<id property="id" column="id"/>
<!---->
<association property="smbmsRole" javaType="com.smbms.pojo.SmbmsRole" resultMap="showRoleInfo">
</association>
</resultMap>
<select id="listByRoleId" parameterType="long" resultMap="showRoleName">
SELECT u.*,r.id AS rid,r.`roleName`,r.`roleCode`
FROM `smbms_user` AS u
INNER JOIN `smbms_role` AS r ON u.`userRole`=r.id
</select>
2,collection元素
---------实体类内部嵌套的是一个集合类型的属性
collection元素包含的属性
名称 | 说明 |
---|---|
property | 实体类中用来映射查询结果子集的集合属性 |
ofType | property指定的集合属性中的元素的数据类型,可以使用java完全限定类名或别名。 |
resultMap | 引用外部resultMap |
collection元素包含的子元素
名称 | 说明 |
---|---|
id | 指定和数据表主键字段对应的标识属性。 |
result | 指定结果集字段和实体类属性的映射关系。 |
eg:
//用户的实体类中 添加属性
private List<SmbmsAddress> addressList;//用户地址列表
public List<SmbmsAddress> getAddressList() {
return addressList;
}
public void setAddressList(List<SmbmsAddress> addressList) {
this.addressList = addressList;
}
//相应接口中编写方法
/**
* 根据永用户id查询用户及相关地址
* @param id
* @return
*/
List<SmbmsUser> listUserAndAddressesByUserId(@Param("userId")int id);
<!--相应的mapper文件中-->
<resultMap id="show" type="com.smbms.pojo.SmbmsUser">
<id property="id" column="id"></id>
<collection property="addressList" ofType="com.smbms.pojo.SmbmsAddress">
<id property="id" column="aid"></id>
<result property="contact" column="contact"></result>
<result property="addressDesc" column="addressDesc"></result>
<result property="postCode" column="postCode"></result>
<result property="tel" column="tel"></result>
</collection>
</resultMap>
<select id="listUserAndAddressesByUserId" parameterType="int" resultMap="show">
SELECT u.*,a.id AS aid,a.`addressDesc`,a.`contact`,a.`postCode`,a.`tel`
FROM `smbms_user` AS u
INNER JOIN `smbms_address` AS a ON u.id=a.`userId`
WHERE u.id=#{userId}
</select>
//测试类
@Test
void listUserAndAddressesByUserId() {
List<SmbmsUser> list=userMapper.listUserAndAddressesByUserId(1);
for (SmbmsUser smbmsUser : list) {
System.out.println(smbmsUser.getUserName()+"\t");
//找到此用户的地址集合并打印
for (SmbmsAddress smbmsAddress : smbmsUser.getAddressList()) {
System.out.println(smbmsAddress.getAddressDesc());
}
}
}
//结果
系统管理员
北京市东城区东交民巷44号
北京市海淀区丹棱街3号
北京市东城区美术馆后街23号
resultType和resultMap总结
resultType | resultMap | |
---|---|---|
相同 | 均基于Map数据结构 | 均基于Map数据结构 |
不同1 | 直接指定结果类型,依靠自动映射 用于比较简单,直接的数据封装场景 | 对外部resultMap定义的引用,可自由控制结果映射规则和封装范围 用于处理结果集字段名与实体类属性名不一致,或者需要对连接查询结果使用嵌套映射等复杂问题。 |
不同2 | 框架会先将查询的结果集存储在map结构中,以字段名作为key, 当select元素使用此属性指定结果类型时,框架会自动将Map中的键值对对应赋值给实体类中与key同名的属性 | 框架会先将查询的结果集存储在map结构中,以字段名作为key, 当select元素使用此属性时,则根据所引用的resultMap元素中定义的映射规则把Map中的键值对赋值给指定的实体类属性。 |
每日一句: 每一个不曾起舞的日子,都是对生命的一种辜负!