

mybatis - 通用mapper
source link: https://www.tuicool.com/articles/qUBfquB
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

title: 玩转spring-boot-mybatis
date: 2019-03-11 19:36:57
type: "mybatis"
categories: mybatis #分类名
tags: mybatis
---
作为持久层的ORM框架,目前在国内主流之一就是MyBatis,学会用它,用好它肯定是必备的功课
我会主要从下面几个方面入整理本篇博客
- 快速搭建快发环境
- 常见的注解
- 怎么玩?
一. 快速搭建开发环境
小插曲,添加测试模块的时候,引入junit模块和spring-boot-text-starter模块有先顺序,不然ide会报错...
坐标
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/><!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!--通用mapper启动器--> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.0.3</version> </dependency> <!--分页助手--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> <!--测试--> <!--先添加 junit 再添加下面的text stater--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>text</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
- 另外插一嘴---mysql连接的版本适配
我现在用的云主机docker上的官方版mysql,版本比较新,因此我的调整版本到 8 以上,不然会报错说什么
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could
配置文件:
- 主要是配置数据库的连接,如果我们使用的是通用mapper,Mybatis可以做到零配置
server: port: 8089 spring: application: name: text-mybatis datasource: url: jdbc:mysql://211.159.XXX.XXX:8888/changwu?serverTimezone=UTC&useUnijava=true&characterEncoding=utf-8&useSSL=false username: root password: 2424zcw.. driver-class-name: com.mysql.jdbc.Driver #输出sql mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
启动类
- 在这里告诉通用mapper我们的mapper包路径
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import tk.mybatis.spring.annotation.MapperScan; @SpringBootApplication @MapperScan("com.changwu.mapper") public class MybatisApp { public static void main(String[] args) { SpringApplication.run(MybatisApp.class); } }
编写Mapper
- 让我们自己的Mapper继承通用mapper,泛型是实体类名
- 给它实体类名,就相当与告诉它了我们的表里的字段,不让他怎么会知道如何动态生成sql ?
import tk.mybatis.mapper.common.Mapper; public interface MyMapper extends Mapper<MyBrand> {}
ok,到现在环境就搭建好了
二. 常见的注解
- 这里的注解主要是作用在实体类上的注解,当我们撸起袖子写代码的时候,被给它难住喽,尴尬
情景1: 对于实体类
标记他对应那张表
import javax.persistence.Table; @Table(name = "tb_brand")
情景2: 对于主键
大多数情况主键一般都叫id,bigint类型,没什么超级特殊的情况我们都希望他可以自己增长,下面两个注解都可以做到这件事,但是前提表id属性必须设置成 autoincreament , 不然报错说,id不能不写
- 注解1:
import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; /* * 使用的是jpa的策略生成器 *JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO. * TABLE:使用一个特定的数据库表格来保存主键。 * SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列 * IDENTITY:主键由数据库自动生成(主要是自动增长型) * AUTO:主键由程序控制。 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
- 注解2:
直接使用Mybatis的原生注解
@Id @KeySql(useGeneratedKeys = true) private Long id;
情景3:
我们都知道springMVC会把前端发送过来的json转化为我们的javaBean,因此我们的javaBean里面的属性名和前端发送的那个对象的属性名要意义对应的,这是规范!
设想,加入前端一顿收集数据,把商品的品牌信息和库存信息都发送过来了,只有关于品牌的javabean,数据接受不全怎么办? 没关系,下面的注解可以搞定
- @Transient (意味短暂的)告诉mapper 他不是PO(持久层对象,Persistence Object)的属性,而且,springMvc还会把信息关于库存的信息,封装进去
@Transient
情景4:
我们的pojo属性名,和数据库中的关键字重名怎么办?
@Column() 可以解决 数据库中的字段为数据库的关键字的问题
@Column(name="`numeric`") // private Boolean numeric; //是否是数字类型
情景5 :
数据表中tingint(1) 对应的javaBean的属性咋写?
tingint(1) // 它是boolean的同义词
情景5:
关于VO , 如何选择性的返回给前端javaBean的属性?就比如说我们查询有没有这个用户,总不至于把密码,私人信息一块返回给前端吧?
import com.fasterxml.jackson.annotation.JsonIgnore; @JsonIgnore
它是jackson的注解
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency>
三. 怎么玩?
下面就是介绍常用的mapper的API
一. CRUD
- 两种新增
//会有选择性的新增, 智能判断 brand里面有没有空的字段,有值,用这个值,没有值而使用数据库的默认值 insertSelective(brand) // 假如前端提交过来的 brand里面的数据是全的,用词方法 brandMapper.insert(brand);
- 简单查询
/** * 根据实体中的属性值进行查询,查询条件使用等号 * @param record * @return */ @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL") List<T> select(T record); /** * 根据实体中的属性值进行查询,查询条件使用等号 * @param record * @return */ @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL") List<T> select(T record); /** * 查询全部结果 * @return */ @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL") List<T> selectAll(); /** * 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号 * @param record * @return */ @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL") T selectOne(T record); /** * 根据实体中的属性查询总数,查询条件使用等号 * @param record * @return */ @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL") int selectCount(T record);
- 简单删除
/** * 根据主键字段进行删除,方法参数必须包含完整的主键属性 * @param key * @return */ @DeleteProvider(type = BaseDeleteProvider.class, method = "dynamicSQL") int deleteByPrimaryKey(Object key); /** * 根据实体属性作为条件进行删除,查询条件使用等号 * @param record * @return */ @DeleteProvider(type = BaseDeleteProvider.class, method = "dynamicSQL") int delete(T record);
- 如何玩修改?
修改主要用到下面这个api
/** * 根据主键更新属性不为null的值 * @param record * @return */ @UpdateProvider(type = BaseUpdateProvider.class, method = "dynamicSQL") int updateByPrimaryKeySelective(T record);
看到这个方法有没有觉得很爽? 它根据主键,修改不为null的属性,意思就是说,我们把不需要修改的地方设置为null就好了
,这样看,前面需要我们一顿整,整啥呢? 结合实际的业务逻辑,把前端给交过来的数据最新的数据放到我们的bean中直接修改,把不需要修改的属性设置为null,有属性可能需要直接删除,有的属性可能要去别的表中查询(别忘了加上事务 @Transactional )
/** * 根据主键更新实体全部字段,null值会被更新 * @param record * @return */ @UpdateProvider(type = BaseUpdateProvider.class, method = "dynamicSQL") int updateByPrimaryKey(T record);
这个方法和上面的神似
二 .分页,过滤(模糊查询),搜索
API
mapper.selectByExample(example)
参照下面原生的sql.拼接查询条件
select * from 表名 where name like '% X %' or letter== 'x' order by id desc
逻辑
public VO queryBrandByPage(Integer page, String key, Integer rows, String sortBy, Boolean desc) { //分页 -- 使用分页助手,在我们真正查询之前,调用这个下面的方法,开启分页查询,他很智能,会用mybatis的拦截器 // 对接下来要执行查询的sql进行拦截,自动的在其后面拼接 limit语句 PageHelper.startPage(page,rows); //当前页码,每页显示的数目 //过滤 --key (StringUtils用的是comment lang3 下面的) // 过滤条件,key是前端用户传递进来的,可能仅仅是一个 小米, 也可能是 小 --- 模糊查询 /* select * from tb_brand where name like '% X %' or letter== 'x' order by id desc */ Example example = new Example(Brand.class); if(StringUtils.isNotBlank(key)){ //不为空,过滤 example.createCriteria().orLike("name","%"+key+"%").andEqualTo("letter",key.toUpperCase()); // example.createCriteria().orLike("name","%"+key+"%").or } //排序 if(StringUtils.isNotBlank(sortBy)) { //传递进来的排序不为空,设置我们的排序条件 // 上面的 order by 可以帮我们生成, 但是后面的 id desc 需要我们自己写 // String orderByClause = "id desc" ; 写死了 String orderByClause = sortBy + (desc ? " DESC " : " ASC "); //坑坑坑 注意要加上 空格 不然拼接完了 就是 orderBy idASC 而不是orderBy id ASC example.setOrderByClause(orderByClause); } //查询 获取到list ,其实是 当前页的数据 page对象 List<Brand> list = brandMapper.selectByExample(example); if (CollectionUtils.isEmpty(list)){ throw new Exception ; } // 解析List PageInfo<Brand> pageInfo = new PageInfo<>(list); return new PageResult<Brand>(pageInfo.getTotal(),list); }
三 .自定义sql
Mybatis只能针对单表为我们生成sql,如果我们的需求是跨表操作,比如说涉及到两张表,我们就得去mapper里面自己写sql
原生sql
select * from tb_brand b inner join tb_category_brand cb on b.id=cb.brand_id -- 去笛卡尔积 where cb.category_id= ? ;
mapper
?用#{id} 取代
@Select("select * from tb_brand b inner join tb_category_brand cb on b.id=cb.brand_id where cb.category_id=#{cid}") List<Brand> queryBrandByCid(@Param("cid") Long cid);
四 .拓展包--批量操作
- 批量查询,批量删除
注意他的包啊!
import tk.mybatis.mapper.additional.idlist.IdListMapper; public interface Mapper extends Mapper<Category> , IdListMapper<Category,Long> {}
/** * 根据主键字符串进行查询,类中只有存在一个带有@Id注解的字段 * @param idList * @return */ @SelectProvider(type = IdListProvider.class, method = "dynamicSQL") List<T> selectByIdList(@Param("idList") List<PK> idList); /** * 根据主键字符串进行删除,类中只有存在一个带有@Id注解的字段 * @param idList * @return */ @DeleteProvider(type = IdListProvider.class, method = "dynamicSQL") int deleteByIdList(@Param("idList") List<PK> idList);
- 批量插入:
import tk.mybatis.mapper.additional.insert.InsertListMapper; public interface BaseMapper<T> extends InsertListMapper<T> {} @RegisterMapper public interface InsertListMapper<T> { @InsertProvider( type = InsertListProvider.class, method = "dynamicSQL" ) int insertList(List<? extends T> var1); }
抽取出一个baseMapper, 添加 @RegisterMapper 它才会被扫描到生效
import tk.mybatis.mapper.additional.idlist.IdListMapper; import tk.mybatis.mapper.additional.insert.InsertListMapper; import tk.mybatis.mapper.annotation.RegisterMapper; import tk.mybatis.mapper.common.Mapper; @RegisterMapper public interface BaseMapper<T> extends IdListMapper<T,Long>,Mapper<T>, InsertListMapper<T> { }
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK