tkmybatis详细教程(一篇就明白)

tkmybatis 是对底层 sql 进行了抽象封装,不需要考虑 sql 怎么写,只需要按照逻辑思维,遵循 tkmybatis 的语法即可实现数据库操作。

本文适合对springboot项目结构有一定了解的读者。

本文的项目基础是一个demo项目(多模块的)。

1. 配置

1、添加 tkmybatis 的依赖

            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>2.1.5</version>
            </dependency>

2、创建 dao 层的 mapper 接口,每个接口都要继承  tk.mybatis.mapper.common.Mapper 接口。此接口的形式为 Mapper<T>,带了个泛型,此泛型一般指的是对应的 pojo 或者 domain。比如:

public interface HouseMapper extends Mapper<House> {
}

3、在 Application 启动类上添加 mapper 扫描注解,表示要扫描到 dao 层的 mapper 接口。

比如本项目的mapper接口就统一放在 com.dgh.dao 下面,用 @MapperScan(basePackages = "包名") 来指定。

附注:在项目启动时,springboot 会自动扫描 Application 启动类所在的当前目录以及下一级目录,一般 Application 启动类都放在根目录,所以在单一项目下,只要是在 Java 类上添加了注解,都能够默认被 springboot 扫描到,并被添加到 springboot 的容器中,一般不需要特别用  @ComponentScan 去指定 springboot 要扫描哪些目录。

本文之所以特地用  @ComponentScan 去指定了 service 层和 controller 层的目录,是因为本文的项目是一个多模块项目,service 层和 controller 层各自都是一个独立的模块,与 Application 启动类不在同一目录下。

@SpringBootApplication
@MapperScan(basePackages = "com.dgh.dao")
@ComponentScan(basePackages = "com.dgh.service")
@ComponentScan(basePackages = "com.dgh.controller")
public class ControllerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ControllerApplication.class, args);
    }
}

4、tkmybatis 具体的使用是在 service 层,service 层又分为接口和接口实现类,具体就在接口实现类里面。

5、其它的代码、配置与普通的springboot项目一样。

2. tkmybatis的结构

下图是 tkmybatis 的结构图,圈中的是 Mapper 接口,是最底层的,也就意味着它继承了所有的功能。因此才有了 “配置” 中第2步继承Mapper<T>接口。

它定义各种 sql 语句的基础,通过灵活的拼接,查询参数的设置,可以满足开发者各种的数据库查询要求。

既然如此,那我猜 tkmybatis 的底层是动态代理实现的。

3. 增删查改——基础方法

3.1 删除

DeleteByPrimaryKeyMapper接口有一个方法 deleteByPrimaryKey,顾名思义,以表的主键字段作为条件判断,进行删除。

delete from table where id = ?

int deleteByPrimaryKey(Object var1);

DeleteMapper接口有一个方法 delete,参数就是数据库表对应的Java实体类,参数实体中哪些字段不为null,就会被作为删除sql语句的条件字段,且条件关系是 and,而不是 or。

delete from table where 字段1 = ?and 字段2 = ?

int delete(T var1);

 注意:在定义实体类时,每个成员变量的类型都应该是Java类,不能是基本类型,比如整型,应该用 Integer,而不是 int。如果用 int 的话,在没有给 int 成员变量赋值时,ava 会默认给它赋值为 0,由于 0 不是 null,所以会被 tkmybatis 当做是删除条件。

比如前段发送的删除请求,参数实体如下,height字段为 null,本来意思是不把 height 字段作为删除的条件字段,如果 Java 实体类的 height 字段类型定义为 Integer,那一切正常,但是如果定义为 int 类型,那么在实例化对象并赋值时,默认赋值 height = 0,sql语句将变成  delete from house where age = 69 and height = 0;   这样就违背了本意,容易造成错误的删除后果。

3.2 插入

InsertMapper 接口有一个方法 insert 方法,往数据库表插入一条记录,表有多少个字段,在 tkmybatis 生成的 insert sql 语句中就有多少个字段。

insert into table (所有字段) values (?,?...,?)

int insert(T var1);

InsertSelectiveMapper 接口有一个方法 insertSelective,实体类参数中不为 null 的字段就会被考虑,在 tkmybatis 生成的 insert sql 语句中只会包含这些不为 null 的字段。

insert into table (部分字段) values (?,..?)

int insertSelective(T var1);

3.3 查询

SelectMapper 接口有一个方法 select,参数实体类中哪些字段不为 null,就会被作为 select sql 语句中的条件字段,且字段之间的关系是 and。

select 所有字段 from table where 字段1 = ? and 字段2 = ?

List<T> select(T var1);

SelectOneMapper 接口有一个方法 selectOne,与 select 方法一样,只是返回结果只能为空或者一个,如果有多个,则抛出异常。

同上

T selectOne(T var1);

SelectCountMapper 接口有一个方法 selectCount,查询满足条件的记录有多少条。

select count(id) from table where 字段1 = ? and 字段2 = ?

int selectCount(T var1);

SelectAllMapper 接口有一个方法 selectAll,查询全表所有记录。

select 所有字段 from table;

List<T> selectAll();

SelectByPrimaryKeyMapper 接口有一个方法 selectByPrimaryKey,根据主键进行查询。

select 所有字段 from table where 主键字段 = ?

T selectByPrimaryKey(Object var1);

ExistsWithPrimaryKeyMapper 接口有一个方法 existsWithPrimaryKey,根据主键查询某条记录是否存在。

select case when count(主键字段) > 0 then 1 else 0 end as result from table where 主键字段 = ?

boolean existsWithPrimaryKey(Object var1);

3.4 修改

UpdateByPrimaryKeyMapper 接口有一个方法 updateByPrimaryKey,根据主键字段准确地修改某一条记录。

update table set 所有字段

int updateByPrimaryKey(T var1);

UpdateByPrimaryKeySelectiveMapper 接口有一个方法 updateByPrimaryKeySelective,根据主键字段准确地修改某一条记录的部分字段(实体类参数的不为 null 的字段)。

update table set 部分字段

int updateByPrimaryKeySelective(T var1);

4 批量增删查改——基础方法

4.1 批量插入

这两个功能有一个要求,那就是操作的数据库表必须有一个自增主键,因为它要求主键必须要有一个默认值,否则就抛出异常。

这两个接口是集成到 MySqlMapper 接口中了,所以 dao 层的 mapper 接口还要继承 MySqlMapper 接口才能使用批量插入功能。

public interface HouseMapper extends Mapper<House>, MySqlMapper<House> {
}

InsertListMapper 接口有一个方法 insertList,批量插入。

insert into table (所有字段,除了自增主键) values (?,..,?), ...,(?,...,?)

int insertList(List<? extends T> var1);

InsertUseGeneratedKeysMapper 接口有一个方法 insertUserGeneratedKeys,单个插入。

int insertUseGeneratedKeys(T var1);

4.2 批量查询与批量删除

SelectByIdsMapper 接口有一个方法 selectByIds,按照多个主键 id 值进行查询,但是方法的参数是 String,那么主键id之间用逗号隔开就行。

select 所有字段 from table where id in (id值1,id值2,...,id值n)

List<T> selectByIds(String var1);

DeleteByIdsMapper 接口有一个方法 deleteByIds,按照多个主键 id 值进行删除。

delete from table where id in (id值1,id值2,...,id值n)

int deleteByIds(String var1);

5 自定义查询条件

5.1 删改查方法

图中接口都有一个共同点,就是需要 Example 对象作为方法的参数,Example 对象包含了我们各种自定义的查询条件,相当于 sql 语句中 where 部分的条件。

每个接口都包含了一个方法,供我们调用。总结如下表:

方法功能描述
int deleteByExample(Object var1);一般参数就是Example对象,按照条件进行删除,返回删除的记录数
List<T> selectByExample(Object var1);一般参数就是Example对象,按照条件进行查询,返回查询结果集
int selectCountByExample(Object var1);一般参数就是Example对象,按照条件进行查询,返回符合查询条件的记录数
T selectOneByExample(Object var1);一般参数就是Example对象,按照条件进行查询,结果只能为空或者一个,否则抛出异常
int updateByExample(@Param("record") T var1, @Param("example") Object var2);第一个参数是新记录,第二参数是example对象,用新记录替换掉符合条件的旧记录
int updateByExampleSelective(@Param("record") T var1, @Param("example") Object var2);功能同上,只是可以仅替换掉记录的部分字段
List<T> selectByRowBounds(T var1, RowBounds var2);第一个参数是查询条件,第二个参数是 RowBounds 对象(包含2个属性,offset 和 limit),offset 表示起始行,limit 表示需要的记录数;方法的功能是按照查询条件进行查询,再按照 offset 和 limit 在结果集中取相应数量的记录。
List<T> selectByExampleAndRowBounds(Object var1, RowBounds var2);第一个参数是 Example 对象,第二个参数是 RowBounds 对象,先根据 example 条件进行查询,再按照 offset 和 limit 取相应数量的记录。
List<T> selectByConditionAndRowBounds(Object var1, RowBounds var2);同上

5.2 Example 条件设置

先创建 Example 对象,再创建 Example.criteria 对象,借助这两个对象,可以灵活地设置各种条件。Example 对象可以理解为 sql 语句层次的设置, 而 Example.criteria 对象可以理解为 sql 语句中的一个单一的条件表达式设置。

原理上可以理解为:一个 example 包含了若干个 criteria ,每个 criteria 就是 sql 语句中条件部分的一个括号部分(没有嵌套),比如 (id = 5),criteria 包含了一个方法 void setAndOr(String andOr),它的意思相当于在括号前面加上 and 还是 or,比如执行了方法 setAndOr("and"),那么 criteria 相当于 and (id = 5),而 example 就把这些 criteria 拼凑起了,比如 example 包含了 2 个 criteria,分别是 (id = 5) 和 and (name = "张三"),那么此 example 的效果就是 (id = 5) and (name = "张三")。

Example example = new Example(House.class);
Example.Criteria criteria = example.createCriteria();

具体可以怎么设置呢?criteria 包含的方法总结如下表:

方法功能描述
andAllEqualTo(Object param)所有字段都作为 where 后面的判断条件,判断值就是参数实体对象
andBetween(String property, Object value1, Object value2)where property between value1 and value2 ,范围条件,包含两端
andEqualTo(Object param)实体对象中不为 null 的字段作为 where 后面的判断条件
andEqualTo(String property, Object value)某一个<字段,值>作为 where 后面的判等条件
andGreaterThan(String property, Object value)大于条件,某个字段大于某个值
andGreaterThanOrEqualTo(String property, Object value)大于等于条件,某个字段大于等于某个值
andIn(String property, Iterable values)where property in (),范围条件
andIsNotNull(String property)where property is not null,判空条件
andIsNull(String property)where property is null,判空条件
andLessThan(String property, Object value)小于条件
andLessThanOrEqualTo(String property, Object value)小于等于条件
andLike(String property, String value)where property like value,注意 value 应该是一个匹配表达式
andNotBetween(String property, Object value1, Object value2)范围条件,不包含两端
andNotEqualTo(String property, Object value) 要求字段不等于某个值
andNotIn(String property, Iterable values)要求字段不在某个范围内
andNotLike(String property, String value)模糊查询,要求不 like。
 void setAndOr(String andOr)上面已经介绍过了

上表的方法都是“与”关系,即 and。 同样的,有相应的 “或” 关系,即 or。比如 orAllEqualTo、orGreaterThan 等等,都是将方法名中的 “and” 换成 “or”。

那 criteria 能否嵌套呢?能否有更方便的使用方式呢?回答:能,有。如下表:

Example.Criteria orCondition(String condition, Object value)condition参数是个sql字符串,可以拼接进 sql 语句的,value 是一个值,会拼接到 condition 后面的,此方法的最终结果为 or condition + value。
Example.Criteria orCondition(String condition)功能同上,只是更加直接,一个字符串搞定,只是字符串参数可以写成类似这种 “id = ”+getId(),"( id = "+getId()+")",一样灵活,此方法的最终结果为 or condition。
Example.Criteria andCondition(String condition)不再赘述
Example.Criteria andCondition(String condition, Object value)不再赘述

Example 类包含的方法总结如下表:

方法功能描述
void setDistinct(boolean distinct)查询的结果是否要进行唯一性过滤,true表示过滤,false(默认)表示不过滤。
void setOrderByClause(String orderByClause)查询结果按照某个,或者某些字段进行升序,降序。比如参数是 “id asc” 就是按照 id 进行升序,“id asc,age desc” 就是按照 id 升序,在 id 相等的情况下,按照 age 降序。
Example selectProperties(String... properties)当利用 example 进行查询时,此方法可以设置想要查询的字段是哪些,比如我只需要查询一张表的部分字段。 
Example.OrderBy orderBy(String property)排序,与 setOrderByClause 功能一样,只是用法不同,比如 orderBy("id").asc() 表示按照 id 升序, orderBy("id").asc().orderBy("age").desc() 表示按照 id 升序,再按照 age 降序
Example.Criteria or()创建一个 or 方式的、空的criteria,具体的 criteria 内容可以稍后设置。
void or(Example.Criteria criteria)直接以 or 的方式添加一个现有的 criteria
Example.Criteria and()同上,不过是 and 方式
void and(Example.Criteria criteria)同上,and 方式

 Example 类还有其它的一些方法,本人觉得都有些鸡肋或者重复,也就不再介绍了。

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值