赞
踩
MyBatis-plus 是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性
学习新技术的方式
1、导入对应的依赖
2、进行相关的配置
3、进行代码编写
步骤
1、创建数据库Mybatis_plus
2、创建user表
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) ); INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com'); -- 实际开发中还有 version(乐观锁) deleted(软删除) create_time modify_time 等等
3、创建springboot的项目
4、导入对应依赖
<dependencies> <!-- 连接Mysql的驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- lombok 简化代码--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- mybatis-plus 这是自己开发的--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
说明:使用mybatis-plus 可以简化代码、注意不要mybatis-plus和mybatis 重复导入 以免依赖出错误
5、连接数据库 这个和mybatis相似
# mysql 5 驱动不同 com.mysql.jdbc.Driver
spring.datasource.name=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&useSSL=true&characterEncoding=utf8
#mysql 8 驱动不同 com.mysql.cj.jdbc.Driver 需要连接时区的配置 serverTimeZone=GMT%2B8
6、传统方式:pojo-mapper(连接mybatis 、配置mapper.xml文件)-service-controller
6、 使用了MyBatis-plus以后
pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Long age;
private String email;
}
mapper
// 继承BaseMapper 就有了基本的CRUD 和查询功能
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
注意启动类上:需要添加一个扫描注解@MapperScan("com.hejiaxing.mapper")
测试使用
@SpringBootTest class MybatisPlusApplicationTests { @Resource private UserMapper userMapper; @Test void contextLoads() { List<User> list = userMapper.selectList(null); list.forEach(System.out::println); } } -- 结果 User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com)
开发的时候要查看SQL执行情况,上线以后可以取消
#配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
输出结果
@Test
void testInsert() {
User user=new User();
user.setName("Hjx");
user.setAge(18L);
user.setEmail("906@qq.com");
int res = userMapper.insert(user); //自动帮我们生成了ID
System.out.println(res); //返回结果 受影响的行数
System.out.println(user); //生成以后的对象
}
结果:成功插入一条数据 ID自动生成 1392720750414139394
ID的生成策略:全局唯一
默认全局唯一ID ID_WORKER
@Data @AllArgsConstructor @NoArgsConstructor public class User { //ID的 策略一般有 UUID、自增ID、雪花算法、zookeeper、ridis 等等 @TableId(type = IdType.ID_WORKER) private Long id; //雪花算法默认 private String name; private Long age; private String email; }) 分布式系统唯一ID:https://zhuanlan.zhihu.com/p/63802895 **雪花算法** Twitter开源,生成一个64bit(0和1)字符串(1bit不用,41bit表示存储时间戳,10bit表示工作机器id(5位数据标示位,5位机器标识位),12bit序列号) ![snowflake](C:\Users\hjx\Pictures\snowflake.jpg) > 主键自增 配置主键自增需要执行的操作: 1、在实体类上设置ID的type;`@TableId(type = IdType.AUTO)` 2、设置数据库的ID为自增 3、再次执行插入数据测试 备注:上一个是雪花算法产生的ID、自增加1 ;结果正确 > 其余源码解释 ~~~ java public enum IdType { AUTO(0), //自增策略 NONE(1), //不填写ID INPUT(2),// 自己输入 ID_WORKER(3),//默认 雪花算法生成id UUID(4),//UUID生成 ID_WORKER_STR(5);// 雪花算法的String类型 }
@Test
void testUpdate() {
User user=new User();
user.setName("Update测试");
user.setId(1L);
int update = userMapper.updateById(user); //传入一个User 对象 自动拼接SQL 根据Id进行更新
System.out.println(update);
}
一般正式环境中 还会有create_time 、modify_time 等;这些字段希望可以自动填充数据
方式1:数据库设置(一般不允许操作数据库)
Alter `user` add `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
Alter `user` add `modify_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间'
//新增User的属性
private Date createTime;
private Date modifyTime;
执行Insert插入操作-发现时间以及有了
方式2:mybatis-plus的自动填充
1、还原开始的数据库设置
2、配置bean的字段
//在对应字段上加入 @TableField(fill=) fill 填充 表示执行什么操作时候需要做的事情 默认是不执行任何操作
@TableField(fill = FieldFill.INSERT ) //表示执行插入的时候执行操作
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//表示执行插入-更新 的时候执行操作
private Date modifyTime;
3、创建自己的Handler 执行操作
@Slf4j @Component //交给Sprng的IOC容器管理 public class MyMetaDataHandler implements MetaObjectHandler { // 插入执行的事情 @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("modifyTime",new Date(),metaObject); } //更新填充的时候的操作 @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.setFieldValByName("modifyTime",new Date(),metaObject); } }
4、执行插入或者更新操作验证正确!
OptimisticLockerInnerInterceptor
乐观锁:顾名思义十分乐观、他总是以为不会出问题、无论干什么先不会上锁!如果出现了问题、再次更新值进行测试
悲观锁:顾名思义十分悲观、他总是以为会出问题、无论干什么都先上锁!在执行操作!
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
步骤1、新增mysql字段
Alter `user` add `version` int(10) DEFAULT '1' COMMENT '版本控制'
步骤2、User对象新增version字段 并添加标签
@Version
private Integer version;
步骤3、spring boot配置config 乐观锁插件
@EnableTransactionManagement //管理事务
@MapperScan("com.hejiaxing.mapper") //扫描mapper
@Configuration //配置类
public class MybatisPlusInterceptor {
@Bean
public OptimisticLockerInterceptor mybatisPlusInterceptor() {
OptimisticLockerInterceptor interceptor = new OptimisticLockerInterceptor();
return interceptor;
}
}
步骤4、进行乐观锁的成功和失败测试
成功的正确执行-及在单线程的情况下无其他人执行操作
//测试乐观锁正确的方式仅一人执行更新操作
@Test
void testInterceptor() {
//第一步先查出对应的数据
User user = userMapper.selectById(1L);
//第二步 修改信息
user.setName("乐观锁1");
//第三步 执行更新操作
userMapper.updateById(user);
}
结果:先从数据库找到该条数据、然后执行更新操作的时候条件中有version=1 、然后version版本被修改为2 、修改成功!
失败的情况-有多人或者多线程执行操作;当版本不一样时无法执行
//测试乐观锁失败的方式 多人执行更新 @Test void testInterceptorFail() { //第一个人 找到数据 想要进行修改 但是被第二人抢先了 User user = userMapper.selectById(1L); user.setName("乐观锁1"); //第二个人 找到数据 先修改了 User use1 = userMapper.selectById(1L); use1.setName("乐观锁2"); //第三步 第二个人先 执行更新操作 int update = userMapper.updateById(use1); System.out.println(use1); int update1 = userMapper.updateById(user); System.out.println(user); //在有乐观锁的情况下:第二人先执行、此时版本version已经改变 第一人去执行时候Version版本不对应 即修改失败 数据库是第二个的修改内容 }
// 日志信息 1.找到数据 ==> Preparing: SELECT id,name,age,email,create_time,modify_time,version FROM user WHERE id=? ==> Parameters: 1(Long) <== Columns: id, name, age, email, create_time, modify_time, version <== Row: 1, 乐观锁1, 18, test1@baomidou.com, null, 2021-05-14 07:20:18, 2 <== Total: 1 // 2.第二个人先执行更新 version改成3 ==> Preparing: UPDATE user SET name=?, age=?, email=?, modify_time=?, version=? WHERE id=? AND version=? ==> Parameters: 乐观锁2(String), 18(Long), test1@baomidou.com(String), 2021-05-14 07:30:04.789(Timestamp), 3(Integer), 1(Long), 2(Integer) <== Updates: 1 // 此时的version改为3 User(id=1, name=乐观锁2, age=18, email=test1@baomidou.com, createTime=null, modifyTime=Fri May 14 07:20:18 CST 2021, version=3) //此时第一人再去修改:但是版本参数依旧是2 所有更新失败 ==> Preparing: UPDATE user SET name=?, age=?, email=?, modify_time=?, version=? WHERE id=? AND version=? ==> Parameters: 乐观锁1(String), 18(Long), test1@baomidou.com(String), 2021-05-14 07:30:06.586(Timestamp), 3(Integer), 1(Long), 2(Integer) // 受影响的行为0 更新失败 <== Updates: 0 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5e5beb8a] User(id=1, name=乐观锁1, age=18, email=test1@baomidou.com, createTime=null, modifyTime=Fri May 14 07:20:18 CST 2021, version=2)
@Test
void testSelect () {
// 根据ids进行查询
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L));
//实际SQL: SELECT id,name,age,email,create_time,modify_time,version FROM user WHERE id IN ( ? , ? )
users.forEach(System.out::println);
HashMap<String,Object> map=new HashMap();
map.put("name","hjx");
List<User> users = userMapper.selectByMap(map);
//实际执行SQL:: SELECT id,name,age,email,create_time,modify_time,version FROM user WHERE name = ?
// 自动拼接高级查询
users.forEach(System.out::println);
}
分页方式:
1、使用limit进行分页
2、使用pageHelper进行分页
3、MP内置分页插件
使用步骤
1、配置分页插件
@EnableTransactionManagement //管理事务 @MapperScan("com.hejiaxing.mapper") //扫描mapper @Configuration //配置类 public class MybatisPlusInterceptor { @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } // 这是分页插件的config配置bean @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限制数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对部分 left join return paginationInterceptor; } }
2、直接进行使用
@Test
void testSelectPage() {
// 分页查询 设置当前页为第一页 分页数为3
IPage<User> page=new Page(1,3);
IPage<User> userIPage = userMapper.selectPage(page, null);
//1.userIPage.getRecords() 获取所有记录
userIPage.getRecords().forEach(System.out::println);
// 2.userIPage.getTotal();获取所有总数
System.out.println(userIPage.getTotal());
//3. userIPage.getCurrent() 当前页 1
System.out.println(userIPage.getCurrent());
//4. userIPage.getPages() 获取一共有几页 4
System.out.println(userIPage.getPages());
}
@Test
void testDelete() {
//根据id删除记录
//实际SQL:DELETE FROM user WHERE id=?
userMapper.deleteById(1392720750414139399L);
// 根据一些id进行删除
//实际SQL: DELETE FROM user WHERE id IN ( ? , ? )
userMapper.deleteBatchIds(Arrays.asList(1392720750414139398L,1392720750414139397L));
//根据map进行删除
//SQL:DELETE FROM user WHERE name = ?
HashMap<String,Object> map=new HashMap();
map.put("name","Hjx");
userMapper.deleteByMap(map);
}
但是实际开发中、很多地方会用到软删除;删除时改变指定字段的值、查询时候增加相应条件进行查询 数据库记录依旧存在;
使用步骤
1、数据库新增 逻辑删除字段 deleted
Alter `user` add `deleted` int(1) DEFAULT '0' COMMENT '逻辑删除'
2、bean中新增对应字段
@TableLogic //注解TableLogic 表示是逻辑删除字段
private Integer deleted;
3、进行配置
@Bean
public ISqlInjector iSqlInjector(){
return new LogicSqlInjector();
}
# 配置逻辑删除 logic-delete-value 删除的值为1 没删除的为0
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4、删除和查询测试 是否加上了逻辑删除
@Test
void testLogicDelete() {
//根据id删除记录
userMapper.deleteById(3L);
}
进行查询操作、查看是否已经加上了逻辑删除字段
@Test
void testLogicSelect () {
userMapper.selectById(1L);
}
查询时候需要构造各种方法 可以设置对应的Wrapper进行查询 一般使用QueryWrapper
判断全部相同或者个别是nulll
@Test
void contextLoads() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
HashMap<String,Object> map=new HashMap<String,Object>();
map.put("name","乐观锁2");
map.put("id",1L);
map.put("create_time",null);
wrapper.allEq(map);
List<User> list = userMapper.selectList(wrapper);
list.forEach(System.out::println);
}
@Test
void test() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("id",1L);
List<User> list = userMapper.selectList(wrapper);
// SELECT id,name,age,email,create_time,modify_time,version,deleted FROM user WHERE deleted=0 AND id = ?
list.forEach(System.out::println);
}
BETWEEN 值1 AND 值2
@Test
void test1() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询年龄在10-20的人 id大于等于2的
wrapper.ge("id",2L)
.between("age",10,20);
List<User> list = userMapper.selectList(wrapper);
//SELECT id,name,age,email,create_time,modify_time,version,deleted FROM user WHERE deleted=0 AND id >= ? AND age BETWEEN ? AND ?
list.forEach(System.out::println);
}
1、like --->
like ‘%xxx%’
2、notLike --->
not like ‘%xxx%’
3、likeLeft --->
like ‘%xxx’
4、likeRight --->
like ‘xxx%’
5、isNull isNull("name")
—>name is null
6、isNotNull isNotNull("name")
—>name is not null
7、in in(“age”,{1,2,3})--->
age in (1,2,3)
8、notIn notIn(“age”,{1,2,3})--->
age not in (1,2,3)
@Test
void test2() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询 名字中带有乐观 创建时间是空的 并且id在 234的
wrapper.like("name","乐观")
.isNull("create_time")
.in("id",2L,3L,4L);
List<User> list = userMapper.selectList(wrapper);
//SELECT id,name,age,email,create_time,modify_time,version,deleted FROM user WHERE deleted=0 AND id >= ? AND age BETWEEN ? AND ?
list.forEach(System.out::println);
}
9、inSql
inSql("age", "1,2,3,4,5,6")
—>age in (1,2,3,4,5,6)
inSql("id", "select id from table where id < 3")
—>id in (select id from table where id < 3)
10、 notInSql
notInSql("age", "1,2,3,4,5,6")
—>age not in (1,2,3,4,5,6)
notInSql("id", "select id from table where id < 3")
—>id not in (select id from table where id < 3)
11、 groupBy
groupBy("id", "name")
—>group by id,name
12、orderByAsc 升序排列
13、orderByDesc 降序排列
其他还有很多 可以查看官网详细内容
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
/** * Author: hjx * Date: 2021/5/17 16:05 * Describe: 这是MP的代码自动生成 */ public class CodeGenerator { public static void main(String[] args) { // 1、创建代码生成器对象 AutoGenerator generator = new AutoGenerator(); //当前项目的文件夹地址 String projectPath = System.getProperty("user.dir"); // 2、全局配置 GlobalConfig globalConfig=new GlobalConfig(); globalConfig.setAuthor("HJX");// 设置作者 globalConfig.setOpen(false);// 设置自动打开文件夹 globalConfig.setOutputDir(projectPath+ "/src/main/java"); //设置文件输出的地址 globalConfig.setFileOverride(true); //设置文件重新生成覆盖之前的 globalConfig.setDateType(DateType.ONLY_DATE); //定义生成的实体类中日期类型 globalConfig.setServiceName("%sService"); //去掉Service接口的首字母I globalConfig.setIdType(IdType.ID_WORKER_STR); //主键策略 globalConfig.setSwagger2(false);//开启Swagger2模式 generator.setGlobalConfig(globalConfig); //将配置放入到生成器中 // 3、数据库配置 DataSourceConfig dsc=new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&useSSL=true&characterEncoding=utf8"); dsc.setDbType(DbType.MYSQL); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); generator.setDataSource(dsc); //4、包配置 PackageConfig pc=new PackageConfig(); pc.setController("controller"); pc.setEntity("entity"); pc.setMapper("mapper"); pc.setService("service"); pc.setXml("mapper"); pc.setParent("com.hejiaxing"); // pc.setModuleName("testGen"); generator.setPackageInfo(pc); //5、策略配置 StrategyConfig strategyConfig=new StrategyConfig(); strategyConfig.setInclude("t_dept"); //设置需要生成的表名称 strategyConfig.setNaming(NamingStrategy.underline_to_camel);//设置表的类型 t_user的 进行驼峰命名 strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); //字段 驼峰命名 strategyConfig.setEntityLombokModel(true); strategyConfig.setRestControllerStyle(true); //开启rest的风格 //设置逻辑删除字段 strategyConfig.setLogicDeleteFieldName("deleted"); // 数据自动填充配置 TableFill createTime = new TableFill("create_time", FieldFill.INSERT);//插入的时候自动更新 TableFill modifyTime = new TableFill("modify_time", FieldFill.INSERT_UPDATE);//插入 更新的时候自动更新 ArrayList<TableFill> tableFills=new ArrayList(); tableFills.add(createTime); tableFills.add(modifyTime); strategyConfig.setTableFillList(tableFills); // 乐观锁 strategyConfig.setVersionFieldName("version"); generator.setStrategy(strategyConfig); generator.execute(); //执行代码 trategyConfig.setEntityLombokModel(true); strategyConfig.setRestControllerStyle(true); //开启rest的风格 //设置逻辑删除字段 strategyConfig.setLogicDeleteFieldName("deleted"); // 数据自动填充配置 TableFill createTime = new TableFill("create_time", FieldFill.INSERT);//插入的时候自动更新 TableFill modifyTime = new TableFill("modify_time", FieldFill.INSERT_UPDATE);//插入 更新的时候自动更新 ArrayList<TableFill> tableFills=new ArrayList(); tableFills.add(createTime); tableFills.add(modifyTime); strategyConfig.setTableFillList(tableFills); // 乐观锁 strategyConfig.setVersionFieldName("version"); generator.setStrategy(strategyConfig); generator.execute(); //执行代码 } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。