Myabtis-Plus配置
MybatisPlus官网
官方文档上有详细的spring boot配置mybatis-plus的教程,此处就不在详细赘述。
mybatis-plus是基于spring完成的只能再spring相关应用上实现。
- 引入父工程
注意mybatis-plus和spring boot的版本匹配不然会出现
推荐版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
参考pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
</dependencies>
配置并连接数据库
- 创建数据库表
- 添加若干数据
- application.properties中配置
datasource
datasource
是连接数据库必须的配置,数据库驱动包通过反射来加载这些信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://139.9.209.93/task?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
- ORM映射
将数据库表映射到java的对象中,实现信息交换。
@Data
@TableName("bt_04")
public class BT_04 {
@TableId(value = "opt_id")
private Integer id;
@TableField("drag_start_lat")
private Double DragStartLat;
@TableField("drag_start_lon")
private Double DragStartLon;
@TableField("drag_end_lat")
private Double DragEndLat;
@TableField("drag_end_lon")
private Double DragEndLon;
}
注意
@TableName
和@TableField
相辅相成共同完成ORM映射。后者辅助前者。
名称 | 作用 | 备注 |
---|---|---|
@TableName | 完成数据库表到对象的映射 | 位于bean的开头参数为数据库表名 |
@TableField | 完成字段到属性的映射 | mp默认下划线命名到驼峰命名转换,遵守规则可以省去该注解,参数为对象属性 |
@TableId | 完成主键的映射 | 参数可以设置自增等条件 |
car_name[下环线命名]
carName[驼峰命名]
mybatis-plus默认前者转后者。
mp作为myabtis的升级版延续了前身的注解,也扩展了许多新的注解
具体请参考官网 MyBatis-Plus
之前已经通过@TableFieId注解将数据库表实现映射了,而关系的桥梁就是sql,那么如何应用sql呢?
通过mybatis的mapper接口和mapper映射文件关联即可。但是mp有更好的方法就是BaseMapper
一个BaseMapper管理一个映射关系。
myabtis
public interface BTfourMapper { //extends BaseMapper<BT_04>
@Select("select * from bt_04")
List<BT_04> query();
}
mybatis-plus
public interface BTfourMapper extends BaseMapper<BT_04>{
}
通过BaseMapper的泛型映射后无需编写sql语句更方便。
可以看到BaseMapper中定义了很多接口来满足常规需求
因此只要集成该接口就可以调用方法,由于泛型的绑定实现了表的唯一性。
BaseMapper的CRUD接口
public interface BTfourMapper extends BaseMapper<BT_04>{
}
任意接口继承BaseMapper
就可以使用其方法,在通过泛型绑定变成相关表的专属mapper,例如
//mybatis
public interface UserMapper{
/**
*相关CURD操作
*/
List<User> queryAll();
...
//每个查询返回结果使用泛型接收,所以mapper下的有需要的都要写
}
//mybatis-plus
public interface UserMapper extends BaseMapper<User>{
}
//在接口处使用泛型,后续直接使用
BaseMapper的具体方法及使用参考官网
mapper实例:
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class BTtest {
@Autowired
BTfourMapper bTfourMapper;
@Test
public void method(){
List<BT_04> bt_04s = bTfourMapper.selectList(null);
System.out.println(bt_04s);
}
}
在该单元测试中自动装配的mapper为一个只集成BaseMapper的接口,selectList为接口super的方法,参数为一个Wraper(查询条件包装),没有填null。
BaseMapper
中包含了基本的CURD操作,其实就是对mapper做了一个包装,因为每个mapper无外乎都是CURD
操纵,具有统一型,面向不同的对象又具有多样性,包装后的mapper具有通用性。---- 感谢开发团队 😮
下面是BaseMapper的源码:
public interface BaseMapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
}
需要注意的是使用BaseMapper一定要加上泛型。
Model的CRUD接口
细心的朋友可能就发现使用mapper时都有相应的xml的文件映射呀,或者相应的注解绑定着sql语句呀?
是的,上面的实例并未出现sql语句,是如何实现了的呢?对于CURD操作也是具有相似性的,例如
// 表a查询
select username,password,status from user
//查询表2
select code,name,status from sys_dict
同理只要将表的字段与对应sql的条件对应上也就具通用性,如下所示:
package com.baomidou.mybatisplus.core.enums;
public enum SqlMethod {
INSERT_ONE("insert", "插入一条数据(选择字段插入)", "<script>\nINSERT INTO %s %s VALUES %s\n</script>"),
DELETE_BY_ID("deleteById", "根据ID 删除一条数据", "<script>\nDELETE FROM %s WHERE %s=#{%s}\n</script>"),
DELETE_BY_MAP("deleteByMap", "根据columnMap 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>"),
DELETE("delete", "根据 entity 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>"),
DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量删除数据", "<script>\nDELETE FROM %s WHERE %s IN (%s)\n</script>"),
LOGIC_DELETE_BY_ID("deleteById", "根据ID 逻辑删除一条数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
LOGIC_DELETE_BY_MAP("deleteByMap", "根据columnMap 条件逻辑删除记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_DELETE("delete", "根据 entity 条件逻辑删除记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量逻辑删除数据", "<script>\nUPDATE %s %s WHERE %s IN (%s) %s\n</script>"),
UPDATE_BY_ID("updateById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
UPDATE("update", "根据 whereEntity 条件,更新记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_UPDATE_BY_ID("updateById", "根据ID 修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
LOGIC_UPDATE_ALL_COLUMN_BY_ID("updateAllColumnById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s}"),
SELECT_BY_MAP("selectByMap", "根据columnMap 查询一条数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>\nSELECT %s FROM %s WHERE %s IN (%s)\n</script>"),
SELECT_ONE("selectOne", "查询满足条件一条数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_COUNT("selectCount", "查询满足条件总记录数", "<script>\nSELECT COUNT(%s) FROM %s %s\n</script>"),
SELECT_LIST("selectList", "查询满足条件所有数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_PAGE("selectPage", "查询满足条件所有数据(并翻页)", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_MAPS("selectMaps", "查询满足条件所有数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_MAPS_PAGE("selectMapsPage", "查询满足条件所有数据(并翻页)", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_OBJS("selectObjs", "查询满足条件所有数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
LOGIC_SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s} %s"),
LOGIC_SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>\nSELECT %s FROM %s WHERE %s IN (%s) %s\n</script>");
private final String method;
private final String desc;
private final String sql;
private SqlMethod(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}
public String getMethod() {
return this.method;
}
public String getDesc() {
return this.desc;
}
public String getSql() {
return this.sql;
}
}
SqlMethod
是mybatis封装sql的类,位于com.baomidou.mybatisplus.core.enums
包下该类的返回值是一个集合。通过SqlMethod.
获取需要的sql语句。
SqlMethod
不是泛型没有通用性,还需要包装类对其解析封装并具有泛型,这个类就是Model
。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.baomidou.mybatisplus.extension.activerecord;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.TableInfoHelper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionUtils;
public abstract class Model<T extends Model> implements Serializable {
private static final long serialVersionUID = 1L;
public Model() {
}
public boolean insert() {
SqlSession sqlSession = this.sqlSession();
boolean var2;
try {
var2 = SqlHelper.retBool(sqlSession.insert(this.sqlStatement(SqlMethod.INSERT_ONE), this));
} finally {
this.closeSqlSession(sqlSession);
}
return var2;
}
public boolean insertOrUpdate() {
return !StringUtils.checkValNull(this.pkVal()) && !Objects.isNull(this.selectById(this.pkVal())) ? this.updateById() : this.insert();
}
public boolean deleteById(Serializable id) {
SqlSession sqlSession = this.sqlSession();
boolean var3;
try {
var3 = SqlHelper.delBool(sqlSession.delete(this.sqlStatement(SqlMethod.DELETE_BY_ID), id));
} finally {
this.closeSqlSession(sqlSession);
}
return var3;
}
public boolean deleteById() {
Assert.isFalse(StringUtils.checkValNull(this.pkVal()), "deleteById primaryKey is null.", new Object[0]);
return this.deleteById(this.pkVal());
}
public boolean delete(Wrapper<T> queryWrapper) {
Map<String, Object> map = new HashMap(1);
map.put("ew", queryWrapper);
SqlSession sqlSession = this.sqlSession();
boolean var4;
try {
var4 = SqlHelper.delBool(sqlSession.delete(this.sqlStatement(SqlMethod.DELETE), map));
} finally {
this.closeSqlSession(sqlSession);
}
return var4;
}
public boolean updateById() {
Assert.isFalse(StringUtils.checkValNull(this.pkVal()), "updateById primaryKey is null.", new Object[0]);
Map<String, Object> map = new HashMap(1);
map.put("et", this);
SqlSession sqlSession = this.sqlSession();
boolean var3;
try {
var3 = SqlHelper.retBool(sqlSession.update(this.sqlStatement(SqlMethod.UPDATE_BY_ID), map));
} finally {
this.closeSqlSession(sqlSession);
}
return var3;
}
public boolean update(Wrapper<T> updateWrapper) {
Map<String, Object> map = new HashMap(2);
map.put("et", this);
map.put("ew", updateWrapper);
SqlSession sqlSession = this.sqlSession();
boolean var4;
try {
var4 = SqlHelper.retBool(sqlSession.update(this.sqlStatement(SqlMethod.UPDATE), map));
} finally {
this.closeSqlSession(sqlSession);
}
return var4;
}
public List<T> selectAll() {
SqlSession sqlSession = this.sqlSession();
List var2;
try {
var2 = sqlSession.selectList(this.sqlStatement(SqlMethod.SELECT_LIST));
} finally {
this.closeSqlSession(sqlSession);
}
return var2;
}
public T selectById(Serializable id) {
SqlSession sqlSession = this.sqlSession();
Model var3;
try {
var3 = (Model)sqlSession.selectOne(this.sqlStatement(SqlMethod.SELECT_BY_ID), id);
} finally {
this.closeSqlSession(sqlSession);
}
return var3;
}
public T selectById() {
Assert.isFalse(StringUtils.checkValNull(this.pkVal()), "selectById primaryKey is null.", new Object[0]);
return this.selectById(this.pkVal());
}
public List<T> selectList(Wrapper<T> queryWrapper) {
Map<String, Object> map = new HashMap(1);
map.put("ew", queryWrapper);
SqlSession sqlSession = this.sqlSession();
List var4;
try {
var4 = sqlSession.selectList(this.sqlStatement(SqlMethod.SELECT_LIST), map);
} finally {
this.closeSqlSession(sqlSession);
}
return var4;
}
public T selectOne(Wrapper<T> queryWrapper) {
return (Model)SqlHelper.getObject(this.selectList(queryWrapper));
}
public IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper) {
Map<String, Object> map = new HashMap(2);
map.put("ew", queryWrapper);
map.put("page", page);
SqlSession sqlSession = this.sqlSession();
try {
page.setRecords(sqlSession.selectList(this.sqlStatement(SqlMethod.SELECT_PAGE), map));
} finally {
this.closeSqlSession(sqlSession);
}
return page;
}
public Integer selectCount(Wrapper<T> queryWrapper) {
Map<String, Object> map = new HashMap(1);
map.put("ew", queryWrapper);
SqlSession sqlSession = this.sqlSession();
Integer var4;
try {
var4 = SqlHelper.retCount((Integer)sqlSession.selectOne(this.sqlStatement(SqlMethod.SELECT_COUNT), map));
} finally {
this.closeSqlSession(sqlSession);
}
return var4;
}
public SqlRunner sql() {
return new SqlRunner(this.getClass());
}
protected SqlSession sqlSession() {
return SqlHelper.sqlSession(this.getClass());
}
protected String sqlStatement(SqlMethod sqlMethod) {
return this.sqlStatement(sqlMethod.getMethod());
}
protected String sqlStatement(String sqlMethod) {
return SqlHelper.table(this.getClass()).getSqlStatement(sqlMethod);
}
protected Serializable pkVal() {
return (Serializable)ReflectionKit.getMethodValue(this, TableInfoHelper.getTableInfo(this.getClass()).getKeyProperty());
}
protected void closeSqlSession(SqlSession sqlSession) {
SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(this.getClass()));
}
}
有了Model后,直接使用该类可以进行CRUD,但是必须存在对应的mapper继承BaseMapper。基本步骤就是实体类继承Model添加泛型,对应Mapper继承BaseMapper,然后实体类对象也可以进行CRUD操作。
实例:
//实体类继承Model添加泛型
@TableName("user")
public class User extends Model<User> {
@TableId
private int id;
@TableField("username")
private String username;
@TableField("password")
private String password;
}
//对应接口继承BaseMapper
public interface UserMapper extends BaseMapper<User>{
}
//实体类直接调用方法
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class UserMapperTest {
//@Autowired User user;
@Test
public void one(){
User user = new User();
List<User> users = user.selectList(null);
System.out.println(users);
}
}
Model调用CRUD的接口的限制是需要接收到实体类参数。
IService的CRUD接口
service调用方法基本方法比mapper层调用多了service层
//实体类
@TableName("user_address")
public class UserAddress {
private int id;
private int address_id;
private String detail_address;
private int user_id;
private Date create_time;
private Date update_time;
private String name;
private String phone;
}
//mapper层
public interface UserAddressMapper extends BaseMapper<UserAddress> {
}
mapper没有@MapperScan注解的话需要加@Component
service接口继承Iservice,并且service接口的实现类要继承ServiceImpl<xxxMapper,pojo>
//service层
//接口
public interface UserAddressService extends IService<UserAddress> {
}
//接口实现类
@Service
public class UserAddressServiceImpl extends ServiceImpl<UserAddressMapper, UserAddress>implements UserAddressService{
}
具体需要在那层调用要根据实际需求。
//测试
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class UserAddressTest {
@Autowired
UserAddressService userAddressService;
@Test
public void methodOne(){
UserAddress one = userAddressService.getById(1);
System.out.println(one);
}
}
总结:
1、Model:使用映射类pojo继承model,直接使用该类可以进行CRUD,但是必须存在对应的mapper继承BaseMapper;
2、BaseMapper和Iservice
BaseMapper是使用dao层数据进行CRUD,只需要进行使用dao层接口继承BaseMapper即可;
Iservice是使用service层进行CRUD,需要使用service接口继承Iservice,并且service接口的实现类要继承ServiceImpl<xxxMapper,pojo>;
BaseMapper和Iservice里面提供的方法都差不多,只是Iservice提供了批量操作的实现,比如: 批量添加、批量修改。