乐趣区

关于mybatis:Mybatis-中xml和注解映射so-easy啦

关注“Java 后端技术全栈”

回复“面试”获取全套面试材料

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 settoString() 办法这里给省略,心愿大家在应用的应用,应用快捷键很简略的就搞定了。

下面提到过 resultTyperesultMap,那么他们两到底有什么区别呢?

resultType 和 resultMap 有什么区别?
  • resultType:间接示意返回类型,包含根本数据类型和简单数据类型。
  • resultMap:内部 resultMap 定义的援用,通过对应的内部 resultMap 的 id,示意后果映射到哪个 resultMap 上,个别用于字段名和属性名不统一的状况,或者须要做简单的联结查问以便自在管制映射后果。
两者的关联

当进行查问时,查问进去的每个字段都会放在一个 Map 里,当查问元素返回属性是 resultType 的时候,会将键值对取出赋所指定的属性。其实 MyBatis 的每个查问映射的返回类型都是 resultMap,只是当咱们应用resultType 的时候,会主动把对应的值赋给所指定的对象属性,当应用 resultMap 时候,因为 map 不是很好的示意畛域,咱们就进一步的转化为对应的实体对象。resultMap次要作用于简单的联结查问上。

resultMap的主动映射级别:默认级别为 PARTIAL,也能够在 settings 更改值。

留神 resultTyperesultMap实质是一样的,都是 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 的区别。

举荐浏览

6000 多字 | 秒杀零碎设计留神点【实践】

面试官:说说你对 Java 异样的了解

退出移动版