Myabtis-Plus配置
官方文档有关于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映射。后者辅助前者。
姓名 | 影响 | 评论 |
---|---|---|
@表名 | 完成数据库表到对象的映射 | bean开头的参数是数据库表名 |
@TableField | 完整的字段到属性映射 | mp 默认从下划线命名转换为驼峰式命名。如果遵守规则,可以省略注释。参数是对象属性。 |
@表Id | 完整的主键映射 | 可设置参数自增等条件 |
car_name[下环线命名]
carName[驼峰命名]
mybatis-plus默认前者转后者。
mp作为myabtis的升级版本,延续了前身的注释,同时还添加了很多新的注释。
具体请参考官网MyBatis-Plus
之前已经通过@TableFieId注解将数据库表实现映射了,而关系的桥梁就是sql,那么如何应用sql呢?
通过mybatis的mapper接口和mapper映射文件关联即可。但是mp有更好的方法就是BaseMapper
一个BaseMapper管理一个映射关系。
米阿布蒂斯
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的具体方法和使用请参考官网
映射器示例:
@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,但必须有一个对应的继承BaseMapper的mapper。基本步骤就是实体类继承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接口
服务调用方法的基本方法调用的服务层比mapper层多。
//实体类
@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、模型:使用映射类pojo继承模型。使用该类可以直接进行CRUD操作,但是必须有对应的继承BaseMapper的Mapper;
2、BaseMapper和Iservice
BaseMapper是使用dao层数据进行CRUD,只需要进行使用dao层接口继承BaseMapper即可;
Iservice是使用service层进行CRUD,需要使用service接口继承Iservice,并且service接口的实现类要继承ServiceImpl<xxxMapper,pojo>;
BaseMapper和Iservice中提供的方法类似,只不过Iservice提供了批量操作的实现,例如:批量添加、批量修改。