| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> MyBaitsPlus快速入门,阿里java技术专家面试 -> 正文阅读 |
|
[Java知识库]MyBaitsPlus快速入门,阿里java技术专家面试 |
//继承BaseMapper基本类,接口里面已经写了很多的crud方法 @Mapper public interface UserMapper extends BaseMapper {} @SpringBootTest class SpringBootDaoApplicationTests { //继承了BaseMapper,所有的方法都来自于父类,我们页可以编写自己的扩展方法 @Autowired UserMapper userMapper; @Test void contextLoads() { //参数是一个Wrapper,条件构造器,这里我们先不使用 null //查询全部用户 List users = userMapper.selectList(null); users.forEach(System.out::println); } } ====================================================================================== 1、@Mapper注解: 作用:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类 添加位置:接口类上面 @Mapper public interface UserDAO { //代码 } 如果想要每个接口都要变成实现类,那么需要在每个接口类上加上@Mapper注解,比较麻烦,解决这个问题用@MapperScan 2、@MapperScan 作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类 添加位置:是在Springboot启动类上面添加, @SpringBootApplication @MapperScan(“com.winter.dao”) public class SpringbootMybatisDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisDemoApplication.class, args); } } 添加@MapperScan(“com.winter.dao”)注解以后,com.winter.dao包下面的接口类,在编译之后都会生成相应的实现类 =================================================================== #开启日志功能 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #控制台输出 ========================================================================= 这个注解表示表的主键 @NoArgsConstructor @AllArgsConstructor @Data public class User { String name; Integer age; @TableId(value=“id”,type = IdType.AUTO) Integer id; } 接受两个参数 value = 主键列名 type = 主键类型 可选类型: **使用@TableId注解时,类型为: type = IdType.AUTO 数据库也需要设置自增 否则会出 Cause: java.sql.SQLException: Field ‘id’ doesn’t have a default value** =================================================================== //测试插入 @Test public void testInsert(){ User user = new User(); user.setName(“淮城一只猫”); user.setAge(5); user.setEmail(“2424496907@qq.com”); int result = userMapper.insert(user); //自动生成id System.out.println(result); //受影响的行数 System.out.println(user); //发现id自动回填 } =====================================================================
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一! 我们需要配置注解自增:
public enum IdType { AUTO(0), //id自增 NONE(1), //未设置主键 INPUT(2), //手动输入,一旦手动输入后,就需要自己去写id,否则id为空 ID_WORKER(3), //默认值,全局唯一id UUID(4), //全局唯一id,uuid ID_WORKER_STR(5); //ID_WORKER的字符串表示法 } =================================================================== //测试更新 @Test public void testUpdate(){ User user = new User(); user.setId(6L); user.setName(“我的博客叫:淮城一只猫”); user.setAge(6); user.setEmail(“2424496907@qq.com”); //注意:updateById参数是一个对象 int result = userMapper.updateById(user); //自动生成id System.out.println(result); //受影响的行数 } =================================================================== 创建时间、修改时间!这些操作一般自动化完成的,我们不希望手动更新! 阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有表都要配置上!而且需要自动化! 1.在表中新增字段create_time、update_time2. 再次测试插入方法,需要先把实体类同步!private Date creteTime; private Date updateTime; MySQL-datetime类型的列设置默认值为CURRENT_TIMESTAMP MySQL中datetime字段的默认值CURRENT_TIMESTAMP 1.删除数据库中的默认值、更新操作2.在实体类字段属性上需要注释//字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段 // 注意!这里需要标记为填充字段 @TableField(fill = FieldFill.INSERT) private Date creteTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; 策略枚举如下: public enum FieldFill { /**
*/ DEFAULT, /**
*/ INSERT, /**
*/ UPDATE, /**
*/ INSERT_UPDATE } 3.自定义实现类 MyMetaObjectHandler(实现元对象处理器接口)@Slf4j @Component//填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入 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); } } 4.测试@SpringBootTest class SpringBootDaoApplicationTests { //继承了BaseMapper,所有的方法都来自于父类,我们页可以编写自己的扩展方法 @Autowired UserMapper userMapper; @Test void contextLoads() { User user=new User(); user.setAge(18); user.setName(“hhhh”); int ret = userMapper.insert(user); System.out.println(user); } } ================================================================== 乐观锁:顾名思义乐观,它总是认为不会出现问题,无论干什么都不去上锁!如果出现问题,再次更新值测试 悲观锁:顾名思义悲观,它总是认为会出现问题,无论干什么都会加上锁!再去操作 乐观锁实现方式:
1.数据库中添加version字段,默认值为12.在实体类的字段上加上@Version注解@Version //乐观锁注解 private Integer version; 说明:
3.配置插件@MapperScan("c
om.Mapper") @EnableTransactionManagement //自动管理事务(默认也是开启的) @Configuration //配置类 public class MybaitsPlusConfig { //注册乐观锁插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } } 4.测试@SpringBootTest class SpringBootDaoApplicationTests { //继承了BaseMapper,所有的方法都来自于父类,我们页可以编写自己的扩展方法 @Autowired UserMapper userMapper; //测试乐观锁成功! @Test public void testOptimisticLocker1() { //1.查询用户信息 User user = userMapper.selectById(276); //2.修改用户信息 user.setName(“aaa”); user.setAge(18); //3.执行更新操作 userMapper.updateById(user); } //测试乐观锁失败!多线程下 @Test public void testOptimisticLocker2() { //线程1 User user1 = userMapper.selectById(276); user1.setName(“aaa”); //模拟另外一个线程执行插队操作 User user2 = userMapper.selectById(276); user2.setName(“bbb”); userMapper.updateById(user2); //自旋锁多次操作尝试提交 userMapper.updateById(user1); } } =================================================================== @SpringBootTest class SpringBootDaoApplicationTests { //继承了BaseMapper,所有的方法都来自于父类,我们页可以编写自己的扩展方法 @Autowired UserMapper userMapper; //测试查询 @Test public void testSelectById() { User user = userMapper.selectById(276); System.out.println("==========================="); System.out.println(user); } //测试批量查询 @Test public void testSelectByBatchId() { List users = userMapper.selectBatchIds(Arrays.asList(270, 271, 272)); System.out.println("==========================="); users.forEach(System.out::println); } //条件查询之一 使用map操作 @Test public void testSelectBatchIds() { HashMap<String, Object> map = new HashMap<>(); //自定义查询,同时满足map集合中的所有条件 map.put(“name”,“bbb”); map.put(“age”,“18”); List users = userMapper.selectByMap(map); System.out.println("==========================="); users.forEach(System.out::println); } } =================================================================== 分页在网站中使用非常多!
//Spring boot方式 @Configuration @MapperScan(“com.baomidou.cloud.service..mapper”) public class MybatisPlusConfig { // 旧版 @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限制数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; } // 最新版 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; } }
//测试分页查询 @Test public void testPage() { //参数一:当前页 //参数二:页面大小 //使用了分页插件之后,所有的分页操作页变得简单了 Page page = new Page<>(1,5); //第二个参数是查询条件 userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); } 分页查询常用的方法: @Test public void testPage() { Page page = new Page<>(1,1); List emps = employeeMapper.selectPage(page, null); System.out.println(emps); System.out.println("=获取分页相关的一些信息========"); System.out.println(“总条数:” +page.getTotal()); System.out.println("当前页码: "+ page.getCurrent()); System.out.println(“总页码:” + page.getPages()); System.out.println(“每页显示的条数:” + page.getSize()); System.out.println("是否有上一页: " + page.hasPrevious()); System.out.println("是否有下一页: " + page.hasNext()); //将查询的结果封装到page对象中 page.setRecords(emps); } 如果返回类型是IPage,那么分页返回的IPage对象与传入IPage的对象是同一个好用的工具===》Arrays用法总结=================================================================== //通过id删除 @Test public void testDeleteById() { userMapper.deleteById(174); } //通过id批量删除 @Test public void testDeleteBatchId() { userMapper.deleteBatchIds(Arrays.asList(177, 178)); } //通过map删除 @Test public void testDeleteMap() { HashMap<String, Object> map = new HashMap<>(); map.put(“name”, “大忽悠1号”); userMapper.deleteByMap(map); } 物理删除:从数据库中直接移除 逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效!delete=0 => delete=1 管理员可以查看被删除的记录!防止数据的丢失,类似于回收站! 说明这里mybaitsPlus提供的逻辑删除功能,只对其默认提供给我们的增删改查的slq语句生效,如果是我们自己写的,则不会拥有其功能只对自动注入的sql起效: 插入: 不作限制 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段 删除: 转变为 更新 例如: 删除: update user set deleted=1 where id = 1 and deleted=0 (如果走了自动注入sql的删除操作,那么其实执行的是更新操作,即将deleted值变为1,即逻辑删除掉了) 查找: select id,name,deleted from user where deleted=0 (查找的时候只会查找出没有被逻辑删除掉的用户) 字段类型支持说明: 支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime) 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now() 附录: 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。 测试一下: 1.在数据表中增加deleted字段2. 实体类中同步属性//逻辑删除字段 @TableLogic private Integer deleted; 3. 配置mybatis-plus: global-config: db-config: logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 4.测试@SpringBootTest class SpringBootDaoApplicationTests { //继承了BaseMapper,所有的方法都来自于父类,我们页可以编写自己的扩展方法 @Autowired UserMapper userMapper; //通过id删除 @Test public void testDeleteById() { userMapper.deleteById(174); } } =============================================================================== 我们在开发中,会遇到一些慢sql,我们有必要把它揪出来 。测试!druid… MP也提供性能分析插件,如果超过这个时间就停止运行!官方3.1.0以上版本推荐使用p6spy!
注意:该插件有性能损耗,建议平时开发测试时使用,不建议生产环境使用。 p6spy p6spy 3.9.0 2.接着编辑 application.properties 文件,更换数据库连接驱动
spring: datasource: #是否使用安全连接 #mysal 8驱动不同com.mysql.cj.jdbc.Driver,还需要增加时区的配置 serverTimezone=GMT%2B8 url: jdbc:p6spy:mysql://localhost:3306/tx?userSSL=false&useUnicode=true&characterEncoding=utf-8 username: root password: 123456 driver-class-name: com.p6spy.engine.spy.P6SpyDriver profiles: active: dev #激活开发环境 3.最后创建 spy.properties 配置文件即可:#3.2.1以上使用 modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory #3.2.1以下使用或者不配置 #modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory 自定义日志打印logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger #日志输出到控制台 appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger 使用日志系统记录 sql#appender=com.p6spy.engine.spy.appender.Slf4JLogger 设置 p6spy driver 代理deregisterdrivers=true 取消JDBC URL前缀useprefix=true 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.excludecategories=info,debug,result,commit,resultset 日期格式guidateformat=yyyy-MM-dd HH:mm:ss 实际驱动可多个#driverlist=org.h2.Driver 是否开启慢SQL记录outagedetection=true 慢SQL记录标准 2 秒outagedetectioninterval=2 4.测试@SpringBootTest class SpringBootDaoApplicationTests { //继承了BaseMapper,所有的方法都来自于父类,我们页可以编写自己的扩展方法 @Autowired UserMapper userMapper; //通过id删除 @Test @Profile({“dev”,“test”}) public void testDeleteById() { User user = userMapper.getUserId(174); System.out.println(user); } } 注意,插件会影响性能,建议开发和测试环境下使用@Profile注解详解1. 上面的样例配置,我们是直接将日志输出到控制台,我们可以修改 appender 配置属性,使用日志系统记录 sql: 2. 再次执行查询,可以看到现在改用日志系统记录 sql 了: 也可以修改 appender 配置属性,将日志输出到文件中: #日志输出到文件 appender=com.p6spy.engine.spy.appender.FileLogger 指定 Log 的文件名 默认 spy.loglogfile=spy.log 指定是否每次是增加 Log,设置为 false 则每次都会先进行清空 默认trueappend=true 3.自定义日志格式? 1. 如果觉得默认的日志格式不合适,我们也可以使用 logMessageFormat 和 customLogMessageFormat 这两个配置参数来自定义日志输出格式:
6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat=%(currentTime) | SQL耗时: %(executionTime) ms | 连接信息: %(category)-%(connectionId) | 执行语句: %(sql) ============================================================================= @Test void test1() { //查询name不为空的用户,并且邮箱不为空的,年龄大于等于12 QueryWrapper wapper = new QueryWrapper<>(); wapper.isNotNull(“name”) //这里推荐使用链式编程 .ge(“age”, 64);//大于等于 userMapper.selectList(wapper).forEach(System.out::println); } @Test void test2() { //查询名字为Tom QueryWrapper wapper = new QueryWrapper<>(); wapper.eq(“name”,“bbb”); //只查询一个用户 User user = userMapper.selectOne(wapper); System.out.println(user); } //范围查询 @Test void test3() { //查询年龄在20~30岁之间的用户 QueryWrapper wapper = new QueryWrapper<>(); wapper.between(“age”, 64, 68);//区间 System.out.println(userMapper.selectCount(wapper));//查询结果数 } |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 5:03:29- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |