文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Mybatis 中xml和注解映射,so easy啦

2024-12-03 15:52

关注

本文转载自微信公众号「Java后端技术全栈」,作者田维常。转载本文请联系Java后端技术全栈公众号。  

MyBatis 提供了XML配置和注解配置两种方式。今天就来搞搞这两种方式是如何实现的。

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

来自官网。

Mybatis映射九个顶级元素:

xml方式

九个顶级映射元素对应标签:

  1. "com.tian.mybatis.mapper.UserMapper"
  2.     "" type=""
  3.     ""
  4.     "" > 
  5.     ""
  6.     <select id="selectUserById">select
  7.     <insert id="insert" >insert
  8.     <update id="">update
  9.     <delete id="">delete
  10.  

select详解

可以看得出,后面可选项还是蛮多的。下面是官网对每项的解释。

select使用案例

  1. "1.0" encoding="UTF-8" ?> 
  2.         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
  3.         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"
  4. "com.tian.mybatis.mapper.UserMapper"
  5.     <select id="selectUserById"  resultType="com.tian.mybatis.entity.User" parameterType="int" > 
  6.         select * from m_user where id = #{id} 
  7.     select
  8.  

#{参数名}:告诉MyBatis生成的PreparedStatement参数,相对于JDBC中,改参数被标识为‘?’。

别名与参数映射类型如下:

返回类型中别名的使用,注意:

如果是我们的entity类,那么resultType是无法使用别名的,只能使用resultMap才可以使用别名。

  1. "1.0" encoding="UTF-8" ?> 
  2.         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
  3.         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"
  4. "com.tian.mybatis.mapper.UserMapper"
  5.     "User" type="com.tian.mybatis.entity.User"/> 
  6.     <select id="selectUserById"  resultMap="User" parameterType="int" > 
  7.         select * from m_user where id = #{id} 
  8.     select
  9.  

但是如果使用的上面映射表里,也可以直接使用别名。

数据库里有两条数据:

UserMapper.xml

  1. "1.0" encoding="UTF-8" ?> 
  2.         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
  3.         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"
  4. "com.tian.mybatis.mapper.UserMapper"
  5.     <select id="countUser" resultType="int"
  6.         select count(1) from m_user 
  7.     select
  8.  

UserMapper.java

  1. import com.tian.mybatis.entity.User
  2. public interface UserMapper { 
  3.     int countUser(); 

测试类:

  1. public class MybatisApplication { 
  2.     public static final String URL = "jdbc:mysql://localhost.com:3306/mblog?useUnicode=true"
  3.     public static final String USER = "root"
  4.     public static final String PASSWORD = "123456"
  5.     public static void main(String[] args) { 
  6.         String resource = "mybatis-config.xml"
  7.         InputStream inputStream = null
  8.         SqlSession sqlSession = null
  9.         try { 
  10.             inputStream = Resources.getResourceAsStream(resource); 
  11.             //工厂模式 
  12.             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
  13.             //获取sql操作会话 
  14.             sqlSession = sqlSessionFactory.openSession(); 
  15.             //构造对象(这里比较特殊,这里构造对象的方式后面会专门分享) 
  16.             UserMapper userMapper =  sqlSession.getMapper(UserMapper.class); 
  17.             //查询统计 
  18.             System.out.println(userMapper.countUser()); 
  19.         } catch (Exception e) { 
  20.             e.printStackTrace(); 
  21.         } finally { 
  22.             try { 
  23.                 inputStream.close(); 
  24.             } catch (IOException e) { 
  25.                 e.printStackTrace(); 
  26.             } 
  27.             sqlSession.close(); 
  28.         } 
  29.     } 

输出:2

当数据库表中的字段名和我们entity中的字段名不一致,怎么处理?

在实际开发中,这种常见是在所难免。我们可以使用下面的这种方式解决。

实体类User

  1. public class User { 
  2.     private Integer id; 
  3.     private String userName; 
  4.     private Integer age;  
  5.     //set get toString方法这里就不贴了 

UserMapper.xml文件内容:

  1. "1.0" encoding="UTF-8" ?> 
  2.         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
  3.         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"
  4. "com.tian.mybatis.mapper.UserMapper"
  5.     "User" type="com.tian.mybatis.entity.User"
  6.         column="id" property="id"/> 
  7.         column="name" property="userName"/> 
  8.      
  9.     <select id="selectUserById"  resultMap="User" parameterType="int" > 
  10.         select * from m_user where id = #{id} 
  11.     select
  12.  

继续使用我们前面的测试类进行测试:

  1. UserMapper userMapper =  sqlSession.getMapper(UserMapper.class); 
  2. System.out.println(userMapper.selectUserById(1)); 

输出:User{id=1, userName='tian', age=22}

注意:实体类的get set 和toString()方法这里给省略, 希望大家在使用的使用,使用快捷键很简单的就搞定了。

上面提到过resultType和resultMap,那么他们两到底有什么区别呢?

resultType和resultMap 有什么区别?

两者的关联

当进行查询时,查询出来的每个字段都会放在一个Map里,当查询元素返回属性是resultType的时候,会将键值对取出赋所指定的属性。其实MyBatis的每个查询映射的返回类型都是resultMap,只是当我们使用resultType的时候,会自动把对应的值赋给所指定的对象属性,当使用resultMap时候,因为map不是很好的表示领域,我们就进一步的转化为对应的实体对象。resultMap主要作用于复杂的联合查询上。

resultMap的自动映射级别:默认级别为PARTIAL,也可以在settings更改值。

注意:resultType和resultMap本质是一样的,都是Map数据结构,但是二者不能同时存在。

增删改案例

insert

从这里可以知道,关于增加insert是没有返回值类型可以让我们指定的。默认返回int类型。

  1. <insert id="insert" parameterType="com.tian.mybatis.entity.User"
  2.         INSERT INTO m_user(`name`,age) VALUES ( #{userName},#{age}) 
  3. insert

对应Mapper中的方法

  1. int insert(User user); 

另外的update和delete类似,这里就没有必要逐一演示了。

注解方式

九个顶级映射元素对应注解:

其他部分注解是配合九个注解进行使用的。

select注解

把本地的UserMapper.xml删掉,然后改一下mybatis-config.xml,把其中的UserMapper.xml给注释掉。添加

  1. "com.tian.mybatis.mapper.UserMapper"/> 

UserMapper.java添加注解

  1. public interface UserMapper { 
  2.     @Select("select * from m_user where id = #{id}"
  3.     User selectUserById(Integer id); 

再次测试

  1. User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1); 
  2. System.out.println(user); 

输出:

  1. User{id=1, userName='null', age=22} 

从输出内容看到,userName为null,这也是因为和数据库表汇中的字段name不一致导致的,那么如何处理呢?

这么搞,再添加一个注解:

  1. public interface UserMapper { 
  2.    @Select("select * from m_user where id = #{id}"
  3.    @Results( @Result(column = "name",property = "userName")) 
  4.    User selectUserById(Integer id); 

输出:

  1. User{id=1, userName='tian', age=22} 

这样也就是在使用注解的时候,处理实体属性名和数据库表字段名不一样的问题的办法。

insert、update、delete同样也可以使用注解来搞定了。

@Insert、@Update、@Delete配上相应的SQL语句。

注解和xml是否可以共存?

  1. <update id="updateAuthorIfNecessary"
  2.        update m_user 
  3.        "SET" suffixOverrides=","
  4.            "userName != null and userName != ''"
  5.                `name` = #{userName}, 
  6.             
  7.            "gender != null and gender != 0"
  8.                gender = #{gender}, 
  9.             
  10.            "age != null and age != 0"
  11.                age = #{age}, 
  12.             
  13.         
  14.        where id=#{id} 
  15.    update

同时在UserMapper.java中的方法上添加注解

  1. @Update("update m_user set  `name` = #{userName},gender = #{gender},age = #{age} where id=#{id}"
  2. int updateAuthorIfNecessary(User user); 

再次中子星的时候回报异常的:

  1. nested exception is java.lang.IllegalArgumentException: 
  2. Mapped Statements collection already contains value for com.tian.mybatis.mapper.UserMapper.updateAuthorIfNecessary.  
  3. 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。但是实际工作还得看你待的项目中有没有对这个进行规范化。

在项目中无非就三种:

全部必须使用xml方式。

全部必须使用注解方式。

可以同时使用xml和注解。

高级映射

association

映射到JavaBean的某个复杂的”数据类型”属性,仅处理一对一的关联关系。

  1. "com.tian.mybatis.entity.User" id="userMapRole"
  2.         column="id" property="id" /> 
  3.         column="name" property="userName" /> 
  4.         column="age" property="age" /> 
  5.         "role" javaType="UserRole"
  6.             column="id" property="id" /> 
  7.             column="roleName" property="roleName" /> 
  8.          
  9.  

association的属性节点:

子元素

collection

映射到JavaBean的某个复杂的”数据类型”属性,这个属性是一个集合列表,处理一对多的关联关系。

  1. "com.tian.mybatis.entity.User" id="userMapAddress"
  2.         column="id" property="id"/> 
  3.         column="name" property="userName"/> 
  4.         "lists" ofType="UserAddress">        
  5.             column = "id" property = "id"
  6.             column="addressDesc" property="addressDesc"/> 
  7.          
  8.      

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的区别。

 

来源:Java后端技术全栈内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯