# mybatis-plus-usage-demo **Repository Path**: wangzz_felix/huidatech-boot-demo-application ## Basic Information - **Project Name**: mybatis-plus-usage-demo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-10-07 - **Last Updated**: 2021-11-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 广东食品市场报价数据爬取 > 爬取站点源:: https://price.21food.cn/market/guangdong/ > 共存在5个子站点源 > 1. 广东省广州市江南农副产品市场:https://price.21food.cn/market/746.html 【13点爬取】 > 2. 广东汕头农副产品批发中心:https://price.21food.cn/market/777.html 【14点爬取】 > 3. 广东江门市新会区水果食品批发市场有限公司:https://price.21food.cn/market/777.html 【15点爬取】 > 4. 广东江门市水产冻品副食批发市:https://price.21food.cn/market/817.html 【16点爬取】 > 5. 佛山中南农产品交易中心:https://price.21food.cn/market/847.html 【17点爬取】 ### 爬取思路 通过MyBatis-Plus中Service层的saveOrUpdate()对新爬取的记录进行新增或更新相关数据(报价日期、最低价格、最高价格) ```java /** * 根据传入的站点源爬取网站的内容并存储或更新到数据库中 * @param urlOriginalSeed 站点源 * @throws Exception */ public void executeCrawlerProgram(String urlOriginalSeed) throws Exception{ // 获得URL种子 List urlSeeds = CrawlerForPriceUtils.getUrlSeeds(urlOriginalSeed); // 获得URL种子对应文档对象 List urlDocuments = CrawlerForPriceUtils.getUrlDocuments(urlSeeds); // 结果集 List priceList = new ArrayList<>(); urlDocuments.forEach(document -> { CrawlerForPriceUtils.getResourceFromEachSource(document, priceList); }); priceList.forEach(price -> { LambdaUpdateWrapper pluWrapper = new LambdaUpdateWrapper<>(); pluWrapper.eq(Price::getProductName, price.getProductName()) .eq(Price::getMarketName, price.getMarketName()); priceService.saveOrUpdate(price, pluWrapper); }); } ``` ### 模块组成 #### 数据库表存储: price ```sql CREATE TABLE `price` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `product_name` varchar(150) NOT NULL COMMENT '农产品名称', `market_name` varchar(255) NOT NULL COMMENT '报价市场', `quotation_date` varchar(30) NOT NULL COMMENT '报价日期', `lowest_price` decimal(10,2) NOT NULL COMMENT '最低价格', `hightest_price` decimal(10,2) NOT NULL COMMENT '最高价格', `sale_type` tinyint(2) NOT NULL DEFAULT '0' COMMENT '销售标记: 0:批发;1:零售', `del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标记:0:正常;1:删除', `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人id', `create_by_name` varchar(100) NOT NULL DEFAULT '' COMMENT '创建人姓名', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(这条数据第一次爬取时间)', `update_by` varchar(64) NOT NULL DEFAULT '' COMMENT '更新人id', `update_by_name` varchar(100) NOT NULL DEFAULT '' COMMENT '更新人姓名', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间(相对于这张表来说是 数据爬取最新时间)', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=424 DEFAULT CHARSET=utf8; ![Snipaste_2021-10-25_20-40-48.png](https://cdn5.maocdn.cn/img/2021/10/25/Snipaste_2021-10-25_20-40-48.png) # Java爬虫 > 数据问题? 数据库获取,消息队列中获取中,都可以成为数据源 爬取数据: 获取请求返回的页面信息,筛选出来我们想要的数据即可! 所有的学不会都是给懒找借口!!! # MyBatisPlus的使用 ### MyBatisPlus概述 > MP可以节省大量工作时间,所有的CRUD代码都可以自动化完成 #### MyBatisPlus是什么 > 使用第三方组件 > 1. 导入对应的依赖 > 2. 研究依赖如何配置 > 3. 代码如何编 > 4. 提高和扩展 ## 入门 #### 1. 创建数据库 ```sql 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) ); DELETE FROM user; 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'); ``` #### 2. 使用MyBatis-Plus注意事项 1. MP可以节省大量代码但不要同时导入mybatis和mybatis-plus 2. mysql5和mysql8驱动不同而且mysql8还要增加时区的配置 ```properties # mysql5 驱动不同 => com.mysql.jdbc.Driver # mysql8 驱动不同 => com.mysql.cj.jdbc.Driver 还要增加时区配置 serverTimezone=GMT%2B8 spring.datasource.url=jdbc:mysql://localhost:3306/bootlearn?serverTimezone=Asia/Shanghai&allowMultiQueries=true spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.username=root spring.datasource.password=mysqladmin ``` #### 3.开发方式 ```text 传统方式: entity - DAO(Database Access Object - 链接mybatis、配置mapper.xml文件) - service - controller 使用MP之后 * entity * mapper接口 * 使用 ``` #### 4.配置日志 * 控制台打印sql ```text mybatis-plus.configuration.log-impl: org.apache.ibatis.logging.stdout.StdOutImpl ``` ### 5. CRUD扩展 ##### 数据库插入的id是全局唯一的id ```text JDBC Connection [HikariProxyConnection@622043416 wrapping com.mysql.jdbc.JDBC4Connection@2bfb583b] will not be managed by Spring ==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) ==> Parameters: 1449544266861846530(Long), Wangzz-demo(String), 22(Integer), wz_bepro@163.com(String) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@78a0ff63] insertRows: 1 ``` #### 主键生成策略 自增id、雪花算法 ```text /** * 对应数据库中的主键类型: * 1. AUTO(0) * - 实体类字段上添加 [@TableId(type = IdType.AUTO] * - 数据库字段一定要自增!(★★★) * 2. NONE(1) * - 需要手动插入Id Parameters: null, Felix - UUID(String), 23(Integer), Wang.zhuangzhuang@huidatech.cn(String) * 3. INPUT(2) * 4. ID_WORKER(3) * 5. UUID(4) * 6. ID_WORKER_STR(5) * */ ``` ```java public enum IdType { AUTO(0), NONE(1), INPUT(2), ASSIGN_ID(3), ASSIGN_UUID(4), /** @deprecated */ @Deprecated ID_WORKER(3), /** @deprecated */ @Deprecated ID_WORKER_STR(3), /** @deprecated */ @Deprecated UUID(4); private final int key; private IdType(int key) { this.key = key; } public int getKey() { return this.key; } } ``` #### 自动填充 创建时间、修改时间! 这些操作都是自动化完成 所有的数据库表: - gmt_create - gmt_modified 方式一: 数据库级别 1. 在表中新增字段 方式二: 代码级别 @TableField(fill = FieldFill.INSERT) // 插入新的数据时填充 private Date createTime @TableField(fill = FieldFill.UPDATE) // 更新数据时填充 private Date updateTime 设置填充策略 ```java import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.springframework.stereotype.Component; @Component public class MyMetaObjectHandler implements MetaObjectHandler{ // 插入时的填充策略 @Override public void insertFill(MetaObject metaObject){ // 插入时的填充策略 Log.info("start insert fill ......"); // setFieldByName(String fieldName, Object fieldVal, MethObject metaObject this.setFieldByName("createTime", new Date(), metaObject); this.setFieldByName("updateTime", new Date(), metaObject); } // 更新时的填充策略 @Override public void updateFill(MetaObject metaObject){ Log.info("start update fill ......"); this.setFieldValByName("updateTime", new Date(), metaObject); } } ``` * 乐观锁 实现方式: 1. 取出记录时,获取当前version 2. 更新时,带上这个version 3. 执行更新时, set version = newVersion where version = oldVersion 4. 如果version不对则更新失败 ```sql # 乐观锁: 1. 查询并获取版本号 version = 1 UPDATE user SET name = "text", version = version + 1 WHERE id = 2 AND version = 1 ``` 测试以下MP的乐观锁插件 ```text 1. 给数据库增加version字段 2. 实体类增加对应的字段 @Version // 乐观锁version注解 private Integer version; 3. 注册组件 @Configuration // 配置类 @MapperScan(value = "com.huidatech.app.dao") // 扫描dao中mapper文件 @EnableTransactionManagement public class MyBatisPlusConfig { // 注册乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor(){ return new OptimisticLockerInterceptor(); } } 4.:white_check_mark: 添加测试代码 ``` # MP 分页处理 1. 配置分页拦截器组件 ```java // MP分页插件 @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } ``` 2. 直接使用Page对象即可 # 逻辑删除 > 物理删除: 从数据库中直接删除 > 逻辑删除: 数据库中没有被移除,而是通过一个变量来让他失效! deleted: 1 undeleted(default): 0 管理员可以查看被删除的记录!防止数据的丢失,类似于回收站 1. 设计一个逻辑删除字段 默认值为0(未删除) , 1 表示已经删除 ```java @TableLogic // 逻辑删除 private Integer deleted; ``` 2. 引入逻辑删除组件 > 高本版3.x不用引入逻辑删除组件 ```java // 逻辑删除组件 @Bean public ISqlInjector sqlInjector(){ return new LogicSqlInjector(); } ``` 3. 配置 ```properties ## 逻辑删除配置 mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0 ``` 4. 测试 # 条件构造器 写一些复杂的sql可以使用条件构造器替代 # 代码生成器 > dao、pojo、service、controller层 1. 导包 ```xml com.baomidou mybatis-plus-generator Latest Version ``` # POI-EasyExcel 1. 将用户信息导出为Excel表格(导出数据) 2. 将Excel表中的信息录入到网站数据库中