前言
码农这一生,做的最多的四件事,不是吃喝玩乐,而是 增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete) 。
泪目。
为何我要写这篇文章,是有感而发,请看图:
哈哈,虽然看着图一乐,但是大部分码农的工作生活确实现状如此。
也许会有人说了,其实很多crud的代码也只是复制粘贴而已,稍微改改就好。
这确实没错,但是人天性嗜懒,日复一日,不免对复制粘贴也产生了些许倦意。
那么为了我们每天都能元气满满,我们尽可能减少大部分我们‘重复’ 的代码。
曾写过一篇 Springboot 整合Mybatis 使用Mybatis-plus 敏捷开发 ,也是可以省掉非常多的crud代码
那么今天,我需要介绍给大家的是 TK-Mybatis。
正文
惯例,今天的实战实例目录结构:
目前不管是mybatis-plus ,还是tk-mybatis。 帮我们省掉的代码,其实都是对于单表操作而言。
(所以一些复杂的sql语句,我们还是可以自己额外编写,所以额外编写的,我们如往常一样写在mapper.xml里面即可)
也就是说,对于单独一个表的crud操作,一些常规的crud相关代码,都是可以帮我们省掉的,我们不用再写了,包括不仅限于:
1.查询该表所有数据 2.根据条件该表查询该表所有数据 3.根据主键该表查询该表单个数据 4.根据条件查询该表单个数据 5.检测数据是否存在 6.统计该表数据条数 7.根据主键删除数据 8.根据条件删除数据 9.根据主键修改数据 10.根据条件修改数据 11.新增数据 12.分页查询 13.当然还有挺多,不一一列举了
创建一个springboot项目,在pom.xml里导入用到的依赖:
<!--jdbc驱动--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--mybatis操作数据库有关--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!--连接mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--使用阿里巴巴的druid数据源,有利于监控sql的执行情况--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!--通用mapper--> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.1.2</version> </dependency> <!--添加lombok支持,可以省掉写get和set方法--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> <optional>true</optional> </dependency> <!--使用fastjson来操作json数据--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency> <!--spring boot web方面的支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.4.RELEASE</version> </dependency>
数据库表,简单一张表:
对于的User.java实体类:
import lombok.Data; import javax.persistence.*; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ @Data @Table(name="user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY,generator = "JDBC") private Integer id; @Column(name = "name") private String name; @Column(name = "age") private Integer age; }
然后是UserMapper.java(注意看细节,继承了Mapper<User> 来自于tk-mybatis),只要继承了这个Mapper,那么文章前头提到的那些代码和sql,我们都不用再去写了,我们只需要写一些多表的,业务复杂的需要额外扩展的就行。:
import tk.mybatis.mapper.common.Mapper; import java.util.List; import java.util.Map; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ public interface UserMapper extends Mapper<User> { //额外扩展的方法,如一些复杂的查询语句等 List<Map> getMyCustom(int age); }
细心的人发现了,我们这次的mapper上面没有写@Mapper。
是的,我们现在进行一个关键的操作,在启动类上,使用tk-mybatis的扫描mapper注解:
pojo和mapper 两层已经完毕了,那么对接持久层需要做的我们已经完毕了。
service层,我们在这层为了方面项目的扩展,后期能省掉更多的接口复写代码(是不是很多人很烦service层里面的代码跟mapper层对于一些普通的crud操作,基本代码没什么区别),
我们需要做一个base层,也就是后续其他业务的表扩展,都同一继承和实现base层即可。
BaseService.java :
import org.apache.ibatis.session.RowBounds; import tk.mybatis.mapper.common.Mapper; import java.util.List; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ public interface BaseService<T> extends Mapper<T> { @Override int deleteByPrimaryKey(Object o); @Override int delete(T o); @Override int insert(T o); @Override int insertSelective(T o); @Override List<T> selectAll(); @Override T selectByPrimaryKey(Object o); @Override public int selectCount(T o); @Override public List<T> select(T o); @Override public T selectOne(T o); @Override public int updateByPrimaryKey(T o); @Override public int updateByPrimaryKeySelective(T o); @Override public int deleteByExample(Object o); @Override public List<T> selectByExample(Object o); @Override public int selectCountByExample(Object o); @Override public T selectOneByExample(Object o); @Override public int updateByExample(T o, Object o2); @Override public int updateByExampleSelective(T o, Object o2); @Override public List<T> selectByExampleAndRowBounds(Object o, RowBounds rowBounds); @Override public List<T> selectByRowBounds(T o, RowBounds rowBounds); }
BaseServiceImpl.java:
import org.apache.ibatis.session.RowBounds; import org.springframework.beans.factory.annotation.Autowired; import tk.mybatis.mapper.common.Mapper; import java.util.List; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ public abstract class BaseServiceImpl<T> implements BaseService<T> { @Autowired private Mapper<T> mapper; @Override public int deleteByPrimaryKey(Object o) { return mapper.deleteByPrimaryKey(o); } @Override public int delete(T t) { return mapper.delete(t); } @Override public int insert(T t) { return mapper.insert(t); } @Override public int insertSelective(T t) { return mapper.insertSelective(t); } @Override public List<T> selectAll() { return mapper.selectAll(); } @Override public int selectCount(T t) { return mapper.selectCount(t); } @Override public List<T> select(T t) { return mapper.select(t); } @Override public T selectOne(T t) { return mapper.selectOne(t); } @Override public int updateByPrimaryKey(T t) { return mapper.updateByPrimaryKey(t); } @Override public int updateByPrimaryKeySelective(T t) { return mapper.updateByPrimaryKeySelective(t); } @Override public int deleteByExample(Object t) { return mapper.deleteByExample(t); } @Override public List<T> selectByExample(Object t) { return mapper.selectByExample(t); } @Override public int selectCountByExample(Object t) { return mapper.selectCountByExample(t); } @Override public T selectOneByExample(Object o) { return mapper.selectOneByExample(o); } @Override public int updateByExample(T t, Object o) { return mapper.updateByExample(t, o); } @Override public int updateByExampleSelective(T t, Object o) { return mapper.updateByExampleSelective(t, o); } @Override public List<T> selectByExampleAndRowBounds(Object o, RowBounds rowBounds) { return mapper.selectByExampleAndRowBounds(o, rowBounds); } @Override public List<T> selectByRowBounds(T t, RowBounds rowBounds) { return mapper.selectByRowBounds(t, rowBounds); } @Override public boolean existsWithPrimaryKey(Object o) { return mapper.existsWithPrimaryKey(o); } @Override public T selectByPrimaryKey(Object o) { return mapper.selectByPrimaryKey(o); } }
ok,业务层的base层已经完成,回归业务,
UserService.java:
import com.jc.tkmybatis.base.BaseService; import com.jc.tkmybatis.pojo.User; import java.util.List; import java.util.Map; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ public interface UserService extends BaseService<User> { //仅仅需要编写额外扩展的业务方法 List<Map> getMyCustom(int age); }
UserServiceImpl.java:
import com.jc.tkmybatis.base.BaseServiceImpl; import com.jc.tkmybatis.mapper.UserMapper; import com.jc.tkmybatis.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ @Service public class UserServiceImpl extends BaseServiceImpl<User> implements UserService { //UserMapper需要继承tk-myabtis的Mapper,这样才能顺利使用到tk-mybatis帮我们写好的N多mapper层方法和sql语句 @Autowired UserMapper userMapper; //仅仅需要编写额外扩展的业务方法 @Override public List<Map> getMyCustom(int age) { return userMapper.getMyCustom(age); } }
到这里,我们其实整合tk-mybatis已经完毕了!(后面有controller层来演示怎么使用)
因为我们为了确保可以额外扩展,我们还是建了mapper.xml的,所以我们在yml加上对于的mapper.xml文件扫描配置:
mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml
对于userMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.jc.tkmybatis.mapper.UserMapper"> <select id="getMyCustom" resultType="java.util.HashMap"> SELECT * FROM user WHERE age>=#{age} </select> </mapper>
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="useGeneratedKeys" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>
controller层,我们写一些curd的接口来进行使用测试:
UserController.java
PS: 我们在controller层注入 UserService后,我们就可以使用tk-mybatis帮我们实现的那一堆方法了。
import com.jc.tkmybatis.pojo.User; import com.jc.tkmybatis.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; /** * @Author : JCccc * @CreateTime : 2020/8/13 * @Description : **/ @RestController public class UserController { @Autowired UserService userService; /** * 新增 * @return */ @PostMapping("addOne") public int addOne() { User user=new User(); user.setName("jc"); user.setAge(10); return userService.insert(user); } /** * 获取所有 分页 * @return */ @GetMapping("getAllByPage") public List<User> getAllByPage() { RowBounds rowBounds=new RowBounds(0,3); return userService.selectByRowBounds(new User(),rowBounds); } /** * 获取某个 * @return */ @GetMapping("getOne") public User getOne() { User user=new User(); user.setId(1); return userService.selectOne(user); } /** * 获取所有 * @return */ @GetMapping("getAll") public List<User> getAll() { return userService.selectAll(); } /** * 修改 * @return */ @GetMapping("updateOne") public int updateOne() { User user=new User(); user.setId(1); user.setName("TG"); return userService.updateByPrimaryKeySelective(user); } /** * 额外扩展的 * @return */ @GetMapping("getMyCustom") public List<Map> getMyCustom() { return userService.getMyCustom(1); } }
接口的测试,大家自行使用postman或者api post等测试就ok,我就不一一列举了。
ps: 上面代码里面的分页查询,是用到了tk-mybatis里的方法 selectByRowBounds 。
习惯用pagehelper的依然可以使用,添加分页插件依赖:
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency>
使用示例:
/** * 获取所有 分页 PageHelper * @return */ @GetMapping("getAllByPage") public PageInfo getAll() { PageHelper.startPage(1, 2); PageInfo pageInfo = new PageInfo(userService.selectAll()); return pageInfo; }
到此,大家应该是学会整合使用了,我建议,我们不仅要求自己处于单纯的使用,稍微深入一点点了解也是需要的(这样说不定突然感兴趣了,自己就去深挖了)。
抛砖引玉
为什么能省掉这么多代码?
说白了,就是tk-mybatis帮我们写了呗。
我们知道mapper是对接持久层的,那么我们看看我们mapper做了什么? 没错,就是继承了tk-mybatis的Mapper<T>:
我们需要的就是了解这些Mapper里面有哪些方法,例如
BaseMapper<T> :
/** * 保存一个实体,null属性也会保存 * * @param record * @return */ int insert(T record); /** * 保存一个实体,null属性不会保存 * * @param record * @return */ int insertSelective(T record); /** * 根据实体属性作为条件进行删除,查询条件使用等号 */ int delete(T record); /** * 根据主键更新属性不为null的值 */ int updateByPrimaryKeySelective(T record); /** * 根据实体中的属性值进行查询,查询条件使用等号 */ List<T> select(T record); /** * 查询全部结果,select(null)方法能达到同样的效果 */ List<T> selectAll(); /** * 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号 */ T selectOne(T record); /** * 根据实体中的属性查询总数,查询条件使用等号 */ int selectCount(T record);
ExampleMapper ,RowBoundsMapper 这些也是需要了解的(小声说下,认真操作的在文章前面有些方法用到了RowBounds,其实是用来分页的~ )。
这篇文章算是一个tk-mybatis的整合引玉篇吧,把BaseService里面的方法都使用调试下,那么使用层面应该没有问题了。