导入依赖

<!--MP-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version>
</dependency>
<!-- 代码生成器-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.4.1</version>
</dependency>
<!-- 代码生成器模板引擎-->
<dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version>
</dependency>

雪花算法

数据库的扩展方式主要包括:业务分库,主从复制,数据库分表

数据库分表

​ 如果业务持续发展,同一业务的单表数据也会达到数据库服务器的处理瓶颈;例如淘宝几亿用户数据,因此需要对单表数据进行拆分。

垂直分表

​ 列也比较多,查询量比较大的时候,通常把经常被查询的字段 和 数据量比较大的字段,拆分到不同的表中,比如age,sex 主要是查询使用,nickname昵称字段和描述字段主要用于展示使用而且本身还比较长,可以将后面两个字段独立到另一个表中去,这样查询的age 和 sex时 能带来一定的性能提升,相当于对表垂直切了一刀,把非主要查询的这两个字段独立出去。也就是把大字段或一般查询用不到的字段分离到另外一张表中。user user_info 用 id进行关联,user id字段自增长,user_info id字段不设策略,user的id是啥 我就是啥

主键一对一关联

水平分表

适合表行数特别大的表,数据量特别大的时候,也没有明确查询字段之类的需求,关键还要看表的访问性能,一些比较复杂的表,可能超过1000万就要分表了,按数据分表,多少万条数据在一个表上,多少行数据在一个表上,相当于横着切一刀 分出去。水平分表相比垂直分表会引入更多的复杂性。

复杂性体现:主键自增问题 如果分2张表,按照主键范围存在不同的表上,比如1~1千万,1千万零一~2千万,分别在两张表上,如果满了 扩展容易,再加即可,实现了动态扩展,各表内数据量有多有少,现在一般都是负载均衡,会导致服务器访问不均衡。如果解决均衡问题,可以将表的主键起始id分表设为1、 2、 3 步长为3,这样就均衡了,但是扩展又会出问题,如果扩展又会出现数据迁移问题,重新分配布局。两种方式扩展都可能会遇到之前的表里面有数据被删除,然后后面的数据主键自增已经占用了新的主键,扩展的id并不是理论上应该存的id,而是之前的表可能已经用掉了。会不安全

解决办法:

Hash:取模运算,放到哪一个表中,要求初始表数量确定,表数量太多维护比较麻烦,太少又可能导致单表性能出现问题,表分布会比较均匀,但是扩展会很麻烦,所有数据都要重分布,uuid不能和mysql的聚簇索引一起用,不利于mysql查询优化

雪花算法snow flake(分布式id占19个符号位):mybatis-plus中默认的主键策略就是雪花算法

分布式主键生成算法,它能够保证不同表的主键不重复性,以及相同表的主键的有序性

核心思想:

长度64bit一个Long型,分四个部分:

1.第一个位置,符号位,为0,表示为正数,一般都不会用负数

2.第二个位置,时间戳位,41bit,存储的是差值,约定于69.73年,这样生成的时间都是不一样的

3.第三个位置,5bit是数据中心(相当于机房代码),5bit机器ID(表示数据中心存储数据的机器,可以部署在1024个节点,相当于1024台机器),

4.第四个位置,12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),支持并发量很大


mybatis-plus 默认识别 名字叫“id”的字段,自动进行雪花算法插入数据库id,如果数据库是uid实体类也是uid字段, 或者其他则识别不了,无法进行默认的雪花算法插入主键到数据库,会报错。所以此时需要在实体类的字段上加@TableId 告诉mybatis-plus这个字段是id 字段(数据库中是uid);

@TableName(value="t_user")
public class User {//默认雪花算法  也可以设置// @TableId(type= IdType.ASSIGN_ID) private String id; 也可以@TableIdprivate Long uid;

或者,数据库名字叫uid,实体类叫做id,也无法完成映射,所以需要加value属性,如同@TableName注解

 @TableName(value="t_user")
public class User {//@TableId(value = "uid",type = IdType.AUTO) 主键自增策略@TableId(value = "uid")private Long id;private String name;private int age;private String email;xxxxxxxxxx @TableId(value = "uid")private Long id;private String name;private int age;private String email;
​

业务中id为空,数据库中也没有设置id;id是主键,不能为空,所以在插入的时候就会报错。如果所有的表都要求主键自增,可以在配置文件中设置

#设置全局主键自增
mybatis-plus.global-config.db-config.id-type=auto

新增两个字段 ,如果类中的列名为驼峰命名

private LocalDateTime createTime;
private LocalDateTime updateTime;
//在数据库中字段为:create_time   update_time mybatis-plus 会自动把驼峰进行转换

如果数据库中的字段名跟实体类不一致,需要用@TableField(value="")

@TableId(value = "uid",type = IdType.AUTO)
private Long id;
@TableField(value = "username")
private String name;
private int age;
private String email;

数据库字段可进行自动填充,创建和更新时间 可以用CURRENT_TIMESTAMP 系统自动管理,更新字段,再勾上默认根据当前时间戳进行更新,这样管理就不需要每次业务里面涉及。也可以在业务层进行设计,自动填充功能,需要在实体类加注解来标识。

@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) //插入或更新的时候自动填充
private LocalDateTime updateTime;
//但是填充什么呢?需要定义实现自动填充功能 实现元对象处理器接口
@Slf4j
@Component
public class MyMeatObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {log.info("insert自动填充....");//插入数据的时候 识别到注解  @TableField(fill = FieldFill.INSERT) 就会进入这个方法来执行this.strictInsertFill(metaObject,"createTime", LocalDateTime.class, LocalDateTime.now());this.strictUpdateFill(metaObject,"updateTime", LocalDateTime.class, LocalDateTime.now());}@Overridepublic void updateFill(MetaObject metaObject) {log.info("update自动填充。。。");//更新的时候this.strictUpdateFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());}
}
​
//判断当前对象自动填充属性是否包含 当前属性
boolean hasAuthor = metaObject.hasSetter("author");
//如果 有setter的方法 有这个author字段 进行自动填充author
if(hasAuthor) {log.info("insert author属性");this.strictInsertFill(metaObject, "author", String.class, "石头");
}

年龄也自动填充

@TableField(fill = FieldFill.INSERT)private Integer age;
log.info("age 填充为18");//对age进行自动填充 当没传age的时候填充18进去
Object age = this.getFieldValByName("age", metaObject);
//如果业务层赋值了就不用去填充,如果没有赋值去进行填充
if(age==null){this.strictInsertFill(metaObject, "age", Integer.class, 18);}
​

@TableLogic 逻辑删除

物理删除:真实删除

逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录使用场景,可以进行数据恢复

数据库中此字段 一般默认类型tinyint类型,默认1为已删除,0未删除

在数据库中创建逻辑删除状态列 同时实体字段一般前面不要加is有些框架识别可能出问题

    //private Integer deleted;//逻辑删除字段   0表示false 1表述true@TableLogic@TableField(value = "is_deleted")private Boolean deleted;

执行记录 需要数据库中此字段 值为0

Preparing: UPDATE t_user SET is_deleted=1 WHERE uid=? AND is_deleted=0 ==> Parameters: 1499759447969390597(Long)<== Updates: 0

//自定义 1为未删除 -1为已删除 需要去配置
@TableLogic
@TableField(value = "is_deleted")
private Integer deleted;
mybatis-plus.global-config.db-config.logic-delete-field=deleted
mybatis-plus.global-config.db-config.logic-delete-value=-1
mybatis-plus.global-config.db-config.logic-not-delete-value=1

分页插件

1.添加配置类 config包 可以将配置全部写在这个包内

spring

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!-- 其他属性 略 --><property name="configuration" ref="configuration"/><property name="plugins"><array><ref bean="mybatisPlusInterceptor"/></array></property>
</bean>
​
<bean id="configuration" class="com.baomidou.mybatisplus.core.MybatisConfiguration"><!-- 需配置该值为false,避免1或2级缓存可能出现问题,该属性会在旧插件移除后一同移除 --><property name="useDeprecatedExecutor" value="false"/>
</bean>
​
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"/></list></property>
</bean>
​
<bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"><!-- 对于单一数据库类型来说,都建议配置该值,避免每次分页都去抓取数据库类型 --><constructor-arg name="dbType" value="H2"/>
</bean>

spring-boot

//可将包扫描写在这个类里面 也可以写在启动类上,对持久层的扫描
@Configuration//表示这是一个配置类,应用程序启动的时候会被自动读取并以配置的形式读取
@MapperScan("mybatisplus.mapper")//可以将持久层所有的配置集中在这里管理 全写在这个配置类中
public class MybatisPConfig {/*** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false* 避免缓存出现问题(该属性会在旧插件移除后一同移除)*///所有的插件都是以拦截器的形式存在@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {//先创建拦截器(插件)管理器MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件 将分页(这里是mysql)添加到一个内置的拦截器管理器中( 将分页插件的拦截器对象创建出来,然后用此方法配置到 这个管理器之中)interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//最后将这个interceptor对象,作为一个bean对象返回return interceptor;}//    @Bean
//    public ConfigurationCustomizer configurationCustomizer() {
//        return configuration -> configuration.setUseDeprecatedExecutor(false);
//    }
}

针对mysql的分页配置类 写好了。进行测试

@Slf4j
@SpringBootTest
public class IntercepterTest {@Resourceprivate UserMapper userMapper;@Resourceprivate ProductMapper productMapper;@Testpublic void test1(){//新建分页参数对象 查询第几页,每页5条记录Page<User> userPage = new Page<>(2, 5);//这两个对象是一个对象 参数为页对象 及qureyMapper条件构造器 先传null//Page<User> userPage1 = userMapper.selectPage(userPage, null);//System.out.println("确认是否是一个对象"+(userPage==userPage1)); true//优化为userMapper.selectPage(userPage, null);//当前页码下的所有记录List<User> users = userPage.getRecords();users.forEach(System.out::println);//总数long total = userPage.getTotal();System.out.println("总数+"+total);//有没有下一页boolean bn = userPage.hasNext();System.out.println("下一页??"+bn);//有没有上一页boolean bp = userPage.hasPrevious();System.out.println("上一页?"+bp);}

在xml中如何使用配置分页?

//@Repository
public interface UserMapper extends BaseMapper<User> {//自定义一个方法 具体的xml实现在resources下面的mapper文件中//扩展mapperList<User> selectAllByName(String name);//第一个参数为分页对象  第二个为查询条件  根据年龄来查询用户 并分页展示IPage<User> selectPageVo(IPage<?> page, Integer age);
 <select id="selectPageVo" resultType="mybatisplus.entity.User">select <include refid="Base_Colum_List"/>from t_user where age > #{age}</select>
</mapper>

xml中不需要去进行 分页,只需要写条件即可,我们传递了page对象进去,MP会自动的去读取参数中的配置对象,且会作为整个查询语句的后缀,然后执行sql

@Test
public void selectByAge(){Page<User> userPage = new Page<>(2,6);IPage<User> userIPage = userMapp      er.selectPageVo(userPage, 18);List<User> users = userIPage.getRecords();users.forEach(System.out::println);
}

执行语句为:自动追加

Total: 1==> Preparing: select uid,name,age,email from t_user where age > ? LIMIT ?,?==> Parameters: 18(Integer), 6(Long), 6(Long)<== Columns: uid, name, age, email<== Row: 1500133241527472131, 建国2, 22, jiangu2o@qq.com<== Row: 1500133241527472134, 建国更新, 100, jiangu2o@qq.com<== Row: 1500133241527472139, 观海200, 200, jianguo5@qq.com

但是实体类里面是 id 所以这里自定义的方法 的xml 需要改

<mapper namespace="mybatisplus.mapper.UserMapper">
<!--sql片段--><sql id="Base_Colum_List">uid as id,name,age,email,is_deleted as deleted,create_time as createTime,update_time as updateTime</sql><select id="selectAllByName" resultType="mybatisplus.entity.User">select <include refid="Base_Colum_List"/>from t_userwhere name = #{name}</select><select id="selectPageVo" resultType="mybatisplus.entity.User">select <include refid="Base_Colum_List"/>from t_user where age > #{age}</select>
​

==> Preparing: select uid as id,name,age,email,is_deleted as deleted,create_time as createTime,update_time as updateTime from t_user where age > ? LIMIT ?,?==> Parameters: 18(Integer), 6(Long), 6(Long)<== Columns: id, name, age, email, deleted, createTime, updateTime<== Row: 1500133241527472131, 建国2, 22, jiangu2o@qq.com, 0, 2022-03-06 14:38:17, 2022-03-06 14:38:17Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4e1459ea]User(id=1500133241527472131, name=建国2, age=22, email=jiangu2o@qq.com, createTime=2022-03-06T14:38:17, updateTime=2022-03-06T14:38:17, deleted=false)


MP的乐观锁应用

A和B都要对数据进行修改操作,但是取出的数据都是未更新过的数据,同时修改,存入就会存在数据覆盖的情况,出现错误数据。比如两个人同时修改某一商品的价格。一个增加一个减少,造成并发冲突,并发也不高但是造成数据不一致问题。可以通过乐观锁来解决

SELECT id,name,version FROM product WHERE id=1;

查询的时候就需要将 控制版本的version取出来 更新时,对version进行控制,每次有人修改的时候都需要提前判断,符合条件才能进行修改。每修改一次 版本号会加一

//告诉mp这 就是版本号@Versionprivate Integer version;
​
​
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;
}

Preparing: SELECT id,name,price,version FROM product WHERE id=?==> Parameters: 1(Long)<== Columns: id, name, price, version<== Row: 1, 笔记本, 150, 3

UPDATE product SET name=?, price=?, version=? WHERE id=? AND version=?==> Parameters: 笔记本(String), 200(Integer), 4(Integer), 1(Long), 3(Integer)

修改后 将版本号为3的记录 版本号更改为4 那么同时另外一条修改语句 则无法修改

=> Preparing: UPDATE product SET name=?, price=?, version=? WHERE id=? AND version=?==> Parameters: 笔记本(String), 120(Integer), 4(Integer), 1(Long), 3(Integer)<== Updates: 0

Wrapper条件构造

Wrapper → AbstractWrapper

AbstractLambdaWrapper(抽象类) → LambdaUpdateWrapper 和 LambdaQueryWrapper

UpdateWrapper QueryWrapper

/*** 查询名字中包含a* 年龄大于10且小于20 email不为空的用户*/
@Test
public  void test(){QueryWrapper<User> queryWrapper = new QueryWrapper<User>();//column对应数据库表的列名 而不是属性名queryWrapper.like("name","a");//左侧为%queryWrapper.likeLeft("name","k");//gt为>  ge为≥  lt为<  le为≤queryWrapper.gt("age",10).lt("age",20).isNotNull("email");List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);//between 大于等于 小于等于queryWrapper.between("age",0,20);

Preparing: SELECT uid AS id,name,age,email,create_time,update_time,is_deleted AS deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND name LIKE ? AND age > ? AND age < ? AND email IS NOT NULL)==> Parameters: %a%(String), %k(String), 10(Integer), 20(Integer)<== Columns: id, name, age, email, create_time, update_time, deleted<== Row: 1499409859102179330, jack, 18, jianguo@qq.com, null, null, 0

case函数

按照姓名 分国籍 操作
SELECT( CASE NAME WHEN 'jack' THEN '美国' WHEN '花花' THEN '日本' WHEN '建国' THEN '中国' ELSE '韩国' END ) country ,sum(age) 总年龄
FROM`t_user` GROUP BY(CASE NAME WHEN 'jack' THEN '美国' WHEN '花花' THEN '日本' WHEN '建国' THEN '中国' ELSE '韩国' END);
/*** 按年龄降序查询用户,如果年龄相同则按id升序排序*/
@Test
public void test2() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();//组装排序条件queryWrapper.orderByDesc("age").orderByAsc("uid");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);
}

Preparing: SELECT uid AS id,name,age,email,create_time,update_time,is_deleted AS deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC==> Parameters: <== Columns: id, name, age, email, create_time, update_time, deleted

/*** 删除email为空的用户*/
@Test
public void test3(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email");int res = userMapper.delete(queryWrapper);System.out.println("删除的记录数:"+res);//之前配置了逻辑删除,所以只是把is_deleted更新为1
}

Preparing: UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)

/*** 查询名字中包含花 且(年龄小于12或email为空的用户),并将这些用户的年龄设置为18,设置为user@haha.com*/
@Test
public void test4(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("name","花").and(i->i.lt("age",18).or().isNull("email"));User user = new User();user.setAge(18);user.setEmail("user@haha.com");int res = userMapper.update(user, queryWrapper);System.out.println("更新的条数为:"+res);

Preparing: UPDATE t_user SET age=?, email=?, update_time=? WHERE is_deleted=0 AND (name LIKE ? AND (age < ? OR email IS NULL))==> Parameters: 18(Integer), user@haha.com(String), 2022-03-14T23:07:38.807(LocalDateTime), %花%(String), 18(Integer)<== Updates: 5

查询所有用户的用户名和年龄 其他的不要

//查询用户名和年龄 其他的不要
@Test
public void test5(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("name","age");//其他属性 不会返回 返回的是map泛型//select语句通常会和selectMaps一起出现List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);
}

==> Preparing: SELECT name,age FROM t_user WHERE is_deleted=0==> Parameters: <== Columns: name, age<== Row: Jack, 20<== Row: 正阳, 20<== Row: Billie, 24

/*** 使用子查询* 查询id不大于3的所有用户的id列表*/
@Test
public void test6(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();//如果子查询由用户输入 容易sql注入 queryWrapper.inSql("uid","select uid from t_user where uid<=3");// 可以这么写 queryWrapper.le("uid",3);List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
}

SELECT uid AS id,name,age,email,create_time,update_time,is_deleted AS deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid<=3))==> Parameters: <== Columns: id, name, age, email, create_time, update_time, deleted<== Row: 2, Jack, 20, test2@baomidou.com, null, null, 0<== Total: 1

UpdateWrapper

/*** 查询名字中包含花 且(年龄小于等于18或email不为空的用户),并将这些用户的年龄设置为16,设置为user@updateWrapper.com*/@Testpublic void test7(){UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.set("age",16).set("email","user@updateWrapper.com").like("name","花").and(i-> i.le("age",18).or().isNotNull("email"));//如果有自动填充功能,必须要把user对象传进去,否则 无法实现,比如updateTime//不需要 可以传nullUser user = new User();int res = userMapper.update(user, updateWrapper);System.out.println("更新的条数为:"+res);}

Preparing: UPDATE t_user SET age=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age <= ? OR email IS NOT NULL))==> Parameters: 16(Integer), user@updateWrapper.com(String), %花%(String), 18(Integer)<== Updates: 5

==> Preparing: UPDATE t_user SET update_time=?, age=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age <= ? OR email IS NOT NULL))==> Parameters: 2022-03-14T23:33:21.205(LocalDateTime), 16(Integer), user@updateWrapper.com(String), %花%(String), 18(Integer)<== Updates: 5

condition 动态组装查询条件

/*** 查询名字中含有 n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选择的*/
@Test
public void test8() {String username = "花";Integer ageBegin =10;Integer ageEnd = 20;QueryWrapper<User> queryWrapper = new QueryWrapper<>();if (StringUtils.isNotBlank(username)) {queryWrapper.like("name", username);}if(ageBegin!=null){queryWrapper.ge("age",ageBegin);}if(ageEnd !=null) {queryWrapper.le("age", ageEnd);}List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
}
//利用重载的方法@Testpublic void test8() {String username = "花";Integer ageBegin = null;Integer ageEnd = 20;QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(username), "name", username).ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
​}

Preparing: SELECT uid AS id,name,age,email,create_time,update_time,is_deleted AS deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND age >= ? AND age <= ?)==> Parameters: %花%(String), 10(Integer), 20(Integer)<== Columns: id, name, age, email, create_time, update_time, deleted<== Row: 1499759447893893121, 花花0, 16, user@updateWrapper.com, null, 2022-03-14 23:33:21, 0

SELECT uid AS id,name,age,email,create_time,update_time,is_deleted AS deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND age <= ?)==> Parameters: %花%(String), 20(Integer)<== Columns: id, name, age, email, create_time, update_time, deleted<== Row: 1499759447893893121, 花花0, 16, user@updateWrapper.com, null, 2022-03-14 23:33:21, 0<== Row: 1499759447969390594, 花花1, 16, user@updateWrapper.com, null, 2022-03-14 23:33:21, 0<== Row: 1499759447969390595, 花花2, 16, user@updateWrapper.com, null, 2022-03-14 23:33:21, 0

lambdaQueryWrapper

/*** 查询名字中含有 n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选择的*/
@Test
public void test9() {String username = "花";Integer ageBegin = null;Integer ageEnd = 20;LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.like(StringUtils.isNotBlank(username), User::getName, username).ge(ageBegin != null, User::getAge, ageBegin).le(ageEnd != null, User::getAge, ageEnd);List<User> users = userMapper.selectList(lambdaQueryWrapper);users.forEach(System.out::println);
}

lambdaUpdateWrapper

/*** 查询名字中包含花 且(年龄小于等于18或email不为空的用户),并将这些用户的年龄设置为16,设置为user@updateWrapper.com*/
@Test
public void test10() {LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.set(User::getAge, 16).set(User::getEmail, "user@updateWrapper.com").like(User::getName, "花").and(i -> i.le(User::getAge, 18).or().isNotNull(User::getEmail));//如果有自动填充功能,必须要把user对象传进去,否则 无法实现,比如updateTime//不需要 可以传nullUser user = new User();int res = userMapper.update(user, updateWrapper);System.out.println("更新的条数为:" + res);
}

其实就是把条件组装里的字符串形式 替换为Lambda替换,避免编译的时候没有发现的不必要的错误。


Gennerator代码生成器

public class CodeGenerator {@Testpublic void genCode(){// 代码生成器AutoGenerator mpg = new AutoGenerator();
​// 全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir");gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("eric");//去掉Service接口的首字母I 不加 接口名字前面会有I %s是占位符 实体名字gc.setServiceName("%sService");//生成后是否打开资源管理器gc.setOpen(false);//主键策略gc.setIdType(IdType.AUTO);//开启swagger2模式gc.setSwagger2(true);mpg.setGlobalConfig(gc);
​// 数据源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://localhost:3306/srb_core?serverTimezone=GMT%2B8&characterEncoding=utf8");// dsc.setSchemaName("public");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("root");dsc.setDbType(DbType.MYSQL);mpg.setDataSource(dsc);
​// 包配置PackageConfig pc = new PackageConfig();
//        pc.setModuleName();pc.setParent("com.xie.srb.core");//此对象与数据库表结构一一对应,通过dao层向上传输数据源对象pc.setEntity("pojo.entity");
//        pc.setService();
//        pc.setXml();mpg.setPackageInfo(pc);
​// 策略配置StrategyConfig strategy = new StrategyConfig();//数据库表映射到实体的命名策略 数据库表名称 下划线变驼峰strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略 列名转驼峰strategy.setColumnNaming(NamingStrategy.underline_to_camel);
​// strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");strategy.setEntityLombokModel(true);//逻辑删除字段strategy.setLogicDeleteFieldName("is_deleted");//去掉布尔值的is_前缀(确保tinyint(1) 实体类中最好不要用is做前缀 容易出问题 变成deleted 会加字段映射@TableFieldstrategy.setEntityBooleanColumnRemoveIsPrefix(true);//restful风格控制器 一般都会返回json 有@ResponseBody  会直接用@RestControllerstrategy.setRestControllerStyle(true);mpg.setStrategy(strategy);//执行mpg.execute();
​}
}

核心模块的yml配置

erver:port: 8110
spring:profiles:active: devapplication:# 以后要注册到微服务中 起一个 服务名name: service-coredatasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/srb_core?serverTimezone=GMT%2B8&characterEncoding=utf8username: rootpassword: root
mybatis-plus:configuration:#日志输出log-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:com/xie/srb/core/mapper/xml/*.xml

创建主类

package com.xie.srb.core;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
​
@SpringBootApplication
@ComponentScan("com.xie.srb")
public class ServiceCoreApplication {public static void main(String[] args) {SpringApplication.run(ServiceCoreApplication.class,args);}
}
​

配置MP分页

package com.xie.srb.core.config;
/*** 配置分页*/
@Configuration
@MapperScan("com.xie.srb.core.mapper")
//事务处理
@EnableTransactionManagement
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//分页interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return  interceptor;}
}
<build><resources><!-- xml放在java目录--><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><!-- 指定资源的位置(xml放在resources下可以不用指定 --><resource><directory>src/main/java/com/xie/srb/core/mapper/xml</directory></resource></resources>
</build>

Mybatis-plus笔记整理相关推荐

  1. mybatis笔记整理

    前言: mybatis可以说是最容易上手的持久层框架了,相比于hibernate 而言,它都是直接用sql语句对数据库进行操作,而不是用hql,尤其是关联关系复杂的时候,mybatis更容易实现.下面 ...

  2. SpringBoot集成Mybatis用法笔记

    今天给大家整理SpringBoot集成Mybatis用法笔记.希望对大家能有所帮助! 搭建一个SpringBoot基础项目. 具体可以参考SpringBoot:搭建第一个Web程序 引入相关依赖 &l ...

  3. 天猫整站SSM-分页-总结(做个人学习笔记整理用)

    天猫整站SSM-分页-herf(做个人学习笔记整理用) 先写Page.java package com.how2java.tmall.util;public class Page {private i ...

  4. SpringBoot笔记整理(二)

    SpringBoot笔记整理(一) SpringBoot笔记整理(二) SpringBoot笔记整理(三) SpringBoot笔记整理(四) Spring Boot与日志(日志框架.日志配置) 1. ...

  5. 动力节点—2020最新MyBatis教程笔记

    文章目录 1 介绍 2 快速入门 2.1 操作步骤(P9) 2.1.1 首先创建maven 2.1.2 接着会做一些配置 2.2 在编译的target目录下面缺少xml的解决方式(P11) 2.3 日 ...

  6. 运维开发笔记整理-前后端分离

    运维开发笔记整理-前后端分离 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.为什么要进行前后端分离 1>.pc, app, pad多端适应 2>.SPA开发式的流 ...

  7. 《繁凡的深度学习笔记》前言、目录大纲 一文让你完全弄懂深度学习所有基础(DL笔记整理系列)

    <繁凡的深度学习笔记>前言.目录大纲 (DL笔记整理系列) 一文弄懂深度学习所有基础 ! 3043331995@qq.com https://fanfansann.blog.csdn.ne ...

  8. 一文让你完全弄懂逻辑回归和分类问题实战《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(上)(DL笔记整理系列)

    好吧,只好拆分为上下两篇发布了>_< 终于肝出来了,今天就是除夕夜了,祝大家新快乐!^q^ <繁凡的深度学习笔记>第 3 章 分类问题与信息论基础 (上)(逻辑回归.Softm ...

  9. 一文让你完全弄懂回归问题、激活函数、梯度下降和神经元模型实战《繁凡的深度学习笔记》第 2 章 回归问题与神经元模型(DL笔记整理系列)

    <繁凡的深度学习笔记>第 2 章 回归问题与神经元模型(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net/ http ...

  10. mybatis学习笔记(13)-延迟加载

    2019独角兽企业重金招聘Python工程师标准>>> mybatis学习笔记(13)-延迟加载 标签: mybatis [TOC] resultMap可以实现高级映射(使用asso ...

最新文章

  1. 虚拟机批量安装LINUX,基于vmware workstation的 pxe + kickstart批量安装linux
  2. 日本共享自行车建立的强大地下停车系统
  3. HelloWorld讲解
  4. Node.js + React + MongoDB 实现 TodoList 单页应用
  5. 用css和js写表单验证,使用javascript及正则表达式实现表单验证(CSS,js练习)
  6. linux echo输出转义换行回车引号
  7. mysql——数据库设计中int与varchar中的长度含义
  8. [Python学习]错误篇二:切换当前工作目录时出错——FileNotFoundError: [WinError 3] 系统找不到指定的路径...
  9. 学习了Python大数据之后,将来主要做什么
  10. resources 下字体文件报错 simsun.ttc is not a valid TTF file
  11. 精选150道iOS面试题
  12. 现代信息检索——基本概念
  13. MySQL查看锁及事务隔离级别的命令
  14. 模拟斗地主发牌, 把54张牌发给三个玩家, 地主多三张, 对每个玩家的牌进行排序
  15. 29.递归三元表达式生成式匿名函数
  16. 阿里测试左移和开发赋能分享
  17. 什么是MES生产制造执行系统?实施MES生产管理系统有哪些目标?
  18. docker中部署piggymetrics微服务项目
  19. Buuctf—极客大挑战练习
  20. 详解广播域和冲突域的区别

热门文章

  1. Jquery实现全选和反选
  2. python 编程接口_Python 中的面向接口编程
  3. Android Framewrok 添加系统默认依赖库
  4. java 自动下载文件_java+selenium+new——无人化自动下载文件——基于firefox浏览器...
  5. 江西省中小学生学籍管理-跨省办理平台数字证书(2)
  6. ios 表情符号 键盘_iOS中表情键盘的完整实现方法详解
  7. 腾讯云数据库公有云市场稳居TOP 2!
  8. 中国公有云厂商2018年收入利润综合排名
  9. 如何进行智能工厂物流规划
  10. NTT DOCOMO在东京开始3G手机试运营