使用MyBatis进行简单的更新与查询方式
作者:多罗罗~
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中的键值对赋值给指定的实体类属性。 |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。