MyBatis 注解模式

MyBatis注解模式

MyBatis 两种映射模式

MyBatis 有两种 SQL 语句映射模式:一种是基于XML,一种是基于注解

在这之前,我们都是使用基于 XML 映射文件这种模式实现数据库的各种操作。这次,我打算使用 MyBatis 注解的方式重新实现之前的数据库操作。

MyBatis 注解与 XML 映射文件不同之处在于不需要创建 XML 映射文件,SQL 语句映射是直接写在 Mapper 映射器接口方法上即可。

使用 MyBatis 注解后,需要修改 mybatis-config.xml 全局配置文件,如下:

 <!--配置映射路径-->
    <mappers>
        <!--配置 XML 映射文件路径-->
        <!-- <mapper resource="mappers/UserMapper.xml" />-->
        <mapper resource="mappers/GameMapper.xml" />
      
      	<!--配置注解接口路径-->
        <mapper class="mapper.UserMapper" />
    </mappers>

我们把配置的 UserMapper.xml 映射文件路径注释掉,然后添加配置注解 UserMapper 接口路径。如果不注释的话,MyBatis 会优先使用 XML 映射文件,也就是说注释不会生效。

注解实现 CURD + 动态 SQL 操作

以下是之前已创建好 UserMapper 映射器接口,里面的接口方法对应数据库的 CURD 操作。

package mapper;

import entity.UserEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @desc User映射器接口
 * @date 2020/6/19 上午8:59
 */
public interface UserMapper {
    /**
     * 根据年龄查询用户信息
     * @param age 年龄
     * @return user 用户实体集合
     */
    public List<UserEntity> selectUserByAge(@Param("age") int age);

    /**
     * 根据年龄和性别查询用户信息
     * @param userOne 获取年龄
     * @param userTwo 获取性别
     * @return 用户实体集合
     */
    public List<UserEntity> selectUserByAgeAndSex(@Param("userOne") UserEntity userOne,@Param("userTwo") UserEntity userTwo);

    /**
     * 根据姓名和年龄查询用户信息
     * @param name 姓名
     * @param user 获取年龄
     * @return
     */
    public List<UserEntity> selectUserByNameAndAge(@Param("name") String name, @Param("user") UserEntity user);

    /**
     * 查询所有用户信息
     * @return 用户实体集合
     */
    public List<UserEntity> selectUserAll();

    /**
     * 根据姓名集合查询用户
     * @param names 姓名集合
     * @return 用户实体集合
     */
    public List<UserEntity> selectUserByNameList(List<String> names);

    /**
     * 新增用户
     * @param user 用户实体
     * @return 影响行数
     */
    public int insertUser(UserEntity user);

    /**
     * 更新用户姓名
     * @param user 用户姓名
     * @return 影响行数
     */
    public int updateUser(@Param("id") int id,@Param("name") String name);

    /**
     * 根据姓名删除用户
     * @param name 用户姓名
     * @return 影响行数
     */
    public int deleteUserById(int id);
}

接下来,我直接在以上接口方法上使用 MyBatis 注解,以实现 SQL 语句映射,如下:

package mapper;

import entity.UserEntity;
import org.apache.ibatis.annotations.*;

import java.util.List;

/**
 * @author benjamin.xu
 * @desc User映射器接口
 * @date 2020/6/19 上午8:59
 */

public interface UserMapper {
    /**
     * 根据年龄查询用户信息
     * @param age 年龄
     * @return user 用户实体集合
     */
    @Select("select * from tb_user where age > #{age}")
    @Results(id="userMap", value={
            @Result(property = "id",column = "id",id = true),
            @Result(property = "userName",column = "user_name"),
            @Result(property = "password",column = "password"),
            @Result(property = "name",column = "name"),
            @Result(property = "age",column = "age"),
            @Result(property = "sex",column = "sex"),
            @Result(property = "birthday",column = "birthday"),
            @Result(property = "created",column = "created"),
            @Result(property = "updated",column = "updated")
    })
    public List<UserEntity> selectUserByAge(@Param("age") int age);

    /**
     * 根据年龄和性别查询用户信息
     * @param userOne 获取年龄
     * @param userTwo 获取性别
     * @return 用户实体集合
     */
    @Select("select * from tb_user where age > #{userOne.age} and sex = #{userTwo.sex}")
    @ResultMap("userMap")
    public List<UserEntity> selectUserByAgeAndSex(@Param("userOne") UserEntity userOne,@Param("userTwo") UserEntity userTwo);

    /**
     * 根据姓名和年龄查询用户信息
     * @param name 姓名
     * @param user 获取年龄
     * @return
     */
    @Select("select * from tb_user where name = #{name} and age < #{user.age}")
    @ResultMap("userMap")
    public List<UserEntity> selectUserByNameAndAge(@Param("name") String name, @Param("user") UserEntity user);

    /**
     * 查询所有用户信息
     * @return 用户实体集合
     */
    @Select("select * from tb_user")
    @ResultMap("userMap")
    public List<UserEntity> selectUserAll();

    /**
     * 根据姓名集合查询用户
     * @param names 姓名集合
     * @return 用户实体集合
     */
    @Select("<script>" +
            "select * from tb_user\n" +
            "  <where>\n" +
            "     <foreach item=\"name\" collection=\"list\"  index=\"index\" open=\"name in (\" separator=\",\" close=\")\">\n" +
            "        #{name}\n" +
            "     </foreach>\n" +
            "  </where>" +
            "</script>")
    @ResultMap("userMap")
    public List<UserEntity> selectUserByNameList(List<String> names);

    /**
     * 新增用户
     * @param user 用户实体
     * @return 影响行数
     */
    @Insert("insert into tb_user (id,user_name, password, name, age, sex, birthday, created, updated) values \n" +
            "(null,#{userName},#{password},#{name},#{age},#{sex},#{birthday},now(),now())")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    public int insertUser(UserEntity user);

    /**
     * 更新用户姓名
     * @param user 用户姓名
     * @return 影响行数
     */
    @Update("update tb_user set name=#{name} where id=#{id}")
    public int updateUser(@Param("id") int id,@Param("name") String name);

    /**
     * 根据姓名删除用户
     * @param name 用户姓名
     * @return 影响行数
     */
    @Delete("delete from tb_user where id=#{id}")
    public int deleteUserById(int id);
}

执行测试,结果和 XML 映射文件一样,我这里就不截图了。

注解说明:

  • @Insert:插入 SQL 语句注解,相当于 XML 映射文件的 insert 标记
  • @Options:该注解有两个属性:一个是 useGeneratedKeys 属性,设置为 true 表示启动自增主键回传,它只针对 insert 语句有效;一个是 keyProperty 属性,表示主键回传对应的实体类属性名
  • @Update:更新 SQL 语句注解,相当于 XML 映射文件的 update 标记
  • @Delete:删除 SQL 语句注解,相当于 XML 映射文件的 delete 标记
  • @Select:查询 SQL 语句注解,相当于 XML 映射文件的 select 标记
    • @Results:结果集映射注解,相当于 XML 映射文件的结果集映射 ResultMap 标记
      • @Result:实体类属性与数据表字段映射注解,相当于 XML 映射文件中 ResultMap 标记中的 result 子标记(id = true表示该字段是主键)
    • @ResultMap:引用 @Results 注解定义好的结果集映射

如果你已经掌握了 XML 映射文件,想要掌握以上这些注解就太 easy 了;因为和 XML 映射文件相比,无非就是把 SQL 语句映射换了一个地方罢了。

说白了,你可以直接把 XML 映射文件的 SQL 语句复制过来,放到对应的注解里面就完事了。

动态 SQL说明:

注解实现动态 SQL 和 XML 映射文件一样,也是把 SQL 语句复制过来,不过需要将其放到 script 标记里面,告诉 MyBatis 这是动态 SQL 语句,如下:

    @Select("<script>" +
            "  select * from tb_user\n" +
            "  <where>\n" +
            "     <foreach item=\"name\" collection=\"list\"  index=\"index\" 				        open=\"name in (\" separator=\",\" close=\")\">\n" +
            "        #{name}\n" +
            "     </foreach>\n" +
            "  </where>" +
            "</script>")
    @ResultMap("userMap")
    public List<UserEntity> selectUserByNameList(List<String> names);

大家可以看到,里面很多斜杠转义符,所以在注解中实现 动态 SQL,要特别小心,弄不好就会报错,搞得你焦头烂额。

注解实现一对一关联查询

这里需要先修改 mybatis-config.xml 全局配置文件,如下:

 <!--配置映射路径-->
    <mappers>
<!--        <mapper resource="mappers/UserMapper.xml" />-->
<!--        <mapper resource="mappers/GameMapper.xml" />-->
        <mapper class="mapper.UserMapper" />
        <mapper class="mapper.GameMapper" />
    </mappers>

目的是将原来配置的 XML 映射文件路径注释掉,然后添加注解接口路径。

以下是之前已创建好 GameMapper 映射器接口,如下:

package mapper;

import entity.GameEntity;
import entity.PlayerEntity;
import entity.RoleEntity;

/**
 * @desc 游戏映射器接口
 * @date 2020/7/10 下午6:20
 */
public interface GameMapper {
    /**
     * 根据角色ID查询账号信息
     * @param id 角色Id
     * @return 角色实体对象
     */
    public RoleEntity selectRoleById(int id);

    /**
     * 根据游戏名查询游戏账号
     * @param name 游戏名
     * @return 游戏实体类
     */
    public GameEntity selectGameByName(String name);

    /**
     * 根据玩家名查询游戏
     * @param name 玩家名
     * @return 玩家实体类
     */
    public PlayerEntity selectPlayerByName(String name);
}

接下来,我直接在以上接口方法上使用 MyBatis 注解,以实现 SQL 语句映射,如下:

    @Select("select r.*,a.* from tb_role as r join tb_account as a on r.account_id=a.id where r.id=#{id}")
    @Results(value = {
            @Result(property = "id",column = "id",id = true),
            @Result(property = "profession",column = "profession"),
            @Result(property = "rank",column = "rank"),
            @Result(property = "money",column = "money"),

            //一对一关联映射
            @Result(property = "account.id",column = "id"),
            @Result(property = "account.userName",column = "user_name"),
            @Result(property = "account.password",column = "password")
    })
    public RoleEntity selectRoleById(int id);

注:暂时没有找到 MyBatis 注解如何实现一对多以及多对多的关联查询的方法

注解实现一对一、一对多和多对多子查询

子查询需要用到两个注解:

  • @One:一对一映射注解,相当于 XML 映射文件的 association 标记
  • @Many:一对多映射注解,相当于 XML 映射文件的 collection 标记

我直接在以上接口方法上使用 MyBatis 注解,以实现 SQL 语句映射,如下:

package mapper;

import entity.AccountEntity;
import entity.GameEntity;
import entity.PlayerEntity;
import entity.RoleEntity;
import org.apache.ibatis.annotations.*;

/**
 * @desc 游戏映射器接口
 * @date 2020/7/10 下午6:20
 */
public interface GameMapper {
    /**
     * 根据角色ID查询账号信息
     * @param id 角色Id
     * @return 角色实体对象
     */
    @Select("select * from tb_role where id=#{id}")
    @Results(value = {
            @Result(property = "id",column = "id",id = true),
            @Result(property = "profession",column = "profession"),
            @Result(property = "rank",column = "rank"),
            @Result(property = "money",column = "money"),
            @Result(property = "account",column = "account_id",
                    one = @One(select = "selectAccountById"))
    })
    public RoleEntity selectRoleById(int id);

    @Select("select * from tb_account where id=#{id}")
    @ResultType(AccountEntity.class)
    public AccountEntity selectAccountById(int id);

    /**
     * 根据游戏名查询游戏账号
     * @param name 游戏名
     * @return 游戏实体类
     */
    @Select("select * from tb_game where name =#{name}")
    @Results(value = {
            @Result(property = "id",column = "id",id = true),
            @Result(property = "name",column = "name"),
            @Result(property = "type",column = "type"),
            @Result(property = "operator",column = "operator"),
            @Result(property = "accounts",column = "id",
                    many = @Many(select = "selectAccountById"))
    })
    public GameEntity selectGameByName(String name);

    /**
     * 根据玩家名查询游戏
     * @param name 玩家名
     * @return 玩家实体类
     */
    @Select("select * from tb_player where name = #{name}")
    @Results(value = {
            @Result(property = "id",column = "id",id = true),
            @Result(property = "name",column = "name"),
            @Result(property = "age",column = "age"),
            @Result(property = "sex",column = "sex"),
            @Result(property = "games",column = "id",
            many = @Many(select = "selectGameById"))
    })
    public PlayerEntity selectPlayerByName(String name);

    @Select(" select * from tb_game where id in (select game_id from tb_player_game where player_id=#{id})")
    @ResultType(GameEntity.class)
    public GameEntity selectGameById(int id);
}

我在接口中新创建了两个查询方法,selectAccountById 和 selectGameById,这两个方法和 XML 映射文件中作用相同,也就是用于子查询。

上一篇:php中封装的curl函数(抓取数据)


下一篇:C# 属性(Property)