Mybatis 中xml和注解映射,分分钟搞定
xsobi 2025-01-08 18:17 23 浏览
MyBatis 提供了XML配置和注解配置两种方式。今天就来搞搞这两种方式是如何实现的。
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
来自官网。
Mybatis映射九个顶级元素:
- mapper:映射文件的根节点,只有一个属性namespace(命名空间),作用如下:
- 用于区分不同的mapper,全局唯一。
- 绑定DAO接口,即面向接口编程,当绑定一个接口,就不用写此接口的实现类,会通过接口的完全限定名找到对应的mapper配置来执行SQL语句,所以,namespace的命名必须要写接口的完全限定名。
- cache:配置给定命名空间的缓存。
- cache-ref:从其他命名空间引用缓存配置。
- resultMap:用来描述数据库结果集和对象的对应关系。
- sql:可以重用的SQL块,也可以被其他语句引用。通常是存放一些公用性的SQL。
- insert:映射插入语句。
- update:更新映射语句。
- delete:删除映射语句。
- select:映射查询语句。
xml方式
九个顶级映射元素对应标签:
<mapper namespace="com.tian.mybatis.mapper.UserMapper">
<resultMap id="" type=""></resultMap>
<sql id=""></sql>
<cache blocking="" ></cache>
<cache-ref namespace=""></cache-ref>
<select id="selectUserById"></select>
<insert id="insert" ></insert>
<update id=""></update>
<delete id=""></delete>
</mapper>
select详解
可以看得出,后面可选项还是蛮多的。下面是官网对每项的解释。
select使用案例
<?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">
<mapper namespace="com.tian.mybatis.mapper.UserMapper">
<select id="selectUserById" resultType="com.tian.mybatis.entity.User" parameterType="int" >
select * from m_user where id = #{id}
</select>
</mapper>
- id必须在这个Mapper中是唯一的,可以被用来引用这条语句 ,这个id必须与之对应的是XxxMapper.java中的方法,必须是一一对应。
- 返回类型:User类型,resultType:查询语句返回结果类型的完全限定名或别名。别名使用方式和parameterType是一样的。
- 参数:整形,表示查询语句传入参数的类型和完全限定名或别名。支持基础数据类型和复杂数据类型。
#{参数名}:告诉MyBatis生成的PreparedStatement参数,相对于JDBC中,该参数被标识为‘?’。
别名与参数映射类型如下:
返回类型中别名的使用,注意:
如果是我们的entity类,那么resultType是无法使用别名的,只能使用resultMap才可以使用别名。
<?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">
<mapper namespace="com.tian.mybatis.mapper.UserMapper">
<resultMap id="User" type="com.tian.mybatis.entity.User"/>
<select id="selectUserById" resultMap="User" parameterType="int" >
select * from m_user where id = #{id}
</select>
</mapper>
但是如果使用的上面映射表里,也可以直接使用别名。
数据库里有两条数据:
UserMapper.xml
<?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">
<mapper namespace="com.tian.mybatis.mapper.UserMapper">
<select id="countUser" resultType="int">
select count(1) from m_user
</select>
</mapper>
UserMapper.java
import com.tian.mybatis.entity.User;
public interface UserMapper {
int countUser();
}
测试类:
public class MybatisApplication {
public static final String URL = "jdbc:mysql://localhost.com:3306/mblog?useUnicode=true";
public static final String USER = "root";
public static final String PASSWORD = "123456";
public static void main(String[] args) {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
SqlSession sqlSession = null;
try {
inputStream = Resources.getResourceAsStream(resource);
//工厂模式
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sql操作会话
sqlSession = sqlSessionFactory.openSession();
//构造对象(这里比较特殊,这里构造对象的方式后面会专门分享)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//查询统计
System.out.println(userMapper.countUser());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
sqlSession.close();
}
}
}
输出:2
当数据库表中的字段名和我们entity中的字段名不一致,怎么处理?
在实际开发中,这种常见是在所难免。我们可以使用下面的这种方式解决。
实体类User
public class User {
private Integer id;
private String userName;
private Integer age;
//set get toString方法这里就不贴了
}
UserMapper.xml文件内容:
<?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">
<mapper namespace="com.tian.mybatis.mapper.UserMapper">
<resultMap id="User" type="com.tian.mybatis.entity.User">
<id column="id" property="id"/>
<result column="name" property="userName"/>
</resultMap>
<select id="selectUserById" resultMap="User" parameterType="int" >
select * from m_user where id = #{id}
</select>
</mapper>
- type:对应的是我们的实体类,全路径名。
- id:可以理解为别名。
- id:唯一标识,此id值用于select元素resultMap属性的引用。
- column:对应我们数据库表中的字段名称。
- property:对应我们的实体类的属性,比如:User中的属性userName,要和数据库表m_user中的name对应。
- result:标识一些简单属性,其中column属性代表数据库的字段名,property代表查询出来的字段名映射到实体类的某个属性。
继续使用我们前面的测试类进行测试:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper.selectUserById(1));
输出:User{id=1, userName='tian', age=22}
注意:实体类的get set 和toString()方法这里给省略, 希望大家在使用的使用,使用快捷键很简单的就搞定了。
上面提到过resultType和resultMap,那么他们两到底有什么区别呢?
resultType和resultMap 有什么区别?
- resultType:直接表示返回类型, 包括基本数据类型和复杂数据类型。
- resultMap:外部resultMap定义的引用,通过对应的外部resultMap的id,表示结果映射到哪个resultMap上,一般用于字段名和属性名不一致的情况,或者需要做复杂的联合查询以便自由控制映射结果。
两者的关联
当进行查询时,查询出来的每个字段都会放在一个Map里,当查询元素返回属性是resultType的时候,会将键值对取出赋所指定的属性。其实MyBatis的每个查询映射的返回类型都是resultMap,只是当我们使用resultType的时候,会自动把对应的值赋给所指定的对象属性,当使用resultMap时候,因为map不是很好的表示领域,我们就进一步的转化为对应的实体对象。resultMap主要作用于复杂的联合查询上。
resultMap的自动映射级别:默认级别为PARTIAL,也可以在settings更改值。
注意:resultType和resultMap本质是一样的,都是Map数据结构,但是二者不能同时存在。
增删改案例
insert
从这里可以知道,关于增加insert是没有返回值类型可以让我们指定的。默认返回int类型。
<insert id="insert" parameterType="com.tian.mybatis.entity.User">
INSERT INTO m_user(`name`,age) VALUES ( #{userName},#{age})
</insert>
对应Mapper中的方法
int insert(User user);
另外的update和delete类似,这里就没有必要逐一演示了。
注解方式
九个顶级映射元素对应注解:
其他部分注解是配合九个注解进行使用的。
select注解
把本地的UserMapper.xml删掉,然后改一下mybatis-config.xml,把其中的UserMapper.xml给注释掉。添加
<mapper class="com.tian.mybatis.mapper.UserMapper"/>
UserMapper.java添加注解
public interface UserMapper {
@Select("select * from m_user where id = #{id}")
User selectUserById(Integer id);
}
再次测试
User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1);
System.out.println(user);
输出:
User{id=1, userName='null', age=22}
从输出内容看到,userName为null,这也是因为和数据库表格中的字段name不一致导致的,那么如何处理呢?
这么搞,再添加一个注解:
public interface UserMapper {
@Select("select * from m_user where id = #{id}")
@Results( @Result(column = "name",property = "userName"))
User selectUserById(Integer id);
}
输出:
User{id=1, userName='tian', age=22}
这样也就是在使用注解的时候,处理实体属性名和数据库表字段名不一样的问题的办法。
insert、update、delete同样也可以使用注解来搞定了。
@Insert、@Update、@Delete配上相应的SQL语句。
注解和xml是否可以共存?
<update id="updateAuthorIfNecessary">
update m_user
<trim prefix="SET" suffixOverrides=",">
<if test="userName != null and userName != ''">
`name` = #{userName},
</if>
<if test="gender != null and gender != 0">
gender = #{gender},
</if>
<if test="age != null and age != 0">
age = #{age},
</if>
</trim>
where id=#{id}
</update>
同时在UserMapper.java中的方法上添加注解
@Update("update m_user set `name` = #{userName},gender = #{gender},age = #{age} where id=#{id}")
int updateAuthorIfNecessary(User user);
再次中子星的时候回报异常的:
nested exception is java.lang.IllegalArgumentException:
Mapped Statements collection already contains value for com.tian.mybatis.mapper.UserMapper.updateAuthorIfNecessary.
please check file [D:\workspace\my_code\mybatis\target\classes\mapper\UserMapper.xml] and com/tian/mybatis/mapper/UserMapper.java (best guess)
大致意思就是说,已经存在了,即就是不能同时使用xml和注解。二者选其一。
xml可以和注解结合使用,但是得保证同一个方法不能同时存在xml和注解。
建议
简单的sql处理可以使用注解,复杂的sql使用xml。但是实际工作还得看你待的项目中有没有对这个进行规范化。
在项目中无非就三种:
1.全部必须使用xml方式。
2.全部必须使用注解方式。
3.可以同时使用xml和注解。
高级映射
association
映射到JavaBean的某个复杂的”数据类型”属性,仅处理一对一的关联关系。
<resultMap type="com.tian.mybatis.entity.User" id="userMapRole">
<id column="id" property="id" />
<result column="name" property="userName" />
<result column="age" property="age" />
<association property="role" javaType="UserRole">
<id column="id" property="id" />
<result column="roleName" property="roleName" />
</association>
</resultMap>
association的属性节点:
- property:映射数据库列的实体对象属性名。
- javaType:完整的java类名和限定名。propert所映射的属性的类型。
子元素
- id:一般为映射主键,可以提高性能。
- result:
- column:映射的数据库的字段名。
- property:映射的数据列对应的实体对象属性。
collection
映射到JavaBean的某个复杂的”数据类型”属性,这个属性是一个集合列表,处理一对多的关联关系。
<resultMap type="com.tian.mybatis.entity.User" id="userMapAddress">
<id column="id" property="id"/>
<result column="name" property="userName"/>
<collection property="lists" ofType="UserAddress">
<id column = "id" property = "id">
<result column="addressDesc" property="addressDesc"/>
</collection>
</resultMap>
ofType:完整的Java类名和限定名。propert所映射的属性的类型。
其余和association基本一致。
association和collection都具备延迟加载功能。
延迟加载:先从单表查询,需要时再查关联表,大大的提高了数据库性能,因为相对来说单表查询比多表查询要快。
xml和注解的关系
上面我们已经讲了两种方式的实现,下面来对比一下,两种方式的关系:
xml方式
必须有个一个XxxMapper.xml与之对应,方法名对应xml中的id,方法入参和方法出参都必须对应起来,很容易出问题。我们在开发的时候有的是可以使用代码生成器生成,但是有的是必须自己手写,有的公司也是要求必须手写,所以这里需要注意。
注解方式
不需要XxxMapper.xml文件,只需要在对应XxxMapper.java中的方法上加上注解就搞定了,但是这里是有坑的。毕竟把sql放到了我们的Java代码里了。
优缺点
xml方式: 增加了xml文件,修改麻烦,条件不确定(ifelse判断),容易出错,特殊转义字符比如大于小于 。
注解方式:复杂sql不好用,搜集sql不方便,管理不方便,修改需重新编译
总结
本文讲述了Mybatis的两种映射方式,以及一些注意点,一些关系和区别。
实体属性名和数据库表字段名不一样的情况下,xml和注解分别是如何处理的。resultType和resultMap的区别。
- 上一篇:您的网站需要XML站点地图吗?
- 下一篇:XML文档篇(二):认识 xsd 文档
相关推荐
- 我把家搬进了NAS?家庭资产数字化革命,现在连袜子都有编号了!
-
本内容来源于@什么值得买APP,观点仅代表作者本人|作者:羊刀仙家里东西一多,总有一种“我记得我有这个,但我不知道放哪了”的错觉。...
- Mega Run第3关通关攻略-跳上高空(mega运动)
-
错过火炮等于失败,这是MegaRun在上一关中给玩家的一点小挑战,那在后面的关卡中,这中挑战会给你造成什么困难呢?具体请看MegaRun第3关通关攻略-跳上高空。MegaRun第3关在一开始我...
- Axure高保真教程:中继器表格自动合计模板
-
编辑导语:合计作为日常使用频率比较高的一个功能,但在Axure里面传统的表格如果做合计是很麻烦的,遇到数据多的时候很耗费时间,那么该如何优化,提高工作效率?本文以中继器表格为核心,教大家如何制作一个自...
- 多角色登录原型(分角色登录)
-
编辑导读:多角色登录是很多系统都需要具备的功能,例如在招聘网站里,登录的角色包括、求职者、招聘企业的hr、猎头、内部员工等等。本文作者分享了如何在Axure里面制作多角色登录的原型模板,希望对你有帮助...
- 利用Axure+js创建可配置地图页面(axure地址选择)
-
编辑导语:如何利用Axure实现自定义地图展示?本篇文章里,作者结合Axure与高德地图,对如何在Axure中设置相应参数、进而预览时实现自定义地图展示效果的操作流程进行了示范和总结,一起来看一下。本...
- 纬地智能模板的一些基础与概念(纬地智能模板的一些基础与概念是什么)
-
对于公路及相关土木工程的勘测设计工作,虽然基础的理论和方法是基本相同的,但是受到各国家、地区文化、制图习惯等方面因素的影响,不同地域公路勘测设计的习惯和表达方式有着很大的差异,当然语言方面的不同和差...
- WPF界面开发第三方控件入门指南——菜单项
-
点击“了解更多”获取工具DevExpressWPFSubscription拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强...
- 鸿蒙开发:自定义一个搜索模版(鸿蒙系统怎么添加百度搜索条)
-
前言代码案例基于Api13。...
- 简单介绍一下前端各框架中的模板标签
-
在各大前端框架、小程序中,此类标签的作用主要是用来帮助我们包裹多个元素。在浏览器实际渲染中会将其移除只渲染其包裹的DOM元素,所以说不会增加额外的DOM节点...
- 法媒:简单的几个步骤让你的运动鞋更加炫酷
-
【环球网综合报道】有没有觉得自己的运动鞋样式单调,希望它变得更加炫酷?法媒《ELLE》推荐了一种简单易行的装饰方法,让您的运动鞋更加时尚。制作前,您需要准备一张细毡子、一张闪光热胶合布、胶水、两个银夹...
- Blazor 代码隐藏(blazor 操作dom)
-
Razor组件通常是在单个.razor文件中创作的,这样就存在页面中包含html代码和后台代码(@code标记指定的代码)。如下...
- DevExpress WPF入门指南:DXBars, DXRibbon中使用MVVM的两种方式
-
你也可以下载Universal安装包或者到DevExpress中文网查看更多示例和教程哦本文档介绍在DXBars,DXRibbon和GalleryControl这三个控件中使用MVVM框架的...
- 干货,Uploadfive插件上传,Python接收存储
-
在Web开发工作中,经常遇到上传需求,上传照片,文件等,网上的上传插件有很多,我使用的是一款H5上传插件Uploadfive,与之对应的是Uploadify,后者是基于Flash的,不过现在越来越多的...
- 用DevExpress实现基于HTML&CSS的桌面应用程序的UI(二)
-
DevExpressWinForm拥有180+组件和UI库,能为WindowsForms...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- characterencodingfilter (33)
- getmonth (34)
- label换行 (33)
- android studio 3 0 (34)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- xmlhttp (35)
- mysql更改密码 (34)
- 权限777 (33)
- htmlposition (33)
- 学校网站模板 (34)
- textarea换行 (34)
- 轮播 (34)
- asp net三层架构 (38)
- bash (34)