MybatisPlus官网,点此进入
mybtis简化jdbc,mybatisPlus简化mybatis
1.无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
2.损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
3.强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
4.支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
5.支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
6.支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
7.支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
8.内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
9.内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
10.分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
11.内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
12.内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
现在我们只能看到查询结果,而看不到执行的sql语句,所以我们必须要看日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
@Test
public void testInsert(){
User user = new User();
user.setName("sxh22");
user.setAge(19);
user.setEmail("[email protected]");
int result=userMapper.insert(user); //自动生成id
System.out.println(result); //受影响的行数
}
默认使用:
@TableId(type = IdType.NONE)
分布式系统唯一id生成方案
雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。
其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。雪花算法支持的TPS可以达到419万左右(2^22*1000)
1.添加注解
@TableId(type = IdType.AUTO)
2.数据库字段一定要设置为自增
@TableId(type = IdType.INPUT) //手动输入
不传参数时,默认为null
创建时间,修改时间,自动操作更新,避免手动更新
1.在表中新增字段create_time,update_time
将默认值设为:CURRENT_TIMESTAMP
勾选更新
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
编写处理器,处理这个注解
@Component //把处理器加入到IOC容器中
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//更新时候的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
@Test
public void selectById(){
//按id查询
User user=userMapper.selectById(1L);
System.out.println(user);
}
@Test
public void selectByBatchIds(){
//批量查询
List<User> userlist=userMapper.selectBatchIds(Arrays.asList(1L,2L));
userlist.forEach(System.out::println);
// System.out.println(userlist);
}
//按自定义条件查询 map
@Test
public void selectByMap(){
HashMap<String,Object> map = new HashMap<>();
//自定义查询条件
map.put("name","kkk");
List<User> userlist= userMapper.selectByMap(map);
userlist.forEach(System.out::println);
}
@Test
public void testPage(){
Page<User> page=new Page<>(1,5); //当前页 每页条数
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}
@Test //测试删除
public void TestDeleteById(){
userMapper.deleteById(1438051051285536769L);
}
@Test //批量删除
public void TestDeleteBatchIds(){
userMapper.deleteBatchIds(Arrays.asList(1L,2L,3L));
}
@Test //map条件删除
public void TestDeleteByMap(){
HashMap<String,Object> map = new HashMap<>();
//自定义删除的条件
map.put("name","kkk");
userMapper.deleteByMap(map);
}
并没有从数据库中直接删除,而是标记了deleted,默认为0,代表没有被删除
类似于回收站
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
查询的时候会自动过滤被逻辑删除的记录
乐观锁:十分乐观,总是认为不会出现认为不会出现问题,无论什么操作都不会上锁,如果出现问题,就在测试加锁
@Version //代表这是一个乐观锁
private int version;
3.注册组件
@MapperScan("com.sxh.mybatisplus.mapper")//这种方式比@Mapper更灵活
@EnableTransactionManagement //自动管理事务
@Configuration //表明这是一个配置类
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
测试乐观锁:
@Test
public void testOptimisticLocker(){
//单线程情况下:成功
//1.查询
User user=userMapper.selectById(1L);
//2.修改
user.setName("kkk");
//3.执行更新操作
userMapper.updateById(user);
}
@Test
public void testOptimisticLocker2(){
//第一个线程
User user=userMapper.selectById(1L);
user.setName("kkk2");
//模拟第二个线程插队
User user2=userMapper.selectById(1L);
user2.setName("kkk3");
userMapper.updateById(user2); //如果没有乐观锁就会覆盖 执行了
userMapper.updateById(user); //如果没有乐观锁就会覆盖 没有执行
}
悲观锁:悲观,任何操作都加锁
在开发中的一些慢sql
在 MybatisPlus3.2.0 后,性能分析插件被移除了,官方推荐使用第三方性能分析插件
@Test
void contextLoads() {
System.out.println(("----- 查询name不为空的用户,并且邮箱不为空,年龄大于等于12 ------"));
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
List<User> userList = userMapper.selectList(wrapper);
// Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
@Test
void Testeq() {
//查询name等于宋先慧
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","宋先慧");
User user=userMapper.selectOne(wrapper); //selectOne查询一条数据
System.out.println(user);
}
@Test
void TestBetween() {
//查询age 20-30之间的数据
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,30); //区间
int num=userMapper.selectCount(wrapper);//selectCount 返回查询结果数
System.out.println(num);
}
@Test
void TestLike() {
//模糊查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notLike("name","e")//name不包含e的
.like("name","") //name包含e的
.likeRight("email","t") //t%
.likeLeft("email","t"); //%t
List<Map<String,Object>> maps=userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
@Test
void Testinner(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//子查询
wrapper.inSql("id","select id from user where age>12");
List<Object> list=userMapper.selectObjs(wrapper);
list.forEach(System.out::println);
}
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.4.1version>
dependency>
public class CodeGenerator {
public static void main(String[] args) {
//构建一个代码自动生成器对象
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java"); //路径
gc.setAuthor("songxh"); //作者
gc.setOpen(false); //不打开文件夹
gc.setFileOverride(false);//不覆盖原来生成的
// gc.setSwagger2(true); 实体属性 Swagger2 注解
gc.setServiceName("%sService"); //去I前缀
gc.setIdType(IdType.AUTO);
gc.setDateType(DateType.ONLY_DATE);//日期类型
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
// pc.setModuleName(scanner("模块名"));
pc.setParent("com.sxh.c");
pc.setEntity("pojo");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setInclude("user");//设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
/* strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");*/
strategy.setEntityLombokModel(true);
// strategy.setRestControllerStyle(true);
strategy.setLogicDeleteFieldName("deleted");
//自动填充配置
TableFill createTime=new TableFill("create_time", FieldFill.INSERT);
TableFill updateTime=new TableFill("update_time", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills=new ArrayList<>();
tableFills.add(createTime);
tableFills.add(updateTime);
strategy.setTableFillList(tableFills);
//乐观锁
strategy.setVersionFieldName("version");
//开启驼峰命名
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
// 公共父类
/* strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");*/
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");
//strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}