MyBatisPlus——入门到进阶

✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:知识分享、知识备份
✨特色专栏: 知识分享
🥭本文内容:MyBatisPlus——入门到进阶
📚 ** ps **  : 阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。


目录

01. 入门

1. 添加依赖

2. Mapper继承BaseMapper接口

02. 常见注解

1. 说明

 2. 例子

03. 常见配置

03. 常见配置

04. 核心功能-条件构造器

1. 说明

2. 例子

05. 核心功能-自定义SQL

1. 说明

2. 步骤

a. 基于Wrapper构建where条件

b. 在mapper方法中用Param注解声明wrapper变量名称,必须是ew

c.定义SQL,并使用Wrapper条件

06. 核心功能-Service接口

1. 说明

2. 步骤

a. Service层继承IService接口

b. Service实现类继承(Impl)继承ServiceImpl

c. 调用方法(以save为例,更多例子点击这里)

3. 补充

07. 扩展功能-代码生成 

方式一:使用代码生成器代码进行生成

方式二:使用MybatisX进行代码生成(这个会少一个controller)

方式三:使用应用商店的MybatisPlus插件进行代码生成

08. 扩展功能-静态工具

1.说明

2. 例子

09. 扩展功能-逻辑删除

1. 说明

2. 例子

3. 补充(引用自黑马视频)

10.  扩展功能-枚举处理器

1. 说明

2. 例子

11. 扩展功能-JSON处理器

1. 说明

2. 例子

 12. 插件功能-分页插件

1. 说明

2. 例子


01. 入门

1. 添加依赖

<!--        <dependency>-->
<!--            <groupId>org.mybatis.spring.boot</groupId>-->
<!--            <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!--            <version>2.3.1</version>-->
<!--        </dependency>--><!--    MyBatisPlus依赖    --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.6</version></dependency>

2. Mapper继承BaseMapper接口

// 类似于
public interface UserMapper extend BaeMapper<User>{}

02. 常见注解

1. 说明

mp通过扫描实体类,并基于反射获取实体类信息作为数据库表信息,比较常用的注解如下:

  • @TableName:指定表名
  • @TableId:用来指定表中的主键字段信息
    • idType枚举说明:
      • ATUO:数据库自增
      • INPUT:通过set方法自行输入
      • ASSUGN_ID:分配ID(接口IdentifierGenerator的方法nextId来生成id,默认实现类为DefaultIdentifierGenerator雪花算法)
  • @TableField:用来指定表中的普通字段信息
    • 使用场景:
      • 成员变量名宇数据库字段名不一致
      • 成员变量名以is开头,且是布尔值
      • 成员变量名宇数据库关键字冲突
      • 成员变量不是数据库字段

 2. 例子

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.time.LocalDateTime;@Data
@TableName("tb_user")
public class User {/*** 用户id*/@TableId(type = IdType.AUTO)private Long id;/*** 用户名*/@TableField("`username`")private String username;/*** 密码*/@TableField(exist = false)private String password;/*** 注册手机号*/private String phone;/*** 详细信息*/private String info;/*** 使用状态(1正常 2冻结)*/private Integer status;/*** 账户余额*/private Integer balance;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;
}

03. 常见配置

03. 常见配置

mybatis-plus:configuration:# MyBatis 配置map-underscore-to-camel-case: true# 扫描包global-config:# 全局配置db-config:# 数据库配置id-type: auto# 包的位置type-aliases-package: com.itmeteors.mp.domain.po

04. 核心功能-条件构造器

1. 说明

mp为我们提供了的条件构造器方法,以便与我们进行查询操作:

2. 例子

    // 01. 查询出名字中带o的,存款大于1000元人的id、userName、info、balance@Testvoid testQueryWrapper(){//    1. 构建查询条件QueryWrapper<User> wrapper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").ge("balance", 1000);//    2. 查询List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}// 02. 更新用户名为jack的用户的余额为2000@Testvoid testUpdateByQueryWrapper(){//    1. 要更新的数据User user = new User;user.setBalance(2000);//    2. 更新要的条件QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");//    3. 执行更新userMapper.update(user,wrapper);}// 03. 更新id为1,2,4的用户的余额,扣200@Testvoid testUpdateWrapper(){List<Long> ids = List.of(1L,2L,4L);UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200").in("id",ids);userMapper.update(null,wrapper);}// 04. 使用lambada方式更新id为1,2,4的用户的余额,扣200@Testvoid testLambadaUpdateWrapper(){List<Long> ids = List.of(1L,2L,4L);LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<User>().setSql("balance = balance - 200").in(User::getId,ids);userMapper.update(null,wrapper);}

05. 核心功能-自定义SQL

1. 说明

利用mp来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。

2. 步骤

a. 基于Wrapper构建where条件

    @Testvoid testUpdateWrapper2(){//    1. 更新条件List<Long> ids = List.of(1L, 2L, 4L);int amount = 200;//    2. 定义条件QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);//    3. 调用自定义SQL方法userMapper.updateBalanceByIds(wrapper,amount);}

b. 在mapper方法中用Param注解声明wrapper变量名称,必须是ew

    void updateBalanceByIds(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper,@Param("amount") int amount);

c.定义SQL,并使用Wrapper条件

    <update id="updateBalanceByIds">UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment}</update>

06. 核心功能-Service接口

1. 说明

mp的service接口为我们定义了很多增删改查的方法,减少了在service层的代码书写量

2. 步骤

a. Service层继承IService接口

public interface IUserService extends IService<User> {}

b. Service实现类继承(Impl)继承ServiceImpl

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {}

c. 调用方法(以save为例,更多例子点击这里)

@SpringBootTest
class IUserServiceTest {@Autowiredprivate IUserService userService;@Testvoid testSaveUser(){User user = new User();user.setUsername("tesst");user.setPassword("123");user.setPhone("15966666666");user.setBalance(200);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userService.save(user);}
}

3. 补充

使用 saveBatch()方法 默认不生效:

原因:虽然执行了批量插入方法,但是语句未被合并并优化,然后还是多个请求单独发送给MySQL服务器,网络往返次数和服务器解析SQL语句的开销未减少

解决方法:在yml的数据库连接url最后加上: rewriteBatchedStatements=true,允许驱动程序重写批处理语句为单个字符串,并发送给服务器,从而提高插入、更新和删除操作的速度。

当然,这样可能也会有缺点:

  1. SQL注入风险:因为语句被重写,所以可能会增加SQL注入的风险。务必确保你使用的SQL语句是安全的,避免直接拼接用户输入。
  2. 不支持所有SQL语法:某些复杂的SQL语法可能不支持重写。
  3. 调试困难:由于语句被重写,所以在调试时可能更难以确定问题所在。

07. 扩展功能-代码生成 

方式一:使用代码生成器代码进行生成

步骤:

  1. 导入依赖
    <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.6</version>
    </dependency>
  2. 配置生成器类
    public class CodeGenerator {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true", "root", "****").globalConfig(builder -> {builder.author("Meteors") // 设置作者.enableSwagger() // 开启 swagger 模式.outputDir("C:\\Users\\Meteors\\Desktop\\SpringCloud微服务—资料\\day01-MybatisPlus\\资料\\mp-demo\\src\\main\\java"); // 指定输出目录}).dataSourceConfig(builder ->builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {int typeCode = metaInfo.getJdbcType().TYPE_CODE;if (typeCode == Types.SMALLINT) {// 自定义类型转换return DbColumnType.INTEGER;}return typeRegistry.getColumnType(metaInfo);})).packageConfig(builder ->builder.parent("com.itheima.mp") // 设置父包名.entity("domain.po") // 设置实体类包名.pathInfo(Collections.singletonMap(OutputFile.xml, "C:\\Users\\Meteors\\Desktop\\SpringCloud微服务—资料\\day01-MybatisPlus\\资料\\mp-demo\\src\\main\\resources\\mapper")) // 设置mapperXml生成路径).strategyConfig(builder ->builder.addInclude("address") // 设置需要生成的表名.addTablePrefix("t_", "c_") // 设置过滤表前缀.entityBuilder().enableLombok() // 启用 Lombok.enableTableFieldAnnotation() // 启用字段注解.controllerBuilder().enableRestStyle() // 启用 REST 风格).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
    }
    

  3. 运行代码

方式二:使用MybatisX进行代码生成(这个会少一个controller)

步骤:

  1. 选择MybatisX:
  2. 选择

方式三:使用应用商店的MybatisPlus插件进行代码生成

步骤:

  1. 下载插件
  2. 重启idea,并配置数据库
  3. 进行代码生成

08. 扩展功能-静态工具

1.说明

使用静态工具可以避免循环依赖问题。

2. 例子

需求(如果普通方式进行实现,下面两个需求可能会造成循环依赖)

  • 改造更具id查询用户的接口,查询用户的同时,查询出用户对应的所有地址
    //Controller@ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Long id) {return userService.queryUserAndAddressById(id);}
    //ServiceUserVO queryUserAndAddressById(Long id);
    //Impl@Overridepublic UserVO queryUserAndAddressById(Long id) {//    1. 查询用户User user = getById(id);if (user == null || user.getStatus() == 2) {throw new RuntimeException("用户状态异常!");}//    2. 查询地址List<Address> addressList = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();//  3. 封装VOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);if (CollUtil.isNotEmpty(addressList)){userVO.setAddresses(BeanUtil.copyToList(addressList, AddressVO.class));}return userVO;}
  • 改造根据id批量查询用户的接口,查询用户的同时,查询出用户对应的所有地址
    // Controller@ApiOperation("根据id批量查询用户接口")@GetMappingpublic List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids) {return userService.queryUserAndAddressByIds(ids);}
    // ServiceList<UserVO> queryUserAndAddressByIds(List<Long> ids);
    // Impl@Overridepublic List<UserVO> queryUserAndAddressByIds(List<Long> ids) {// 1. 查询用户List<User> users = listByIds(ids);if (CollUtil.isEmpty(users)) {return Collections.emptyList();}// 2. 查询地址// 2.1 获取用户id集合List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());// 2.2 根据用户id查询地址List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();// 2.3 转换地址VOList<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);// 2.4 用户地址集合分组处理,相同用户的放入一个集合(组)中Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);if (CollUtil.isNotEmpty(addressVOList)) {addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));}// 3. 转换VO返回List<UserVO> list = new ArrayList<>(users.size());for (User user : users) {//    3.1 转换User的PO为VOUserVO vo = BeanUtil.copyProperties(user, UserVO.class);//    3.2 转换地址VOvo.setAddresses(addressMap.get(user.getId()));//    3.3 添加到集合list.add(vo);}return list;}

09. 扩展功能-逻辑删除

1. 说明

逻辑删除解释基于代码逻辑模拟删除效果,但并不会真正删除数据。思路:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为1
  • 查询时值查询标记为0的数据

例如逻辑删除字段为deleted:

  • 删除操作:UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0;
  • 查询操作:SELECT * FROM  user WHERE deleted = 0; 

mp提供了逻辑删除功能,无需改变方法调用的方式,而是在底层帮我们自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可:

2. 例子

在使用mp的逻辑删除功能之后,原有的查询功能会默认在末尾添加查询条件,删除功能会自动变更为UPDATE,下面是具体的例子:

  • 代码
@SpringBootTest
class IAddressServiceTest {@Autowiredprivate IAddressService addressService;@Testvoid testLogicDelete(){//    1. 删除addressService.removeById(59L);//  2. 查询Address address = addressService.getById(59L);System.out.println("address = " + address);}
}
  • 结果

3. 补充(引用自黑马视频)

逻辑删除本身也有自己的问题,比如:

  • 会导致数据库表垃圾数据越来越多,影响查询效率
  • SQL中全部需要对逻辑删除字段做判断,影响查询效率

因此,需要进行逻辑删除时,可以考虑把数据迁移到其它表的方法进行替代

10.  扩展功能-枚举处理器

1. 说明

用户状态字段如果用例如private Integer status的方式进行表示,用这种类型表示不直观且代码且属于硬编码,可维护性差、灵活性低、可扩展性差、可读性差、重用性受限、错误分险增加,而使用mp枚举处理器,可以避免这些缺点。

2. 例子

将原有的状态字段改为枚举类型:

  1. 步骤1:在yaml文件中设置枚举处理器
  2. 步骤2:新建枚举类
    @Getter
    public enum UserStatus {NORMAL(1,"正常"),FROZEN(2,"冻结"),;@EnumValueprivate final int value;@JsonValueprivate final  String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
    }
  3. 步骤3:将字段类型替换为枚举类型
        /*** 使用状态(1正常 2冻结)*/private UserStatus status;
  4. 结果:

11. 扩展功能-JSON处理器

1. 说明

当数据中的表中含有json类型的字段时,如果自己实现Java代码实体类与之对应,比较麻烦,此时可以使用mp的json处理器进行实现,提高开发效率。

2. 例子

将一个数据库中使用json类型的info属性,使用 json处理让Java实体类与之对应,步骤:

  1. 新建那个属性的实体类
    @Data
    @NoArgsConstructor
    @AllArgsConstructor(staticName = "of")
    public class UserInfo {private Integer age;private String intro;private String gender;
    }
  2. 字段上定义处理器并在实体类上开启autoResultMap

ps:

  • 赋值方式
//user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
user.setInfo(UserInfo.of(24,"英语老师","female"));
  • 结果

 12. 插件功能-分页插件

1. 说明

在mp3.4版本之后,mp已经默认集成了mp插件,但如果需要对分页的功能(例如溢出总页数后是否进行处理、单页条数限制、数据库类型设置、方言实现设置)等,仍需要新建分页插件进行实现。

2. 例子

以新建一个的分页插件和通过分页实体实现分页功能为例,步骤如下:

  1. 添加分页插件
    package com.itheima.mp.config;import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;@Configuration
    public class MyBatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//  1. 创建分页插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);paginationInnerInterceptor.setMaxLimit(1000L);//  2. 添加分页插件interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}
    }
    
  2. 新建分页实体
    @Data
    public class PageQuery {private Integer pageNo;private Integer pageSize;private String sortBy;private Boolean isAsc;public <T>  Page<T> toMpPage(OrderItem ... orders){// 1.分页条件Page<T> p = Page.of(pageNo, pageSize);// 2.排序条件// 2.1.先看前端有没有传排序字段if (sortBy != null) {p.addOrder(new OrderItem(sortBy, isAsc));return p;}// 2.2.再看有没有手动指定排序字段if(orders != null){p.addOrder(orders);}return p;}public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc){return this.toMpPage(new OrderItem(defaultSortBy, isAsc));}public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {return toMpPage("create_time", false);}public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {return toMpPage("update_time", false);}
    }
    
  3. 新建分页返回实体
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class PageDTO<V> {private Long total;private Long pages;private List<V> list;/*** 返回空分页结果* @param p MybatisPlus的分页结果* @param <V> 目标VO类型* @param <P> 原始PO类型* @return VO的分页对象*/public static <V, P> PageDTO<V> empty(Page<P> p){return new PageDTO<>(p.getTotal(), p.getPages(), Collections.emptyList());}/*** 将MybatisPlus分页结果转为 VO分页结果* @param p MybatisPlus的分页结果* @param voClass 目标VO类型的字节码* @param <V> 目标VO类型* @param <P> 原始PO类型* @return VO的分页对象*/public static <V, P> PageDTO<V> of(Page<P> p, Class<V> voClass) {// 1.非空校验List<P> records = p.getRecords();if (records == null || records.size() <= 0) {// 无数据,返回空结果return empty(p);}// 2.数据转换List<V> vos = BeanUtil.copyToList(records, voClass);// 3.封装返回return new PageDTO<>(p.getTotal(), p.getPages(), vos);}/*** 将MybatisPlus分页结果转为 VO分页结果,允许用户自定义PO到VO的转换方式* @param p MybatisPlus的分页结果* @param convertor PO到VO的转换函数* @param <V> 目标VO类型* @param <P> 原始PO类型* @return VO的分页对象*/public static <V, P> PageDTO<V> of(Page<P> p, Function<P, V> convertor) {// 1.非空校验List<P> records = p.getRecords();if (records == null || records.size() <= 0) {// 无数据,返回空结果return empty(p);}// 2.数据转换List<V> vos = records.stream().map(convertor).collect(Collectors.toList());// 3.封装返回return new PageDTO<>(p.getTotal(), p.getPages(), vos);}
    }
    
  4. 查询类继承分页实体类
    @EqualsAndHashCode(callSuper = true)
    @Data
    @ApiModel(description = "用户查询条件实体")
    public class UserQuery extends PageQuery{@ApiModelProperty("用户名关键字")private String name;@ApiModelProperty("用户状态:1-正常,2-冻结")private Integer status;@ApiModelProperty("余额最小值")private Integer minBalance;@ApiModelProperty("余额最大值")private Integer maxBalance;
    }
    
  5. 实现查询接口
    // Controller@ApiOperation("根据条件分页查询用户接口")@GetMapping("/page")public PageDTO<UserVO> queryUserPage(UserQuery query){return userService.queryUsersPage(query);}
    // ServicePageDTO<UserVO> queryUsersPage(UserQuery query);
    // Impl@Overridepublic PageDTO<UserVO> queryUsersPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();//  1. 构建查询条件//  1.1 分页条件Page<User> page = query.toMpPageDefaultSortByUpdateTimeDesc();//  2. 分页查询Page<User> p = lambdaQuery().like(name!=null,User::getUsername,name).eq(status!=null,User::getStatus,status).page(page);//  3. 封装VO结果return PageDTO.of(p,user -> {//    1. 拷贝基础属性UserVO vo = BeanUtil.copyProperties(user, UserVO.class);//    2. 处理特殊逻辑vo.setUsername(vo.getUsername() +"**");return vo;});}

     最后,

            希望文章对你有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/23661.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GIS教程】土地利用转移矩阵

随着科技社会的不断进步&#xff0c;人类活动对地理环境的影响与塑造日益明显&#xff0c;土地不断的侵蚀与改变也导致一系列的环境问题日益突出。土地利用/覆盖&#xff08;LUCC&#xff09;作为全球环境变化研究的重点问题为越来越多的国际研究机构所重视&#xff0c;研究它的…

Day25 首页待办事项及备忘录添加功能

​ 本章节,完成首页待办事项及备忘录添加功能 一.修改待办事项和备忘录逻辑处理类,即AddMemoViewModel和AddTodoViewModel 在 AddMemoViewModel逻辑处理类中,为了支持与其关联的View视图文件的数据绑定,需要定义一个与视图文件相匹配的实体类 Model。这个Model将包含 View中…

图像算法---自动对焦AF

一&#xff0c;CDAF反差对焦原理 CDAF&#xff0c;全称Contrast Detection Auto Focus&#xff0c;即反差式对焦或对比度检测自动对焦&#xff0c;是一种广泛应用于入门级数码相机和相机模块化智能手机上的自动对焦技术。以下是关于CDAF反差对焦的详细介绍&#xff1a; 工作原…

每日AI资讯-20240606

智普AI推出全新开源大模型GLM-4-9B 智谱AI日前推出全新开源模型GLM-4-9B&#xff0c;该尺寸模型首次具备多模态能力。据了解&#xff0c;GLM-4-9B&#xff0c;最高支持1M/约两百万字上下文输入&#xff0c;相当于2本《红楼梦》或125篇论文的长度。性能上&#xff0c;GLM-4-9B函…

《手把手教你》系列练习篇之13-python+ selenium自动化测试 -压轴篇(详细教程)

1. 简介 “压轴”原本是戏曲名词&#xff0c;指一场折子戏演出的倒数第二个剧目。在现代社会中有很多应用&#xff0c;比如“压轴戏”&#xff0c;但压轴也是人们知识的一个盲区。“压轴”本意是指倒数第二个节目&#xff0c;而不是人们常说的倒数第一个&#xff0c;倒数第一个…

苗情生态自动监测站

TH-MQ1在现代农业发展中&#xff0c;苗情生态自动监测站的应用已经变得日益重要。这种技术不仅为农业生产提供了实时的数据支持&#xff0c;还通过精准监测和科学决策&#xff0c;提高了农业生产的效率和质量。 首先&#xff0c;苗情生态自动监测站的优势在于其能够实现精准监…

全流程透明双语大语言模型MAP-Neo,4.5T 高质量数据训练

前言 近年来&#xff0c;大语言模型 (LLM) 已经成为人工智能领域最热门的研究方向之一&#xff0c;并在各种任务中展现出前所未有的性能。然而&#xff0c;由于商业利益的驱动&#xff0c;许多最具竞争力的模型&#xff0c;例如 GPT、Gemini 和 Claude&#xff0c;其训练细节和…

读书笔记-《软件定义安全》之一:SDN和NFV:下一代网络的变革

第1章 SDN和NFV&#xff1a;下一代网络的变革 1.什么是SDN和NFV 1.1 SDN/NFV的体系结构 SDN SDN的体系结构可以分为3层&#xff1a; 基础设施层由经过资源抽象的网络设备组成&#xff0c;仅实现网络转发等数据平面的功能&#xff0c;不包含或仅包含有限的控制平面的功能。…

Unity Magica Cloth2 使用教程

视频教程 参考文章 前提&#xff1a; 找到角色的模型 模之屋&#xff0c;我这里准备了转好FBX格式的吟霖模型点击自取【源自 模之屋】 角色舞蹈动画 点击下载【源自 Mixamo】 导入Unity【如何将原神的角色导入Unity】 三渲二 (必须是2022.3LTS和URP项目) Magica Cloth2 头…

Mybatis05-一对多和多对一处理

多对一和一对多 多对一 多对一的理解&#xff1a; 多个学生对应一个老师 如果对于学生这边&#xff0c;就是一个多对一的现象&#xff0c;即从学生这边关联一个老师&#xff01; 结果映射&#xff08;resultMap&#xff09;&#xff1a; association 一个复杂类型的关联&…

在线Logo背景去除:pixian.ai

文章目录 简介特色 简介 pixian.ai是一款智能图片背景去除工具&#xff0c;进入网页后&#xff0c;会非常醒目地提示你准备【Free】还是【Paid】&#xff0c;这点就非常好&#xff0c;不向有一些网站&#xff0c;主打免费使用&#xff0c;但时不时弹出“免费注册”&#xff0c…

Python 连接 MySQL 及 SQL增删改查(主要使用sqlalchemy)

目录 一、环境 二、MySQL的连接和使用 2.1方式一&#xff1a;sql为主 2.1.1创建连接 2.1.2 表结构 2.1.3 新增数据 ​编辑 2.1.4 查看数据 ​编辑 2.1.5 修改数据 2.1.6 删除数据 2.2方式二&#xff1a;orm对象关系映射 2.2.1 mysql连接 2.2.2 创建表 2.2.3 新增…

解锁机器学习的无限可能:深入探究scikit-learn的强大功能

解锁机器学习的无限可能&#xff1a;深入探究scikit-learn的强大功能 第一部分&#xff1a;背景和功能介绍 在数据科学和机器学习领域&#xff0c;scikit-learn&#xff08;简称sklearn&#xff09;是一个广泛使用的Python库。它提供了简单高效的工具用于数据挖掘和数据分析&a…

【Python短期内快速掌握学习人工智能知识能力】:从零到入门的NLP学习秘籍

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

Echarts 在折线图的指定位置绘制一个图标展示

文章目录 需求分析需求 在线段交汇处用一个六边形图标展示 分析 可以使用 markPoint 和 symbol 属性来实现。这是一个更简单和更标准的方法来添加标记点在运行下述代码后,你将在浏览器中看到一个折线图,其中在 [3, 35] (即图表中第四个数据点 Thu 的 y 值为 35 的位置)处…

Java反射Reflect机制详解

文章目录 引言反射的基本概念反射基本原理反射应用场景反射基本使用获取类的Class对象获取构造方法并实例化对象获取和调用方法获取和修改字段反射工具类 反射源码解读获取Class对象的源码调用方法的源码 反射优缺点优点缺点 为什么需要反射总结 引言 Java反射是Java语言中的一…

【干货】视频文件抽帧(opencv和ffmpeg方式对比)

1 废话不多说&#xff0c;直接上代码 opencv方式 import time import subprocess import cv2, os from math import ceildef extract_frames_opencv(video_path, output_folder, frame_rate1):"""使用 OpenCV 从视频中抽取每秒指定帧数的帧,并保存到指定文件夹…

宝贝,带上WebAssembly,换个姿势来优化你的前端应用

在你没崛起之前,脸是用来丢的 大家好,我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder 此篇文章所涉及到的技术有 WebAssemblyRustWeb Worker(comlink)wasm-packPhotonffmpeg.wasm脚手架生成前端项目因为,行文字数所限,有些概念可能会一带而过亦或者提供对…

经济与安全兼顾:茶饮店购买可燃气体报警器的价格考量

可燃气体报警器在如今的社会中扮演着至关重要的角色。它们用于检测环境中的可燃气体浓度&#xff0c;及早发现潜在的火灾隐患&#xff0c;保护人们的生命和财产安全。 在这篇文章中&#xff0c;佰德将介绍可燃气体报警器的安装、检定以及价格&#xff0c;通过实际案例和数据&a…

PCL 生成空间椭圆点云

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 设椭圆在 X O Y XOY XOY平面上,参数方程为: