- 1.mybatis-plus简介及学习时的环境
- 2.一个入门案例
- 3.基本CRUD
- 3.1BaseMapper的基本功能测试
- 3.2BaseMapper的自定义功能
- 3.3通用Service接口
- 4.常用注解
- 4.1@TableName
- 4.2@TableId
- 4.3@TableField
- 4.4@TableLogic
- 5、条件构造器和常用接口
- 5.1Wapper
- 5.2QueryWrapper
- 5.3UpdateWapper
- 5.4LambdaQueryWrapper&LambdaUpdateWrapper
- 6.插件
- 6.1分页插件
- 6.2乐观锁插件
- 7.通用枚举
- 8.代码生成器
- 9.多数据源
- 10.mybatisX插件
- 10.1mybatisX代码快速生成
- 10.2快速CRUD
1.mybatis-plus简介及学习时的环境
a)什么是mybatis-plus
是mybatis的增强工具,在mybatis的基础上只做增强不做改变,为简化开发,提高效率而生。
b)框架结构
c)学习环境
IDE:idea 2022.1
JDK:JDK8+
构建工具:maven 3.6.3
MySQL版本:MySQL 8.0.29
Spring Boot:2.7.2
MyBatis-Plus:3.5.1
2.一个入门案例
a)创建数据库及表
插入几条数据
b)创建springboot工程
使用 Spring Initializr 快速初始化一个 Spring Boot 工程
c)引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
d)安装lombok插件,高版本已内置
e)配置application.yaml
连接地址url
MySQL5.7版本的url:
jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
MySQL8.0版本的url:
jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized orrepresents more
spring:
#配置数据源信息
datasource:
#配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
#配置链接数据库的各个信息
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: root
password:
d)创建实体类
@Data//这个注解可以代替下面的全部
//@NoArgsConstructor
//@ToString
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
e)创建mapper接口并扫描
@Mapper
//继承mybatisplus提供的BaseMapper即可以快速实现对单表的增删改查,就可以省去自己写sql语句了
public interface UserMapper extends BaseMapper <User> {
}
不用@mapper注解也可以,在主类上加上@MapperScan注解表示mapper的包名也可以
f)测试
@SpringBootTest
class MybatisplusDemoApplicationTests {
@Autowired
UserMapper userMapper;//这里报错不用管,不爽的话可以换成@Resource
@Test
public void testSelectList(){
//通过条件构造器来查询一个集合,没有条件设置为null
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
g)加入日志功能
在配置文件中配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
加入日志后,在控制台就可以看到mybatis-plus为我们生成的sql语句了
3.基本CRUD
3.1BaseMapper的基本功能测试
Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能,点进BaseMapper,会发现里面有非常多的方法。
a)测试基础插入方法
@Test
public void testInsert(){
User user = new User();
user.setAge(23);
user.setEmail("zhangsan@163.com");
user.setName("zhangsan");
int result = userMapper.insert(user);//返回的是受影响的行数
System.out.println(result);//1
System.out.println(user.getId());//在mybatis_plus中,使用的是雪花算法来生成id,所以数据的表id是bigint类型
}
b)测试基础删除功能
删除的方法共有五个
@Test
public void testDeteleByid(){
// int result = userMapper.deleteById(1557202548075319297l); 通过id来删除用户信息
// Map<String,Object> map = new HashMap<>(); 根据map集合中设置的条件来删除
// map.put("name","zhangsan");
// map.put("age",23);
// int result = userMapper.deleteByMap(map);
List<Long> idList = Arrays.asList(1l, 2l, 3l); //根据list集合中的多个id实现批量删除
int result = userMapper.deleteBatchIds(idList);
System.out.println(result);
}
c)测试基础的修改功能
@Test
public void testUpdate(){
User user = new User();
user.setId(4l);
user.setName("lisi");
user.setEmail("lisi@163.com");
int result = userMapper.updateById(user);//根据id来修改用户信息
System.out.println(result);
}
d)测试基础的查询功能
@Test
public void testSelect(){
//SELECT id,name,age,email FROM user WHERE id=?
User user = userMapper.selectById(1l);//根据id来查询用户信息
//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
List<User> users = userMapper.selectBatchIds(Arrays.asList(1l, 2l, 3l));//根据多个id来查询多个用户信息
Map<String,Object> map = new HashMap<>();
map.put("name","jack");
map.put("age",20);
//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
List<User> users1 = userMapper.selectByMap(map);//根据map集合中的条件来查询用户信息
//SELECT id,name,age,email FROM user
List<User> users2 = userMapper.selectList(null);//使用条件构造器来查询用户,null就是查询所有
}
3.2BaseMapper的自定义功能
mybatis-plus在mybatis之上只做增强,不做修改,所以按照我们之前mybatis的写法即可,即创建一个映射文件
映射文件的默认位置:类路径下的所有xml
UserMapper接口中
/**
* 根据id查询用户信息为map集合
* @param id
* @return
*/
Map<String,Object> selectMapById(Long id);
映射文件中
<?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.javalearn.mybatisplus.mybatisplusdemo.mapper.UserMapper">
<!--Map<String,Object> selectMapById(Long id);-->
<select id="selectMapById" resultType="map">
select id,name,age,email from user where id = #{id}
</select>
</mapper>
3.3通用Service接口
a)官网说明
通用 Service CRUD 封装IService (opens new window)接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,
泛型 T 为任意实体对象
建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类
对象 Wrapper 为 条件构造器
MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑详情查看源码IService和ServiceImpl
b)创建service和实现类
service
//泛型是实体类对象
public interface UserService extends IService<User> {
}
实现类
//继承IService的实现类ServiceImpl,第一个参数是mapper接口,第二个参数是实体类
@Service//标识为组件
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
}
接下来简单测试几个功能,其余的根据方法名和官方文档可以自行学习
c)查询总记录数
@Test
public void testGetCount(){
long count = userService.count();
System.out.println(count);
}
d)批量添加功能
@Test
public void testInsertMore(){
List<User> list = new ArrayList<>();
for (int i=1;i<=10;i++){
User user = new User();
user.setName("aaa"+i);
user.setAge(2+i);
list.add(user);
}
boolean b = userService.saveBatch(list);//返回值代表操作是否成功
}
实现其实是单个添加由循环来实现的
4.常用注解
4.1@TableName
经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表
由此得出结论,MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决定,且默认操作的表名和实体类型的类名一致
那么实体类与表名不一致呢?
可以在实体类上用@TableName注解
或者也可以通过全局配置
4.2@TableId
经过以上的测试,MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认基于雪花算法的策略生成id
当我们的主键不是不叫id,就可以通过@TableId标明主键
这个注解中有两个属性:
1、value: 指定主键的字段,当实体类中的属性与表中的字段名不一样时使用
2、type: 设置主键的递增策略
将数据库的表的主键设置为自动递增后,需要使用type属性,不然生成的主键依旧是雪花算法
设置为AUTO的话,数据库表中的主键必须是自增的
我们也可以在配置文件中设置统一的全局主键生成策略
下面就来聊聊什么是雪花算法
背景:
需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。
数据库的扩展方式主要包括:业务分库、主从复制,数据库分表。
思想:
雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
长度共64bit(一个long型)。
优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
4.3@TableField
若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格例如实体类属性userName,表中字段user_name,此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
若实体类中的属性和表中的字段不满足例如实体类属性name,表中字段username,此时需要在实体类属性上使用@TableField(“username”)设置属性所对应的字段名
4.4@TableLogic
什么是逻辑删除?
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
使用场景:可以进行数据恢复
使用方法:在表中新增一个字段
此时我们执行删除id为1、2、3的数据后发现生成的sql语句变了
此时再查询时,查不到id为1、2、3的数据了,也就是说,删除功能会自动转化为修改逻辑删除位,并且查询功能只能查询逻辑删除位为0的数据
5、条件构造器和常用接口
5.1Wapper
如果要通过各种条件来实现查询修改删除功能,就需要使用到条件构造器Wapper了
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
5.2QueryWrapper
a)查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
@Test
public void test01(){
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.like("user_name","a")//第一个参数是表中的字段名,第二个数据是模糊查询的参数,注意都是表中的字段名,不是实体类的属性名
.between("age",20,30)
.isNotNull("email");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
b)按年龄降序查询用户,如果年龄相同则按id升序排列
@Test
public void test02(){
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.orderByDesc("age")
.orderByAsc("uid");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
c)删除email为空的用户
@Test
public void test03(){
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.isNull("email");
userMapper.delete(queryWrapper);
}
d)使用QueryWrapper实现修改功能
QueryWrapper只能设置查询的条件,所以我们需要传入参数来设置修改的值
@Test
public void test04(){
//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
//注意,我们的条件默认是用and连接的,若需要用or,需要调用or方法
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.gt("age",20)
.like("user_name","a")
.or()
.isNull("email");
User user = new User();
user.setName("小明");
user.setEmail("123");//修改姓名与邮箱
userMapper.update(user,queryWrapper);//第一个参数用于设置修改内容,第二个参数用于设置条件
}
e)条件的优先级
@Test
public void test05(){
//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
//lambda中的条件会优先执行
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.like("user_name","a")
.and(i->i.gt("age",20).or().isNull("email"));
User user = new User();
user.setName("小红");
user.setEmail("123");//修改姓名与邮箱
userMapper.update(user,queryWrapper);
}
.or方法也可以同样用lambda表达式实现类似的效果
f)查询指定的字段
@Test
public void test06(){
//查询用户信息的username和age字段
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.select("user_name","age");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}
g)子查询
@Test
public void test07(){
//查询id小于等于100的用户信息
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.inSql("uid","select uid from t_user where uid <= 100");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
e)模拟实际开发中的组装条件
@Test
public void test09(){
//模拟浏览器传来的数据
String username = "";
Integer ageBegin = 20;
Integer ageEnd = 30;
QueryWrapper<User> queryWrapper = new QueryWrapper();
//这里的StringUtils选择mybatisplus下的
if (StringUtils.isNotBlank(username)){
//isNotBlank判断某个字符串不为空,不为null
queryWrapper.like("user_name",username);
}
if (ageBegin!=null){
queryWrapper.ge("age",ageBegin);
}
if (ageEnd!=null){
queryWrapper.le("age",ageEnd);
}
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
这种写法想对而言比较麻烦,使用下文的condition组装条件会更加简洁
使用带有condition条件的方法即可
@Test
public void test10(){
//模拟浏览器传来的数据
String username = "";
Integer ageBegin = 20;
Integer ageEnd = 30;
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.like(StringUtils.isNotBlank(username),"user_name",username)
.ge(ageBegin!=null,"age",ageBegin)
.le(ageEnd!=null,"age",ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
5.3UpdateWapper
a)将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
@Test
public void test08(){
UpdateWrapper<User> updateWrapper = new UpdateWrapper();
updateWrapper.like("user_name","a")
.and(i->i.gt("age",20).or().isNull("email"));
updateWrapper.set("user_name","小黑").set("email","abc");//这样设置修改的字段
userMapper.update(null,updateWrapper);//和queryWrapper的不同点是这里不用传要修改的参数了
}
5.4LambdaQueryWrapper&LambdaUpdateWrapper
这两个类可以防止我们写错数据库表中的字段名
可以直接利用实体类中的属性对应数据库表中的属性
@Test
public void test11(){
//模拟浏览器传来的数据
String username = "q";
Integer ageBegin = null;
Integer ageEnd = 30;
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(username), User::getName,username)
.ge(ageBegin!=null,User::getAge,ageBegin)
.le(ageEnd!=null,User::getAge,ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
另一个也是一样的,用lambda表达式来代替自己写字段名
@Test
public void test12(){
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.like(User::getName,"a")
.and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
updateWrapper.set(User::getName,"zhangsan").set(User::getEmail,"123");
userMapper.update(null,updateWrapper);
}
6.插件
6.1分页插件
a)简单的配置
新建一个配置类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
a)一个简单的测试
@Test
public void testPage(){
Page<User> page = new Page<>(2,3);//表示当前是第二页,每页三条数据
userMapper.selectPage(page,null);//null代表没有查询条件,即所有数据
System.out.println(page);
}
并且可以通过这个page对象来获取相关数据
b)自定义分页功能
假设在UserMapper中有一个方法,需要根据年龄来查询用户信息
//通过年龄来查询用户信息并分类
//page为Mybatis-plus所提供的分页对象,必须位于第一个参数的位置
Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
注意先在yaml配置文件中配置类型别名
然后是xml文件中的,注意,不需要我们写分页,我们只需要写查询条件即可,mybatis-plus会自动给我们分页
<!--Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);-->
<select id="selectPageVo" resultType="User">
select uid,user_name,age,email from t_user where age > #{age}
</select>
测试
@Test
public void testPageVo(){
Page<User> page = new Page<>(1,3);
userMapper.selectPageVo(page,20);
}
6.2乐观锁插件
乐观锁:操作数据前,会先检查数据有没有被别人操作过,如果被修改过,则操作失败,需要重新取出被修改后的数据进行操作,经常用版本号实现。
悲观锁:取数据后就对数据进行上锁,别人都无法再操作这个数据,只有自己操作完释放锁后,别人才能取出数据进行操作
a)模拟修改冲突
首先创建一张新的表,并创建其对应的实体类与mapper接口
@Test
public void product01(){
//员工1查询商品价格
Product product1 = productMapper.selectById(1);
System.out.println("员工1查询的商品价格"+product1.getPrice());
//员工2查询商品价格
Product product2 = productMapper.selectById(1);
System.out.println("员工2查询的商品价格"+product2.getPrice());
//员工1将商品价格+50
product1.setPrice(product1.getPrice()+50);
productMapper.updateById(product1);
//员工2将商品价格-30
product2.setPrice(product2.getPrice()-30);
productMapper.updateById(product2);
//老板的本意是先上调50,再下调30,但最后的结果却是值下调了30
Product product = productMapper.selectById(1);
System.out.println(product.getPrice());
}
b)使用乐观锁插件来阻止上述操作冲突
修改实体类,标识乐观锁版本号字段
在配置类中添加乐观锁插件
这样修改后,员工2在修改价格时,由于员工1先进行修改,员工2发现版本号不一致,所以员工2的修改操作没有被执行
7.通用枚举
表中的有些字段值是固定的,例如性别(男或女),此时我们可以使用MyBatis-Plus的通用枚举来实现
添加性别字段
a)创建枚举类
@Getter
public enum SexEnum {
MALE(1,"男"),
FEMALE(2,"女");
private Integer sex;
private String sexName;
SexEnum(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}
b)设置配置
注意,我们在数据库中存储的是数字1,2并不是男女,所以这里我们就需要使用mybatis-plus给我们提供的注解和配置了
c)测试添加,正常运行
@Test
public void test(){
User user = new User();
user.setName("admin");
user.setAge(33);
user.setSex(SexEnum.MALE);
userMapper.insert(user);
}
8.代码生成器
mybatis中的逆向工程时通过表来逆向生成实体类,mapper接口以及映射文件,而在mybatis-plus中,是通过表生成更多的代码。
a)引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
b)创建一个测试类,快速生成代码
public class FastAutoGeneratorTest {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "你的密码")
.globalConfig(builder -> {
builder.author("atguigu") // 设置作者
// .enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://mybatis_plus"); // 指定输出目录
}).packageConfig(builder -> {
builder.parent("com.atguigu") // 设置父包名
.moduleName("mybatisplus") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("t_user") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默认的是Velocity引擎模板
.execute(); }
}
生成完成后会自动打开目录
9.多数据源
适用于多种场景:纯粹多库、 读写分离、 一主多从、 混合模式等
下面来模拟纯粹多库的场景,其余的类似
们创建两个库,分别为:mybatis_plus(以前的库不动)与mybatis_plus_1(新建),将mybatis_plus库的product表移动到mybatis_plus_1库,这样每个库一张表,通过一个测试用例,分别获取用户数据与商品数据,如果获取到说明多库模拟成功
a)引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
b)配置多数据源
spring:
# 配置数据源信息
datasource:
dynamic:
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
strict: false
datasource:
#默认数据源
master:
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password:
#从数据源
slave_1:
url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password:
c)创建用户和商品的Service
注意,实现类需要指定操作哪个数据源
然后就可以用这两个service来分别操作两个数据库了,更多细节可以访问官方文档
10.mybatisX插件
a)安装插件
在真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL,多表联查,我们就需要自己去编写代码和SQL语句,我们该如何快速的解决这个问题呢,这个时候可以使用MyBatisX插件
MyBatisX一款基于 IDEA 的快速开发插件,为效率而生
插件用法:
https://baomidou.com/pages/ba5b24/
10.1mybatisX代码快速生成
注意,该插件需要先连接上数据库,点击下图的database
点击+号选择mysql,然后根据提示输入信息即可
右键点击表,就可以看到生成的选项
根据需求填即可
点击finish,就完成了代码生成
10.2快速CRUD
以insert为例,我们在mapper接口中输入insert,就可以看到mybatis-plus为我们提供的模板
alt+insert选择第一个
方法已被补全
并且xml文件中的sql也已经生成
其余的修改和删除也一样,如果有多个条件直接用and连接即可