在mysql数据库上创建一个mybatis_plus_test数据库,并且在其中建表。
对应的建表语句为
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
插入数据语句为
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
当然还是走Spring Initializr:https://start.spring.io/
pom.xml中引入mybatis,mysql,lombok的依赖,等待maven引入依赖完毕,以便后续使用
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.3.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
由于我的版本为5.7.32,所以选择mysql5的配置内容,在properties中添加
我的url和username和password都是自己云服务器上的内容。
#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus
spring.datasource.username=root
spring.datasource.password=123456
在 Spring Boot 启动类中添加 @MapperScan 注解,让它扫描 等会创建的Mapper 文件夹
@MapperScan("com.example.mybatisplustest.mapper")
创建entity文件夹用来保存实体,在其中创建实体类
其中@Data 会帮我们自动重写get,set等一系列方法,大致如图
import lombok.Data;
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
创建一个用户的mapper,其中BaseMapper是框架中自带的,存储的User是之前定义的。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplustest.entity.User;
public interface UserMapper extends BaseMapper<User> {
}
在测试文件中添加代码,记得引入junit依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>compilescope>
dependency>
代码中usermapper会报错没有bean,但由于这是自动注入的依赖,所以可以不用管,运行的时候不会有问题的。如果想避免报错,可以在mapper里添加@Repository
class MybatisPlusTestApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
System.out.println("尝试读取数据库中所有数据");
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
@Test
public void testInsert(){
User user = new User();
user.setAge(18);
user.setEmail("[email protected]");
user.setName("mary");
//插入 result是影响的行数
int result = userMapper.insert(user);
System.out.println(result);
//id可以自动写入
System.out.println(user);
}
代码运行结果如图,其中ID是自动生成的
去数据库里面查询,插入成功
可以看到生成的ID并不是自增ID,因为MyBatis-Plus默认的主键策略是全局唯一ID。
想要设置主键递增有两个方法,第一是在创建数据表的时候指定,第二是在实体字段中配置 @TableId (https://github.com/TableId)(type = IdType.AUTO)
@Data
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
此时运行后报错:Error updating database. Cause: java.sql.SQLException: Field ‘id’ doesn’t have a default value,查了一下还需要在设计表中将表ID改为自增才可以,于是删掉之前那条记录并且重新运行,此时才运行成功。
update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?
//根据ID更新
@Test
public void testUpdateById(){
//首先根据ID查询记录
User user = userMapper.selectById(1L);
//设置要将其修改的值
user.setAge(50);
//将修改方法送上去
int result = userMapper.updateById(user);
System.out.println(result);
}
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能,创建一个config类
//@Configuration表示这是一个配置类
@Configuration
public class PageConfig {
//分页插件 使用@Bean注册
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
然后在Test里面写方法
//测试selectPage分页
@Test
public void testSelectPage() {
//参数1:当前页 参数2:每页显示的记录数
Page<User> page = new Page<>(1,3);
//用到userMapper上 参数2为条件
userMapper.selectPage(page, null);
//打印每页
page.getRecords().forEach(System.out::println);
System.out.println(page.getCurrent());
System.out.println(page.getPages());
System.out.println(page.getSize());
System.out.println(page.getTotal());
System.out.println(page.hasNext());
System.out.println(page.hasPrevious());
}
@Test
public void testDeleteById(){
int result = userMapper.deleteById(6L);
System.out.println(result);
}
//根据ID删除多条记录
@Test
public void testDeleteBatchIds(){
int result = userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));
System.out.println(result);
}
有时候需要逻辑删除这个功能,即修改数据的某个字段,使其表示为已删除状态,而非删除数据,保留该数据在数据库中,但是查询时不显示该数据。
在数据库中添加一个新字段:deleted,记住要将所有的记录的deleted设为0,同时后续的插入语句也要setdeleted(0),才能进行后续操作
ALTER TABLE `user` ADD COLUMN `deleted` boolean
实体类中添加,注意加上@TableLogic注解,其作用是:在字段里加上这个注解再执行BaseMapper的删除方法时,删除方法会变成修改
@TableLogic
private Integer deleted;
在application.properties 加入配置
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
此时执行之前的delete方法,删除ID=1的记录,很明显执行成功了
此时执行成功,查询所有记录显示1已经被删除了
然而在数据库中1还存在,只是deleted从0变为了1
主要是使用MBP进行一些条件查询操作,例如根据ID查询,根据名称,邮箱查询等等。
具体内容可以根据截图看或者查询官网:条件构造器
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : Entity 对象封装操作类,不是用lambda语法
UpdateWrapper : Update 条件封装,用于Entity对象更新操作
AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取
column。
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
queryWrapper是mybatis plus中实现查询的对象封装操作类,可以封装sql对象,包括where条件,order by排序,select哪些字段等等,
//找出年龄大于等于28的
@Test
public void testSelect(){
//注意其封装的是实体User
QueryWrapper<User> UserQueryWrapper = new QueryWrapper<>();
//列名要打对
UserQueryWrapper.ge("age",28);
//执行查询
List<User> users = userMapper.selectList(UserQueryWrapper);
System.out.println(users);
}
//找出年龄等于20的
@Test
public void testSelectNE(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("age","20");
User user = userMapper.selectOne(userQueryWrapper);
System.out.println(user);
}
注意不一定要用selectMaps,之前的list也可以,只是做一个展示,表明可以使用map接收返回数据。
//找出name中有e的,且email以t开头的用户
@Test
public void testSelectLike(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.like("name","e").likeRight("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
maps.forEach(System.out::println);
}
//所有人按年龄升序排列
@Test
public void testSelectBy(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.orderByAsc("age");
List<User> users = userMapper.selectList(userQueryWrapper);
users.forEach(System.out::println);
}
没看出有什么新东西来,就是使用lambda表达式的语法来写wrappper…
//查找年龄=21,名字为Sandy的人
@Test
public void testLambdaQuery(){
LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
userLambdaQueryWrapper.eq(User::getAge,21);
userLambdaQueryWrapper.like(User::getName,"Sandy");
List<User> list = userMapper.selectList(userLambdaQueryWrapper);
System.out.println(list);
}
注意之前的部分都是对于mapper进行操作的(或者说dao层)dao层用来封装一些mapper方法。controller里面注入service,由service来调mapper。
controller和service的区别如下:
controller层,主要用于给前端返回数据的以及接收前端的数据的,
service层,总之就是处理数据用的。
处理controller层传过来的数据然后传给给dao层链接数据库进行增删改查, 从dao层传过来的数据的处理,比如封装成JavaBean。
涉及请求、参数、序列化之类的逻辑可以放在controller。
而具体到数据的操作逻辑,也就是增删改查的操作都应该完整封装到service中。一方面是对于事务的要求,比如一个请求过来,后台需要多步增删改查,一般都要求放到一个service方法中也就是同一段事务里。另一方面也是为了提供统一的接口,有的业务除了本地的controller还会需要服务间通信,比如rest
api或者rpc什么的,最后他们都应该从同一个service拿到一致的基础数据,然后由各自的controller按各自的需求加工后返回。Service层叫服务层,被称为服务,粗略的理解就是对一个或多个DAO进行的再次封装,封装成一个服务,所以这里也就不会是一个原子操作了,需要事物控制。
service是将dao层的增删改查基本操作调用过来,封装到servce类中,集成一个服务。Controller层:业务层,管理用户的操作,用户界面传过的请求,调用对应的服务(service),完成用户请求的处理。
service层就是处理业务逻辑。但是在项目中,有时候在控制层也有业务逻辑。
业务逻辑代码太薄的话放在controller也没关系。涉及修改数据的,有事务控制的,需要放service。
首先创建好一个service
public interface UserService extends IService<User> {
}
再创建一个impl文件夹,作为实现类的保存
首先其实现UserService接口,同时继承ServiceImpl,记住在其中声明mapper和entity
@Service
public class UserServiceimpl extends ServiceImpl<UserMapper, User> implements UserService {
}
可以点进去看ServiceImpl的实现,它已经帮助我们自动注入了mapper
//注入service后查询所有数据
@Autowired
private UserService userService;
//上面是直接调用mapper,属于dao层的内容,现在是调用service,执行后台的一些操作
@Test
public void findAll(){
//这些方法可以在service中自定义声明
List<User> list = userService.list();
for(User u:list){
System.out.println(u);
}
}