Mybatis实践笔记-去XML化的注解开发

文章内容输出来源:拉勾教育Java高薪训练营

介绍

Mybatis使用注解开发,可以减少编写XML文件,对于不复杂的数据逻辑处理也是比较简单适用。
本文演示Mybatis使用注解开发的增删改查操作。

注解介绍

  • @Insert:插入

  • @Update:更新

  • @Delete:删除

  • @Select:查询

  • @Result:封装结果集。对应xml文件中的<resultMap>中的<result>子标签

    • id:是否主键字段
    • column:数据库列名
    • property:属性名
    • one:一对一@One注解
    • many:一对多@Many注解

    如果列和属性的名称一样,则可以省略@result,mybatis会自动映射

  • @Results:多个封装结果集,与@Result一起使用。对应xml文件中的<resultMap>标签

  • @ResultMap:引用映射结果集,减少冗余

    eg:@ResultMap(value="studentMap")。其中value值为@Results中定义的id属性

  • @One:一对一结果集封装。对应xml文件中的<association>标签

    • select:指定多表查询的mapper
    • fetchType:加载方式,会覆盖全局的配置参数lazyLoadingEnabled
    • column:关联的外键ID
    • property:属性名

    fetchType:FetchType.EAGER表示立即加载,FetchType.LAZY表示延迟加载
    eg:@Result(column=" ",property="",one=@One(select=""))

  • @Many:一对多结果集封装。对应xml文件中的<collection>标签

    • select:指定多表查询的mapper
    • fetchType:加载方式,会覆盖全局的配置参数lazyLoadingEnabled
    • column:关联的外键ID
    • property:属性名
    • javaType:属性的类型,一般为List.class

    eg:@Result(property="",column="",javaType=List.class,many=@Many(select=""))

  • @Options:这个注解对应映射语句中的属性配置。常用属性如下:

    • useCache=true,
    • flushCache=false,
    • resultSetType=FORWARD_ONLY,
    • statementType=PREPARED,
    • fetchSize= -1
    • timeout=-1 ,
    • useGeneratedKeys=false
    • keyProperty="id"
  • @Param:参数注解

    当需要多个参数时,此注解用于给每一个参数定义名称。否则就会被以它们的顺序位置命名,如#{1}、#{2}等。
    使用@Param(“person”),SQL中参数解析就可以使用#{person}

  • @SelectKey:插入后,获取id的值

    eg:@SelectKey(statement = "select last_insert_id()" ,keyProperty = "id",keyColumn = "id",resultType = int.class,before = false)
    其中before属性,默认是true,在执行插入语句之前,执行select last_insert_id()。如果设置为flase,则在插入这个语句之后,执行select last_insert_id()
    在已经被@Insert/@InsertProvider/@Update/@UpdateProvider注解了的方法上使用才有效

  • @InsertProvider、@DeleteProvider、@UpdateProvider、@SelectProvider:用于生成插入、删除、更新、查询的SQL语句

    eg:@SelectProvider(type = SqlProvider.class, method = "selectUser")

示例

一、开始之前的配置

项目代码链接:mybatis_demo_01_annoation

1、基于order订单表和user表的操作,两张表的实体如下

  • OrderEntity
public class OrderEntity {
    private Integer id;
    private Integer userId;
    private BigDecimal amount;
    //订单关联的用户
    private UserEntity user;
    //ignore setter/getter
}
  • UserEntity
public class UserEntity {
    private Integer id;
    private String name;
    //用户关联的订单数据
    private List<OrderEntity> orders;
    //ignore setter/getter
}    

2、创建OrderDao和UserDao接口

3、在mybatis配置文件上配置对应的mapper,或者直接配置mapper所在的package包路径

<configuration>
    <mappers>
        <!--<mapper class="com.yyh.demo.dao.OrderDao"/>
        <mapper class="com.yyh.demo.dao.UserDao"/>-->
        <package name="com.yyh.demo.dao"/>
    </mappers>
</configuration>

4、创建OrderTest和UserTest的单元测试类

二、新增订单数据

  • 多参数新增订单
/**
  * 多参数添加订单数据
  * @param userId 用户ID
  * @param amount 金额
  * @return 返回值大于0表示插入成功
  */
@Insert("INSERT INTO `order`(user_id, amount) VALUES(#{userId}, #{amount})")
int insert(@Param("userId") Integer userId, @Param("amount") BigDecimal amount);
  • 实体参数新增订单
/**
    * 实体参数添加订单数据
    * @param order 订单实体
    * @return 返回值大于0表示插入成功
    */
@Insert("INSERT INTO `order`(user_id, amount) VALUES(#{order.userId}, #{order.amount})")
int insertWithEntity(@Param("order") OrderEntity order);
  • 实体参数新增订单,并返回新增的订单ID
/**
    * 实体参数添加订单数据,并返回订单ID
    * @param order 订单实体
    * @return 返回值大于0表示插入成功
    */
@Insert("INSERT INTO `order`(user_id, amount) VALUES(#{order.userId}, #{order.amount})")
@Options(useGeneratedKeys = true, keyProperty = "order.id", keyColumn = "id")
int insertWithEntityAndReturnId(@Param("order") OrderEntity order);

三、更新订单数据

  • 多参数更新订单金额
/**
    * 更新某订单的金额
    * @param id 订单ID
    * @param amount 金额
    * @return 返回值大于0表示更新成功
    */
@Update("UPDATE `order` SET amount=#{amount} WHERE id=#{id}")
int updateAmount(@Param("id") Integer id, @Param("amount") BigDecimal amount);
  • 实体参数更新订单金额
/**
    * 更新某订单的金额
    * @param order 订单实体
    * @return 返回值大于0表示更新成功
    */
@Update("UPDATE `order` SET amount=#{order.amount} WHERE id=#{order.id}")
int updateAmountWithEntity(@Param("order") OrderEntity order);

四、删除订单数据

/**
    * 根据订单ID删除订单
    * @param id 订单ID
    * @return 返回值大于0表示删除成功
    */
@Delete("DELETE FROM `order` WHERE id=#{id}")
int delete(@Param("id") Integer id);

五、查询全部订单数据

@Select("SELECT * FROM `order`")
List<OrderEntity> selectList();

六、查询单条订单数据

/**
    * 根据订单ID查询订单数据
    * @param id 订单ID
    * @return
    */
@Select("SELECT * FROM `order` WHERE id=#{id}")
OrderEntity selectOne(@Param("id") Integer id);

七、查询订单以及关联的用户数据

  • 联合查询
/**
    * 获取订单数据以及关联的用户信息
    * @param id 订单ID
    * @return
    */
@Select("SELECT t1.id,t1.amount,t1.user_id,t2.name as user_name FROM `order` t1,user t2 where t1.user_id=t2.id AND t1.id=#{id}")
@Results({
        @Result(id=true, column = "id", property = "id"),
        @Result(column = "amount", property = "amount"),
        @Result(column = "user_id", property = "userId"),
        @Result(column = "user_id", property = "user.id"),
        @Result(column = "user_name", property = "user.name")
})
OrderEntity selectOneWithUser(Integer id);
  • 嵌套查询
/**
    * 获取订单数据以及关联的用户信息
    * @param id 订单ID
    * @return
    */
@Select("SELECT * FROM `order` WHERE id=#{id}")
@Results({
        @Result(id=true, column = "id", property = "id"),
        @Result(column = "amount", property = "amount"),
        @Result(column = "user_id", property = "user",
                javaType = UserEntity.class, one = @One(select = "com.yyh.demo.dao.UserDao.selectOne"))
})
OrderEntity selectOneWithUser2(Integer id);

八、查询用户以及关联的订单数据

  • 嵌套查询,延迟加载
/**
    * 获取某用户的数据以及关联订单数据。延迟加载
    * @param id
    * @return
    */
@Select("select * from user where id=#{id}")
@Results({
        @Result(id=true, column = "id", property = "id"),
        @Result(column = "name", property = "name"),
        @Result(property = "orders", column = "id",
                javaType = List.class, many = @Many(select = "com.yyh.demo.dao.OrderDao.selectListByUser", fetchType = FetchType.LAZY))
})
UserEntity selectOneWithOrders(Integer id);
  • 嵌套查询
/**
    * 获取某用户的数据以及关联订单数据
    * @param id
    * @return
    */
@Select("select * from user where id=#{id}")
@Results({
        @Result(id=true, column = "id", property = "id"),
        @Result(column = "name", property = "name"),
        @Result(property = "orders", column = "id",
                javaType = List.class, many = @Many(select = "com.yyh.demo.dao.OrderDao.selectListByUser"))

})
UserEntity selectOneWithOrders2(Integer id);

九、使用动态SQL支持复杂条件的查询订单数据

  • 用script标签包裹,像xml文件编写脚本
public class OrderParam {
    //最小金额
    private BigDecimal minAmount;
    //最大金额
    private BigDecimal maxAmount;
    //用户ID
    private Integer userId;
    //ignore getter/setter
}   

/**
    * 复杂的查询订单数据
    * @param param
    * @return
    */
@Select({
        "<script>",
        "SELECT * FROM `order`",
        "<where> ",
        "<if test='null != userId'>and user_id=#{userId}</if>",
        "<if test='null != minAmount'>and amount &gt;= #{minAmount}</if>",
        "<if test='null != maxAmount'>and amount &lt;= #{maxAmount}</if>",
        "</where>",
        "</script>"
})
List<OrderEntity> selectListByCondition2(OrderParam param);
  • 用Provider去实现SQL拼接
  1. 示例1
public class OrderProvider {

    public String selectListByCondition(OrderParam param) {
        SQL sql = new SQL().SELECT("*").FROM("`order`");
        if(null != param.getUserId()) {
            sql.WHERE("user_id=#{userId}");
        }
        if(null != param.getMinAmount()) {
            sql.WHERE("amount>=#{minAmount}");
        }
        if(null != param.getMaxAmount()) {
            sql.WHERE("amount<=#{maxAmount}");
        }
        return sql.toString();
    }
}

 /**
    * 复杂的查询订单数据
    * @param param
    * @return
    */
@SelectProvider(type = OrderProvider.class, method="selectListByCondition")
List<OrderEntity> selectListByCondition(OrderParam param);
  1. 示例2
public class OrderProvider {
    public String selectListByCondition2(Map<String, Object> param) {
        SQL sql = new SQL().SELECT("*").FROM("`order`");
        if(null != param.get("userId")) {
            sql.WHERE("user_id=#{userId}");
        }
        if(null != param.get("minAmount")) {
            sql.WHERE("amount>=#{minAmount}");
        }
        if(null != param.get("maxAmount")) {
            sql.WHERE("amount<=#{maxAmount}");
        }
        return sql.toString();
    }
}

/**
    * 复杂的查询订单数据
    * @param userId 用户ID
    * @param minAmount 最小金额
    * @param maxAmount 最大金额
    * @return
    */
@SelectProvider(type = OrderProvider.class, method="selectListByCondition2")
List<OrderEntity> selectListByCondition3(@Param("userId") Integer userId, @Param("minAmount") BigDecimal minAmount, @Param("maxAmount") BigDecimal maxAmount);

如果接口有多个参数,在provider中要使用Map<String, Object>来进行接收

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269