目录
一.使用的好处
- 1.无侵入式,只做增强不做改变
- 2.损耗小,启动即会自动注入基本crud,加入项目中并不会使代码性能变差
- 3.强大的crud:内置通用的Mapper和service
- 4.内置代码生成器:可快速生成Mapper,model,service,controller层代码
- 5.内置分页插件(类似pageHelper)
- 6.支持超多数据库,基本上常见的都支持
二.经典HelloWorld入门程序
1.建表
DROP TABLE IF EXISTS user;
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)
);
引入数据
DROP TABLE IF EXISTS user;
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)
);
2.引入依赖
注意:说明:我们使用mybatis-plus可以节省我们大量的代码,尽量不要同时导入mybatis和mybatis-plus! 版本的差异!
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
3.配置日志
在application.yml文件中添加
#spring事务管理日志
logging:
level:
com.wal: debug
mybatis-plus:
configuration:
#输出mybatis日志,并打印到控制台上
logImpl: org.apache.ibatis.logging.stdout.StdOutImpl
#打开mybatis驼峰转换开关a_column -> aColumn
mapUnderscoreToCamelCase: true
4.创建项目
entity.user类,@Data来自lombok,可以简化代码的get、set方法
import java.io.Serializable; //写类的时候要习惯将其序列化
@Data
public class User implements Serializable {
private Long id;
private String name;
private Integer age;
private String email;
}
mapper.userMapper接口
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wal.entity.User;
@Mapper
public interface UserMapper extends BaseMapper<User> {
//所有的CRUD已经编写完成
//不需要像以前的配置一些xml
}
接着我们在springtest里进行测试
这里使用@Autowired会标红线,但实际上是没有错误的,可以使用@Resiurce解决
UserMapper 中的
selectList()
方法的参数为 MP 内置的条件封装器Wrapper
,所以不填写就是无任何条件
@SpringBootTest
public class UserMapperTest {
@Resource
private UserMapper userMapper;
@Test
public void testGetAll(){
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
记得在启动类上写一个@MapperScan("com.wal.*.mapper") 去扫描你要使用的mapper,这样@AutoWired和@Resource才能扫描到
成功打印
再写一个简单的增加对象
@Test
public void testAdd(){
User user = new User(6L,"wal",21,"an1ong");
userMapper.insert(user);
}
非常好用
三.注解说明
@TableName()
假设你的数据库表名为user_info,但是你在创建其对应的类时就像叫他user表,那么就使用该注解
@Table("user_info")
public class User implements Serializable{
}
@TableField()
- 和上一个注解一样,你的字段里有email,但你就是想使用mail,就使用value参数
- 其次假设你在实际开发中需要添加一个字段,在user表中添加字段status,但是数据库表中并不需要,此时使用exist参数
- 不想再查询时查询到此字段,使用select参数
@Table("user_info")
public class User implements Serializable{
//重命名
@TableField(value="email")
private String mail;
//不添加到数据库字段
@TableField(exist=false)
private int status;
//不参与查询
@TableField(select=false)
private float salay;
}
@TableId()
主键注解,添加数据时,默认使用雪花算法计算id
所以为了实现id能够自增,需要使用该注解
@TableId(type = IdType.AUTO)
private Long id;
注意在这里要修改一下数据库默认的自动增量,不然会报错
四.乐观锁
乐观锁:顾名思义十分乐观,它总是被认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再次更新测试。
悲观锁:顾名思义十分悲观,它总是出现问题,无论干什么都会上锁!再去操作!
实现方式
- 取出记录是,获取当前version
- 更新事,带上这个version
- 执行更新时,set version=newVersion where version =oldVersion
- 如果version不对,就更新失败
乐观锁: 1、先查询,获得版本号 version=1
--A
update user set name ="shuishui" ,version =version+1
where id =2 and version=1
--B 如果线程抢先完成,这个时候version=2,会导致A修改失败
update user set name ="shuishui" ,version =version+1
where id =2 and version=1
使用步骤
表中需要有字段version(版本号)
创建config类(配置拦截器)
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MbspConfig {
//配置拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//这里可以添加多个拦截器
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
在表的类中添加
//乐观锁版本号
@Version
private Integer version;
模拟并发测试
@Test
public void addMoney1(){
System.out.println("A用户存钱");
User user = userMapper.selectById(6);
System.out.println(user.getSal());
user.setSal(user.getSal()+100);
userMapper.updateById(user);
System.out.println(user.getSal());
}
@Test
public void addMoney2(){
System.out.println("B用户存取");
User user = userMapper.selectById(6);
System.out.println(user.getSal());
user.setSal(user.getSal()+200);
userMapper.updateById(user);
System.out.println(user.getSal());
}
五.分页查询
配置分页拦截器
@Configuration
public class MbspConfig {
//配置拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//这里可以添加多个拦截器,
//乐观锁拦截器
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//分页查询拦截器,不同的数据库要使用不同的配置
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
使用
Page有两个参数
current:当前页
size:一页放几条数据
@Test
public void testSelectAll(){
//分页查询
Page<User> page = new Page<>(1,3);
userMapper.selectPage(page,null);
System.out.println("总共"+page.getTotal());
List<User> records = page.getRecords();
records.forEach(System.out::println);
}
六.逻辑删除
- 并没有真正的在数据库中删除了,这是物理删除,假设以后删掉的数据还会用到,不推荐直接删除。
- 在当前的表中添加一个标记字段,标记这个数据是否处于删除状态,这是逻辑删除,适合数据量小的时候使用。
- 补充:还有一种方法是历史表删除,将删除的数据放在另一张历史表中记录。
使用
推荐使用全局配置,在yml配置文件中设计,这样可以不使用@TableLogic注解
mybatis-plus:
global-config:
db-config:
#全局逻辑删除的实体字段名,配置后可不用@TableLogic注解
logic-delete-field: deleted
#逻辑已删除
logic-delete-value: 1
#逻辑未删除
logic-not-delete-value: 0
@Test
public void deleteUser(){
userMapper.deleteById(8);
}
七.条件查询器
Wrapper
写一些复杂的sql就可以用这个代替
当然直接写xml也行
@Test
void contextLoads(){
// 查询name不为null的用户,并且邮箱不为null的永不,年龄大于等于20的用户
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.isNotNull("name");
wrapper.isNotNull("email");
wrapper.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}
@Test
void test2(){
// 查询name为shuishui的用户
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.eq("name","shuishui");
User user=userMapper.selectList(wrapper)
System.out.println(user);
}
@Test
void test3(){
// 查询年龄在20~30岁之间的用户
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.between("age",20,30);
Integer count =userMapper.selectCount(wrapper);//查询结果数
System.out.println(count);
}
//模糊查询
@Test
void test4(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.notLike("name",“s”);//相当于NOT LIKE '%s%'
wrapper.likeRight("email",“s”);//相当于LIKE 's%'
List<Map<String,Object>>maps =userMapper.selectMaps(wrapper);//查询结果数
maps.forEach(System.out::println);
}
@Test
void test5(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
//子查询
wrapper.insql("id","select id from user where id<3");
List<Object> objects =userMapper.selectobjs(wrapper);
objects.forEach(System.out::println);
}
@Test
void test6(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
//通过id进行排序
wrapper.orderByAsc("id");
List<User> users =userMapper.selectList(wrapper);
objects.forEach(System.out::println);
}
//姓王年龄大于等于25,按年龄降序,年龄相同按id升序排列
void test7(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.likeRoght("name","王").or().ge("age",25).ordeiByDesc("age").orderByAsc("id");
List<User> users =userMapper.selectList(wrapper);
objects.forEach(System.out::println);
}
//创建日期为2019年2月14日并且直属上级为姓王
void test8(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.apply("date_fromat(create_time,'%Y-%m-%d')='2019-02-14'").inSql("manager_id","select id from user where name like '王%'");
List<User> users =userMapper.selectList(wrapper);
objects.forEach(System.out::println);
}
//姓王并且(年龄小于40或者邮箱不为空)
void test9(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
//lt小于,gt大于
wrapper.likeRoght("name","王").and(wq->wa.lt("age",40).or().isNotNull("email"))
List<User> users =userMapper.selectList(wrapper);
objects.forEach(System.out::println);
}
//不列出所有字段
@Test
void test10(){
QueryWrapper<User> wrapper =new QueryWrapper<>();
wrapper.select("id","name").like("name","雨").lt("age",40);
//不显示时间和id
//wrapper.select(User.class,info->!info.getColumn().equals("create_time")&&!info.getColumn().equals("manager_id")).like("name","雨").lt("age",40);
List<User> users =userMapper.selectList(wrapper);
objects.forEach(System.out::println);
}
八.代码生成器
1.快速生成
(1).导入依赖
<!-- 代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- freemarker模板,如果不导入这个依赖的话默认使用的是Velocity-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
(2).创建代码生成器类
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql:///an1ong",
"root",
"123456")
.globalConfig(builder -> {
builder.author("wal") // 设置作者
// .enableSwagger() // 开启 swagger 模式
// .fileOverride() // 覆盖已生成文件
.outputDir("D:\\JAVA_project\\wal\\src\\main\\java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.wal") // 设置父包名
.moduleName("user") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml,
"D:\\JAVA_project\\wal\\src\\main\\resources\\mapper\\user")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("user_info","dept_info"); // 设置需要生成的表名
// .addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
(3).测试
2.交互式生成
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class FastCodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create(
new DataSourceConfig.Builder("jdbc:mysql:///an1ong","root","123456"))
// 全局配置
.globalConfig((scanner, builder) -> builder.author(scanner.apply("请输入作者名称?")).fileOverride())
// 包配置
.packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))
// 策略配置
.strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
.controllerBuilder().enableRestStyle().enableHyphenStyle()
.entityBuilder().enableLombok().addTableFills(
new Column("create_time", FieldFill.INSERT)
).build())
/*
模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
.templateEngine(new BeetlTemplateEngine())
*/
.templateEngine(new FreemarkerTemplateEngine())
.execute();
// 处理 all 情况
}
protected static List<String> getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
}
注意:它会默认在D盘根目录下创建
八.总结
mybatisPlus功能确实强大,sql语句都不用写,用代码生成器连文件都不需要自己创建,但是初学的话还是先把SSM熟悉之后再使用吧