mybatis - 通用mapper

前端之家收集整理的这篇文章主要介绍了mybatis - 通用mapper前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

title: 玩转spring-boot-mybatis
date: 2019-03-11 19:36:57
type: "mybatis"
categories: mybatis #分类
tags: mybatis

作为持久层的ORM框架,目前在国内主流之一就是MyBatis,学会用它,用好它肯定是必备的功课

我会主要从下面几个方面入整理本篇博客

  1. 快速搭建快发环境
  2. 常见的注解
  3. 怎么玩?

一. 快速搭建开发环境

小插曲,添加测试模块的时候,引入junit模块和spring-boot-text-starter模块有先顺序,不然ide会报错...

坐标

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.0.4.RELEASE</version>
  5. <relativePath/><!-- lookup parent from repository -->
  6. </parent>
  7. <properties>
  8. <java.version>1.8</java.version>
  9. </properties>
  10. <dependencies>
  11. <!--web-->
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-web</artifactId>
  15. </dependency>
  16. <!--mybatis-->
  17. <dependency>
  18. <groupId>org.mybatis.spring.boot</groupId>
  19. <artifactId>mybatis-spring-boot-starter</artifactId>
  20. <version>1.3.2</version>
  21. </dependency>
  22. <!--通用mapper启动器-->
  23. <dependency>
  24. <groupId>tk.mybatis</groupId>
  25. <artifactId>mapper-spring-boot-starter</artifactId>
  26. <version>2.0.3</version>
  27. </dependency>
  28. <!--分页助手-->
  29. <dependency>
  30. <groupId>com.github.pageHelper</groupId>
  31. <artifactId>pageHelper-spring-boot-starter</artifactId>
  32. <version>1.2.5</version>
  33. </dependency>
  34. <!--MysqL-->
  35. <dependency>
  36. <groupId>MysqL</groupId>
  37. <artifactId>MysqL-connector-java</artifactId>
  38. <version>8.0.11</version>
  39. </dependency>
  40. <!--测试-->
  41. <!--先添加 junit 添加下面的text stater-->
  42. <dependency>
  43. <groupId>junit</groupId>
  44. <artifactId>junit</artifactId>
  45. <scope>text</scope>
  46. </dependency>
  47. <dependency>
  48. <groupId>org.springframework.boot</groupId>
  49. <artifactId>spring-boot-starter-test</artifactId>
  50. <scope>test</scope>
  51. </dependency>
  52. <dependency>
  53. <groupId>org.projectlombok</groupId>
  54. <artifactId>lombok</artifactId>
  55. </dependency>
  56. </dependencies>
  • 另外插一嘴---MysqL连接的版本适配

我现在用的云主机docker上的官方版MysqL,版本比较新,因此我的调整版本到 8以上,不然会报错说什么

  1. com.MysqL.jdbc.exceptions.jdbc4.MysqLNonTransientConnectionException: Could

配置文件:

  • 主要是配置数据库的连接,如果我们使用的是通用mapper,Mybatis可以做到零配置
  1. server:
  2. port: 8089
  3. spring:
  4. application:
  5. name: text-mybatis
  6. datasource:
  7. url: jdbc:MysqL://211.159.XXX.XXX:8888/changwu?serverTimezone=UTC&useUnijava=true&characterEncoding=utf-8&useSSL=false
  8. username: root
  9. password: 2424zcw..
  10. driver-class-name: com.MysqL.jdbc.Driver
  11. #输出SQL
  12. mybatis:
  13. configuration:
  14. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

启动类

  • 在这里告诉通用mapper我们的mapper包路径
  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import tk.mybatis.spring.annotation.MapperScan;
  4. @SpringBootApplication
  5. @MapperScan("com.changwu.mapper")
  6. public class MybatisApp {
  7. public static void main(String[] args) {
  8. SpringApplication.run(MybatisApp.class);
  9. }
  10. }

编写Mapper

  • 让我们自己的Mapper继承通用mapper,泛型是实体类名
  • 给它实体类名,就相当与告诉它了我们的表里的字段,不让他怎么会知道如何动态生成sql ?
  1. import tk.mybatis.mapper.common.Mapper;
  2. public interface MyMapper extends Mapper<MyBrand> {}

ok,到现在环境就搭建好了


二. 常见的注解

  • 这里的注解主要是作用在实体类上的注解,当我们撸起袖子写代码的时候,被给它难住喽,尴尬

情景1: 对于实体类

标记他对应那张表

  1. import javax.persistence.Table;
  2. @Table(name = "tb_brand")

情景2: 对于主键

大多数情况主键一般都叫id,bigint类型,没什么超级特殊的情况我们都希望他可以自己增长,下面两个注解都可以做到这件事,但是前提表id属性必须设置成 autoincreament,不然报错说,id不能不写

  • 注解1:
  1. import javax.persistence.GeneratedValue;
  2. import javax.persistence.GenerationType;
  3. import javax.persistence.Id;
  4. /*
  5. * 使用的是jpa的策略生成
  6. *JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO. 
  7. * TABLE:使用一个特定的数据库表格来保存主键。 
  8. * SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列
  9. * IDENTITY:主键由数据库自动生成(主要是自动增长型) 
  10. * AUTO:主键由程序控制。
  11. */
  12. @Id
  13. @GeneratedValue(strategy = GenerationType.IDENTITY)
  • 注解2:

直接使用Mybatis的原生注解

  1. @Id
  2. @Keysql(useGeneratedKeys = true)
  3. private Long id;

情景3:

我们都知道springMVC会把前端发送过来的json转化为我们的javaBean,因此我们的javaBean里面的属性名和前端发送的那个对象的属性名要意义对应的,这是规范!

设想,加入前端一顿收集数据,把商品的品牌信息和库存信息都发送过来了,只有关于品牌的javabean,数据接受不全怎么办? 没关系,下面的注解可以搞定

  • @Transient (意味短暂的)告诉mapper 他不是PO(持久层对象,Persistence Object)的属性,而且,springMvc还会把信息关于库存的信息,封装进去
  1. @Transient

情景4:

我们的pojo属性名,和数据库中的关键字重名怎么办?

@Column() 可以解决 数据库中的字段为数据库的关键字的问题

  1. @Column(name="`numeric`") //
  2. private Boolean numeric; //是否是数字类型

情景5 :

数据表中tingint(1) 对应的javaBean的属性咋写?

  1. tingint(1) // 它是boolean的同义词

情景5:

关于VO,如何选择性的返回给前端javaBean的属性?就比如说我们查询有没有这个用户,总不至于把密码,私人信息一块返回给前端吧?

  1. import com.fasterxml.jackson.annotation.JsonIgnore;
  2. @JsonIgnore

它是jackson的注解

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-annotations</artifactId>
  4. <version>RELEASE</version>
  5. <scope>compile</scope>
  6. </dependency>

三. 怎么玩?

 下面就是介绍常用的mapper的API

一. CRUD

  • 两种新增
  1. //会有选择性的新增,智能判断 brand里面有没有空的字段,有值,用这个值,没有值而使用数据库的默认值
  2. insertSelective(brand)
  3. // 假如前端提交过来的 brand里面的数据是全的,用词方法
  4. brandMapper.insert(brand);
  1. /**
  2. * 根据实体中的属性值进行查询查询条件使用等号
  3. * @param record
  4. * @return
  5. */
  6. @SelectProvider(type = BaseSelectProvider.class,method = "dynamicsql")
  7. List<T> select(T record);
  8. /**
  9. * 根据实体中的属性值进行查询查询条件使用等号
  10. * @param record
  11. * @return
  12. */
  13. @SelectProvider(type = BaseSelectProvider.class,method = "dynamicsql")
  14. List<T> select(T record);
  15. /**
  16. * 查询全部结果
  17. * @return
  18. */
  19. @SelectProvider(type = BaseSelectProvider.class,method = "dynamicsql")
  20. List<T> selectAll();
  21. /**
  22. * 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号
  23. * @param record
  24. * @return
  25. */
  26. @SelectProvider(type = BaseSelectProvider.class,method = "dynamicsql")
  27. T selectOne(T record);
  28. /**
  29. * 根据实体中的属性查询总数,查询条件使用等号
  30. * @param record
  31. * @return
  32. */
  33. @SelectProvider(type = BaseSelectProvider.class,method = "dynamicsql")
  34. int selectCount(T record);
  1. /**
  2. * 根据主键字段进行删除方法参数必须包含完整的主键属性
  3. * @param key
  4. * @return
  5. */
  6. @DeleteProvider(type = BaseDeleteProvider.class,method = "dynamicsql")
  7. int deleteByPrimaryKey(Object key);
  8. /**
  9. * 根据实体属性作为条件进行删除查询条件使用等号
  10. * @param record
  11. * @return
  12. */
  13. @DeleteProvider(type = BaseDeleteProvider.class,method = "dynamicsql")
  14. int delete(T record);

修改主要用到下面这个api

  1. /**
  2. * 根据主键更新属性不为null的值
  3. * @param record
  4. * @return
  5. */
  6. @UpdateProvider(type = BaseUpdateProvider.class,method = "dynamicsql")
  7. int updateByPrimaryKeySelective(T record);

看到这个方法有没有觉得很爽? 它根据主键,修改不为null的属性,意思就是说,我们把不需要修改的地方设置为null就好了
,这样看,前面需要我们一顿整,整啥呢? 结合实际的业务逻辑,把前端给交过来的数据最新的数据放到我们的bean中直接修改,把不需要修改属性设置为null,有属性可能需要直接删除,有的属性可能要去别的表中查询(别忘了加上事务 @Transactional )

  1. /**
  2. * 根据主键更新实体全部字段,null值会被更新
  3. * @param record
  4. * @return
  5. */
  6. @UpdateProvider(type = BaseUpdateProvider.class,method = "dynamicsql")
  7. int updateByPrimaryKey(T record);

这个方法和上面的神似

二 .分页,过滤(模糊查询),搜索

API

  1. mapper.selectByExample(example)

参照下面原生的sql.拼接查询条件

  1. select * from 表名
  2. where name like '% X %' or letter== 'x'
  3. order by id desc

逻辑

  1. public VO queryBrandByPage(Integer page,String key,Integer rows,String sortBy,Boolean desc) {
  2. //分页 -- 使用分页助手,在我们真正查询之前,调用这个下面的方法,开启分页查询,他很智能,会用mybatis的拦截
  3. // 对接下来要执行查询sql进行拦截,自动的在其后面拼接 limit语句
  4. pageHelper.startPage(page,rows); //当前页码,每页显示的数目
  5. //过滤 --key (StringUtils用的是comment lang3 下面的)
  6. // 过滤条件,key是前端用户传递进来的,可能仅仅是一个 小米,也可能是 小 --- 模糊查询
  7. /* select * from tb_brand
  8. where name like '% X %' or letter== 'x'
  9. order by id desc
  10. */
  11. Example example = new Example(Brand.class);
  12. if(StringUtils.isNotBlank(key)){ //不为空,过滤
  13. example.createCriteria().orLike("name","%"+key+"%").andEqualTo("letter",key.toUpperCase());
  14. // example.createCriteria().orLike("name","%"+key+"%").or
  15. }
  16. //排序
  17. if(StringUtils.isNotBlank(sortBy)) { //传递进来的排序不为空,设置我们的排序条件
  18. // 上面的 order by 可以帮我们生成,但是后面的 id desc 需要我们自己写
  19. // String orderByClause = "id desc" ; 写死了
  20. String orderByClause = sortBy + (desc ? " DESC " : " ASC "); //坑坑坑 注意要加上 空格 不然拼接完了 就是 orderBy idASC 而不是orderBy id ASC
  21. example.setOrderByClause(orderByClause);
  22. }
  23. //查询 获取到list,其实是 当前页的数据 page对象
  24. List<Brand> list = brandMapper.selectByExample(example);
  25. if (CollectionUtils.isEmpty(list)){
  26. throw new Exception ;
  27. }
  28. // 解析List
  29. PageInfo<Brand> pageInfo = new PageInfo<>(list);
  30. return new PageResult<Brand>(pageInfo.getTotal(),list);
  31. }

三 .自定义sql

Mybatis只能针对单表为我们生成sql,如果我们的需求是跨表操作,比如说涉及到两张表,我们就得去mapper里面自己写sql

原生sql

  1. select * from tb_brand b
  2. inner join tb_category_brand cb on b.id=cb.brand_id -- 去笛卡尔积
  3. where cb.category_id= ? ;

mapper

?用#{id} 取代

  1. @Select("select * from tb_brand b inner join tb_category_brand cb on b.id=cb.brand_id where cb.category_id=#{cid}")
  2. List<Brand> queryBrandByCid(@Param("cid") Long cid);

四 .拓展包--批量操作

注意他的包啊!

  1. import tk.mybatis.mapper.additional.idlist.IdListMapper;
  2. public interface Mapper extends Mapper<Category>,IdListMapper<Category,Long> {}
  1. /**
  2. * 根据主键字符串进行查询,类中只有存在一个带有@Id注解的字段
  3. * @param idList
  4. * @return
  5. */
  6. @SelectProvider(type = IdListProvider.class,method = "dynamicsql")
  7. List<T> selectByIdList(@Param("idList") List<PK> idList);
  8. /**
  9. * 根据主键字符串进行删除,类中只有存在一个带有@Id注解的字段
  10. * @param idList
  11. * @return
  12. */
  13. @DeleteProvider(type = IdListProvider.class,method = "dynamicsql")
  14. int deleteByIdList(@Param("idList") List<PK> idList);
  • 批量插入:
  1. import tk.mybatis.mapper.additional.insert.InsertListMapper;
  2. public interface BaseMapper<T> extends InsertListMapper<T> {}
  3. @RegisterMapper
  4. public interface InsertListMapper<T> {
  5. @InsertProvider(
  6. type = InsertListProvider.class,method = "dynamicsql"
  7. )
  8. int insertList(List<? extends T> var1);
  9. }

抽取出一个baseMapper,添加 @RegisterMapper 它才会被扫描到生效

  1. import tk.mybatis.mapper.additional.idlist.IdListMapper;
  2. import tk.mybatis.mapper.additional.insert.InsertListMapper;
  3. import tk.mybatis.mapper.annotation.RegisterMapper;
  4. import tk.mybatis.mapper.common.Mapper;
  5. @RegisterMapper
  6. public interface BaseMapper<T> extends IdListMapper<T,Long>,Mapper<T>,InsertListMapper<T> {
  7. }

猜你在找的Mybatis相关文章