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会报错...

坐标

Copy

org.springframework.boot

spring-boot-starter-parent

2.0.4.RELEASE

1.8

org.springframework.boot

spring-boot-starter-web

org.mybatis.spring.boot

mybatis-spring-boot-starter

1.3.2

tk.mybatis

mapper-spring-boot-starter

2.0.3

com.github.pagehelper

pagehelper-spring-boot-starter

1.2.5

mysql

mysql-connector-java

8.0.11

junit

junit

text

org.springframework.boot

spring-boot-starter-test

test

org.projectlombok

lombok

另外插一嘴---mysql连接的版本适配

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

Copy

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could

配置文件:

主要是配置数据库的连接,如果我们使用的是通用mapper,Mybatis可以做到零配置

Copy

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包路径

Copy

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 ?

Copy

import tk.mybatis.mapper.common.Mapper;

public interface MyMapper extends Mapper {}

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

二. 常见的注解#

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

情景1: 对于实体类

标记他对应那张表

Copy

import javax.persistence.Table;

@Table(name = "tb_brand")

情景2: 对于主键

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

注解1:

Copy

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的原生注解

Copy

@Id

@KeySql(useGeneratedKeys = true)

private Long id;

情景3:

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

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

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

Copy

@Transient

情景4:

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

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

Copy

@Column(name="`numeric`") //

private Boolean numeric; //是否是数字类型

情景5 :

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

Copy

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

情景5:

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

Copy

import com.fasterxml.jackson.annotation.JsonIgnore;

@JsonIgnore

它是jackson的注解

Copy

com.fasterxml.jackson.core

jackson-annotations

RELEASE

compile

三. 怎么玩?#

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

一. CRUD#

两种新增

Copy

//会有选择性的新增, 智能判断 brand里面有没有空的字段,有值,用这个值,没有值而使用数据库的默认值

insertSelective(brand)

// 假如前端提交过来的 brand里面的数据是全的,用词方法

brandMapper.insert(brand);

简单查询

Copy

/**

* 根据实体中的属性值进行查询,查询条件使用等号

* @param record

* @return

*/

@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")

List select(T record);

/**

* 根据实体中的属性值进行查询,查询条件使用等号

* @param record

* @return

*/

@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")

List select(T record);

/**

* 查询全部结果

* @return

*/

@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")

List 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);

简单删除

Copy

/**

* 根据主键字段进行删除,方法参数必须包含完整的主键属性

* @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

Copy

/**

* 根据主键更新属性不为null的值

* @param record

* @return

*/

@UpdateProvider(type = BaseUpdateProvider.class, method = "dynamicSQL")

int updateByPrimaryKeySelective(T record);

看到这个方法有没有觉得很爽? 它根据主键,修改不为null的属性,意思就是说,我们把不需要修改的地方设置为null就好了

,这样看,前面需要我们一顿整,整啥呢? 结合实际的业务逻辑,把前端给交过来的数据最新的数据放到我们的bean中直接修改,把不需要修改的属性设置为null,有属性可能需要直接删除,有的属性可能要去别的表中查询(别忘了加上事务 @Transactional )

Copy

/**

* 根据主键更新实体全部字段,null值会被更新

* @param record

* @return

*/

@UpdateProvider(type = BaseUpdateProvider.class, method = "dynamicSQL")

int updateByPrimaryKey(T record);

这个方法和上面的神似

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

API

Copy

mapper.selectByExample(example)

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

Copy

select * from 表名

where name like '% X %' or letter== 'x'

order by id desc

逻辑

Copy

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 list = brandMapper.selectByExample(example);

if (CollectionUtils.isEmpty(list)){

throw new Exception ;

}

// 解析List

PageInfo pageInfo = new PageInfo<>(list);

return new PageResult(pageInfo.getTotal(),list);

}

三 .自定义sql#

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

原生sql

Copy

select * from tb_brand b

inner join tb_category_brand cb on b.id=cb.brand_id -- 去笛卡尔积

where cb.category_id= ? ;

mapper

?用#{id} 取代

Copy

@Select("select * from tb_brand b inner join tb_category_brand cb on b.id=cb.brand_id where cb.category_id=#{cid}")

List queryBrandByCid(@Param("cid") Long cid);

四 .拓展包--批量操作#

批量查询,批量删除

注意他的包啊!

Copy

import tk.mybatis.mapper.additional.idlist.IdListMapper;

public interface Mapper extends Mapper , IdListMapper {}

Copy

/**

* 根据主键字符串进行查询,类中只有存在一个带有@Id注解的字段

* @param idList

* @return

*/

@SelectProvider(type = IdListProvider.class, method = "dynamicSQL")

List selectByIdList(@Param("idList") List idList);

/**

* 根据主键字符串进行删除,类中只有存在一个带有@Id注解的字段

* @param idList

* @return

*/

@DeleteProvider(type = IdListProvider.class, method = "dynamicSQL")

int deleteByIdList(@Param("idList") List idList);

批量插入:

Copy

import tk.mybatis.mapper.additional.insert.InsertListMapper;

public interface BaseMapper extends InsertListMapper {}

@RegisterMapper

public interface InsertListMapper {

@InsertProvider(

type = InsertListProvider.class,

method = "dynamicSQL"

)

int insertList(List extends T> var1);

}

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

Copy

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 extends IdListMapper,Mapper, InsertListMapper {

}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐