MyBatis 三剑客之一 通用 Mapper

官方文档地址:https://github.com/abel533/Mapper

依赖

<dependency>
  <groupId>tk.mybatis</groupId>
  <artifactId>mapper-spring-boot-starter</artifactId>
  <version>版本号</version>
</dependency>

对象关系映射

简单映射

数据库表的字段名和实体类的属性名相同,这时候只需要给主键字段添加 @Id 标识即可

复杂映射

通常情况下,数据库表的字段名和实体类的属性名并不完全相同,数据库表的字段名用下划线分隔单词,而Java实体类使用驼峰命名法,

通用 Mapper 中,默认情况下是将实体类字段按照驼峰转下划线形式的表名列名进行转换。
比如数据库字段名为 user_name,映射到实体类属性名为 userName

注解

通用 Mapper 使用了 JPA 的注解和自己定义的注解做对象关系映射,下面对这些注解一一介绍

@NameStyle 注解(Mapper)

这个注解作用在实体类上,优先级高于对应的 style 全局配置。
注解支持以下几个选项:

  • normal:原值
  • camelhump:驼峰转下划线
  • uppercase:转换为大写
  • lowercase:转换为小写
  • camelhumpAndUppercase:驼峰转下划线大写形式
  • camelhumpAndLowercase:驼峰转下划线小写形式

使用时直接在类上配置即可,例如:

@NameStyle(Style.camelhumpAndUppercase)
public class Country

配置该注解后,通用 Mapper 在动态生成 sql 的时候,会将形如 userName 的属性转换为表中的 USER_NAME 字段

@Table 注解(JPA)

@Table 注解可以配置 name,catalogschema 三个属性,配置 name 属性后,直接使用提供的表名,不再根据实体类名进行转换。
其他两个配置中,同时配置时,catalog 优先级高于 schema,也就是只有 catalog 会生效。
配置示例如下:

@Table(name = "sys_user")
public class User

User 实体映射到 sys_user 表。

@column 注解(JPA)

@Column 注解支持 nameinsertableupdateable 三个属性。

  • name 配置映射的列名
  • insertable 对提供的 insert 方法有效,如果设置 false 就不会出现在 SQL 中
  • upodateable 对提供的 update 方法有效,设置为 false 后不会出现在 SQL 中
    当使用关键词时,还会有下面的用法:
@Column(name = "`order`")
private String order;
@ColumnType 注解(Mapper)

该注解是通用 Mapper 用来代替 @Column 注解的,所以它的功能会更强大,推荐直接只用该注解。
且在通用 Mapper 中,该注解的优先级也比 @Column 要高。
除了支持 @Column 中的三个属性外,该注解还提供了 jdbcType 属性和 typeHandler 属性。
jdbcType 用于设置特殊数据库类型时指定数据库中的 jdbcType
typeHandler 用于设置特殊类型处理器,常见的是枚举。
通用 Mapper 提供的 CRUD 方法是没有 XML 文件的,所以就不能用在 XML 中为字段配置类型处理器方法配置,所以通用 Mapper 提供了这两个属性来自定义类型处理器。
用法如下:

@ColumnType(
        column = "countryname",
        jdbcType = JdbcType.VARCHAR,
        typeHandler = StringTypeHandler.class)
private String  countryname;
@Transient 注解(JPA)

一般情况下,实体中的字段和数据库表中的字段是一一对应的,但是也有很多情况我们会在实体中增加一些额外的属性,
这种情况下,就需要使用 @Transient 注解来告诉通用 Mapper 这不是表中的字段,在生成 SQL 是就不会把这些字段添加进去。
默认情况下,只有简单类型会被自动认为是表中的字段(可以通过配置中的 useSimpleType 控制)。

这里的简单类型不包含 Java 中的8种基本类型:

byte,short,int,long,float,double,char,boolean

这是因为在类中,基本类型会有默认值,而 MyBatis 中经常会需要判断属性值是否为空,所以不要在类中使用基本类型,否则会遇到莫名其妙的错误。

对于类中的复杂对象,以及 MapList 等属性不需要配置这个注解。
对于枚举类型作为数据库字段的情况下,需要看配置中的 enumAsSimpleType 参数。
配置示例:

@Transient
private String otherThings; //非数据库表中字段

我感觉这个注解会用不到,因为实体类有 PO,TO,VO,DTO 之分,各司其职,存在不是数据表中字段的属性的情况下,该实体类不能作为和数据库表映射的实体类,
而是其他的比如返回给前端的实体类 VO,通过 BeanUtils.copyProperties 方法在不同类型的实体类之间复制属性。

@Id 注解(JPA)

上面几个注解都涉及到映射,@Id 注解和映射无关,它是一个特殊的标记,用于标识数据库中的关键字段。
正常情况下,一个实体类中至少需要一个标记 @Id 注解的字段,存在关联主键时可以标记多个。
如果表中没有主键,类中就可以不标记。
当类中没有标记 @Id 注解的字段时,通用 Mapper 会理解为类中的所有字段是联合主键。使用所有的 ByPrimaryKey 相关的方法时,有 where 条件的地方,会将所有列作为条件。
配置示例:

@Id
private Integer id;

或者联合注解:

@Id
private Integer userId;
@Id
private Integer roleId;
@KeySql 注解(Mapper)

主键策略主机,用于配置如何生成注解。
这是通用 Mapper 的自定义注解,该注解的目的就是替换 @GeneratedValue 注解。
首先主键策略和数据库关系很大,有些数据库支持主键自增,而有些数据库只能通过序列来获得。
这里介绍支持主键自增的 Mysql 数据库,更详细的内容请看官网。
这种情况下,配置主键策略最简单。
用法如下:

@Id
@KeySql(useGeneratedKeys = true)
private Long id;

对应的 XML 代码:

<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    insert into country (id, countryname, countrycode)
    values (#{id},#{countryname},#{countrycode})
</insert>

@KeySql 注解源码:

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface KeySql {

    /**
     * 是否使用 JDBC 方式获取主键,优先级最高,设置为 true 后,不对其他配置校验
     *
     * @return
     */
    boolean useGeneratedKeys() default false;

    /**
     * 优先级第二,根据配置的数据库类型取回主键,忽略其他配置
     *
     * @return
     */
    IdentityDialect dialect() default IdentityDialect.NULL;

    /**
     * 取主键的 SQL
     *
     * @return
     */
    String sql() default "";

    /**
     * 生成 SQL,初始化时执行,优先级低于 sql
     *
     * @return
     */
    Class<? extends GenSql> genSql() default GenSql.NULL.class;

    /**
     * 和 sql 可以配合使用,默认使用全局配置中的 ORDER
     *
     * @return
     */
    ORDER order() default ORDER.DEFAULT;

    /**
     * Java 方式生成主键,可以和发号器一类的服务配合使用
     *
     * @return
     */
    Class<? extends GenId> genId() default GenId.NULL.class;

}

通过上面的注解,大家可以看到主要的 3 个参数的优先级,useGenerateKeys 优先级最高,其次是 dialect,最后是 sql
其中 order 只对 sql 方式有效。
全局主键
使用 genId 属性可以实现自定义主键生成的方式,也就是全局主键。
由源码可以看出该属性是一个 Class 类型,且必须是 GenId 接口的实现类,我们看一下 GenId 接口的源码:

public interface GenId<T> {
    class NULL implements GenId {
        @Override
        public Object genId(String table, String column) {
            throw new UnsupportedOperationException();
        }
    }

    T genId(String table, String column);
}

通过接口方法可以看出,在生成 Id 时,可以得到当前的表名和列名,我们可以使用这两个信息生成和表字段关联的 Id 信息,
也可以完全不使用这两个信息,生成全局的 Id。
使用 UUID 方式时,首先我们需要提供一个能产生 UUID 的实现类:

public class UUIdGenId implements GenId<String> {
    @Override
    public String genId(String table, String column) {
        return UUID.randomUUID().toString();
    }
}

我们只需要在注解中配置 @KeySql(genId = UUIDGenId.class) 即可,需要注意的是,如果你使用了 @keySql 提供的其他方式,
genId 就不会生效,genId 是所有方式中优先级最低的。

@Version 注解(Mapper)

@Version 是实现乐观锁的一个注解。
乐观锁实现中,要求一个实现类中只能有一个乐观锁字段。
想要使用乐观锁,只需要在实体类中,给乐观锁字段增加 @tk.mybatis.mapper.annotation.Version 注解。
例如:

public class User {
 	private Long id;
  	private String name;
    //...
    @Version
  	private Integer version;
  	//setter and getter
}

@Version 注解有一个 nextVersion 属性,默认值为默认的实现,默认实现如下:

package tk.mybatis.mapper.version;

import java.sql.Timestamp;

/**
 * @author liuzh
 * @since 3.5.0
 */
public class DefaultNextVersion implements NextVersion {

    @Override
    public Object nextVersion(Object current) throws VersionException {
        if (current == null) {
            throw new VersionException("当前版本号为空!");
        }
        if (current instanceof Integer) {
            return (Integer) current + 1;
        } else if (current instanceof Long) {
            return (Long) current + 1L;
        } else if (current instanceof Timestamp) {
            return new Timestamp(System.currentTimeMillis());
        } else {
            throw new VersionException("默认的 NextVersion 只支持 Integer, Long" +
                    " 和 java.sql.Timestamp 类型的版本号,如果有需要请自行扩展!");
        }
    }

}

默认实现支持 IntegerLongjava.sql.Timestamp,如果默认实现不能满足自己的需要,可以实现自己的方法,在配置注解时指定自己的实现即可。
支持的方法:

  • delete
  • deleteByPrimaryKey
  • updateByPrimaryKey
  • updateByPrimaryKeySelective
  • updateByExample
  • updateByExampleSelective
    这些方法在执行时会更新乐观锁字段的值或者使用乐观锁的值作为查询条件。

总结

该篇博客内容抄的通用Mapper官方的内容,只抄了常用的内容,并对内容排版做了修改。
博客的目的主要是为了加深记忆,文章里面也添加了一些自己的一些看法。介绍的注解只有 8 个,这 8 个是常用注解,也看出通用Mapper的使用非常简单。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis Plus提供了通用Mapper和Service,可以减少重复的CRUD操作代码,提高开发效率。 通用Mapper是指通过MyBatis Plus提供的基础Mapper接口和默认实现类,可以通过简单的方法调用完成常见的单表CRUD操作,无需手写SQL语句。这些方法包括insert、insertBatch、deleteById、deleteBatchIds、updateById、update、selectById、selectBatchIds、selectList、selectOne等等。使用通用Mapper可以大大简化DAO层的代码,提高开发效率。以下是一个使用通用Mapper的示例代码: ```java public interface UserMapper extends BaseMapper<User> { } ``` ```java @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { } ``` 通用Service是指通过MyBatis Plus提供的基础Service接口和默认实现类,可以通过简单的方法调用完成常见的单表CRUD操作,无需手写SQL语句。通用Service继承自通用Mapper,并且提供了一些额外的方法,如分页查询、批量插入、批量更新、批量删除等等。使用通用Service可以进一步简化Service层的代码,提高开发效率。以下是一个使用通用Service的示例代码: ```java public interface UserService extends IService<User> { } ``` ```java @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { } ``` 使用通用Mapper和Service需要注意的是,在实体类中需要使用注解@TableId来指定表的主键字段,以及注解@TableField来指定实体类属性和数据库表字段的映射关系。另外,如果需要使用分页查询,则需要在配置文件中配置分页插件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值