• 【用户画像】数据层mybatis、mabatis-plus介绍和使用,多数据源配置、生成分群基本信息(源码实现)


    一 数据层mybatis

    MyBatis 是一款优秀的持久层框架,它支持自定义 SQL。 MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的 XML 或注解来配置和映射。

    省略了了创建数据库的连接,参数的拼接,数据结果的封装。

    1 引入依赖

    依赖作用:将许多需要在mabatis中进行配置的内容,在SpringBoot中就可以进行配置。

    <dependency>
    	<groupId>org.mybatis.spring.bootgroupId>
    	<artifactId>mybatis-spring-boot-starterartifactId>
         <version>2.2.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 创建表

    和customer bean中结构一致。

    在这里插入图片描述

    3 创建Mapper类

    service中一个类表示一个业务,mapper中一个类表示一张表,每一个方法代表一个操作,如插入,查询等。

    在mapper层创建类,com.hzy.spbt.demo.mapper.CustomerMapper,insertCustomer方法实现对表的插入操作。

    • @Param:标识参数。
    • @Insert(“insert into customer(name,age) values (#{customer.name), #{customer.age}”):自动从customer对象中取出name和age属性。
    • #{customer.name), #{customer.age}:不用加单引号,#会自动分别customer对象中每个属性的类型,是数字不用加单引号,是字符串会自动补上一个单引号。
    • @Mapper:标识此类。
    • 只写接口就可以,mabatis会根据注解和在application.properties中的配置,自动创建实现类。
    • 此时这个接口可以直接让service.impl.CustomerServiceImpl实现类使用。
    @Mapper
    public interface CustomerMapper {
        @Insert("insert into customer(name,age) values (#{customer.name), #{customer.age}")
        public void insertCustomer(@Param("customer") Customer customer);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4 在实现类中调用

    com.hzy.spbt.demo.service.impl.CustomerServiceImpl。

    @Service
    public class CustomerServiceImpl implements CustomerService {
    
        @Autowired
        CustomerMapper customerMapper;
    
        @Override
        public void saveCustomer(Customer customer) {
            
            customerMapper.insertCustomer(customer);
            System.out.println("service : saveCustomer:" + customer);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    spring涉及到mabatis的判断可能不准确,上述代码可能会报错,可以按照下图弱化提示:
    在这里插入图片描述

    在application.properties中进行配置。

    spring.datasource.url=jdbc:mysql://hadoop101:3306/user_profile_manage2022?characterEncoding=utf-8&useSSL=false
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=123456
    
    • 1
    • 2
    • 3
    • 4

    会发现JDBC驱动配置项报红,因为程序中并不包含JDBC驱动。

    在pom文件中添加配置,引入驱动。

    <dependency>
    	<groupId>mysqlgroupId>
    	<artifactId>mysql-connector-javaartifactId>
    	<version>5.1.47version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5 运行程序

    运行程序,通过浏览器插件发送请求,如下图

    在这里插入图片描述

    在控制台输出信息:service : saveCustomer:Customer(id=null, name=zhangsan, age=22)

    在数据库中进行查看:

    在这里插入图片描述

    6 增加查找方法

    核心代码如下:

    com.hzy.spbt.demo.service.impl.CustomerServiceImpl中的CustomerMapper方法增加:

    List<Customer> customerList = customerMapper.selectCustomerList();
    System.out.println(customerList);
    
    • 1
    • 2

    com.hzy.spbt.demo.mapper.CustomerMapper中的CustomerMapper方法增加:

    @Select("select * from customer")
    public List<Customer> selectCustomerList();
    
    • 1
    • 2

    执行程序,输出结果如下。

    在这里插入图片描述

    7 总结

    • 注解 : 目录下接口 xxxMapper 标识@Mapper
      • Mapper接口的方法上 @Select @Insert @Update @Delete 实现sql方法
      • 参数名前加@Param 声明变量 可以再SQL 以 #{ }方式引用 ${} (视情况补充单引、特殊符号的处理)、 引用 (完全字符替换)
    • 在service使用mapper 需要用@Autowire 进行装配
    • application.properties 要填写数据库地址,用户名密码 ,驱动

    Mybatis-plus

    Mybatis-plus,简称 MP,是一个Mybatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,完全去SQL化,封装好了大量的CURD操作。 甚至把CRUD操作封装到了Service层,可以直接在controller调用现成的CRUD服务层,极度舒适省心。

    可以省略mapper层的增删改查,也可以省略service层的增删改查。

    局限:只支持简单的CRUD 操作。不支持多表操作(多表 join,union,子查询),不支持GroupBy 和各种函数(rank(),over())。

    1 引入依赖

    
    
        com.baomidou
        mybatis-plus-boot-starter
        3.4.1
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2 代码编写

    在com.hzy.spbt.demo.mapper.CustomerMapper中继承BaseMapper

    com.hzy.spbt.demo.service.impl.CustomerServiceImpl中可以看到能够执行很多方法,其中黑色的为自定义方法。

    在这里插入图片描述

    可以尝试使用几种方法,这里以insert方法为例,增加以下代码:

    customerMapper.insert(customer);
    
    • 1

    执行插入操作会发现,id不是按照原来的方式顺序递增,原因是使用主键的生成策略的问题。

    在这里插入图片描述

    需要对程序进行微调,在customer bean中增加:

    @Data
    public class Customer {
        @TableId(value = "id",type = IdType.AUTO)
        String id;
        String name;
        int age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3 查询操作

    在实现类中编写:

    // 无条件查询
    List<Customer> customerList = customerMapper.selectList(new QueryWrapper<Customer>());
    // 有条件查询
    List<Customer> customerList1 = customerMapper.selectList(new QueryWrapper<Customer>().eq("name","zhangsan"));
    System.out.println(customerList);
    System.out.println(customerList1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4 简化操作

    在service 接口、 serviceImpl 类、Mapper上增加 extends类,如下:

    public interface CustomerService extends IService<Customer>
    public class CustomerServiceImpl extends ServiceImpl<CustomerMapper,Customer> implements CustomerService
    
    • 1
    • 2

    直接在service接口 、mapper中直接使用已经实现的标准插删改查的方法。

    这两个继承(扩展)已经帮助实现了很多标准操作,简化service层的增删改查操作,依赖mybatis-plus生成service层方法,这样标准的增删改查操作,service层都不用写,因此复杂的程序,或者是有一定的特点的程序,才会在service层中编写,如下,直接在Controller层中进行调用。

    @PostMapping("/customer")
    public String saveCustomer(@RequestBody Customer customer){
        customerService.save(customer);
        //customerService.saveCustomer(customer);
        return "save user information: " + customer.toString();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5 进一步简化 - 代码生成器

    省略了标准增删改查模块的业务类、实体类代码

    (1)引入依赖

    
    	com.baomidou
    	mybatis-plus-generator
    	3.4.1
    
    
    
    	org.apache.velocity
    	velocity-engine-core
    	2.0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (2)源码

    实现功能:自动生成对某一张表的增删改查模块。

    用代码生成器的工具类,其中修改数据库的路径用户名密码 ,表名,代码生成的路径。

    public class CodeGenerator {
    
        /**
         * 

    * 读取控制台内容 *

    */
    public static String scanner(String tip) { Scanner scanner = new Scanner(System.in); StringBuilder help = new StringBuilder(); help.append("请输入" + tip + ":"); System.out.println(help.toString()); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotBlank(ipt)) { return ipt; } } throw new MybatisPlusException("请输入正确的" + tip + "!"); } public static void main(String[] args) { // 代码生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setFileOverride(true); gc.setActiveRecord(false);// 不需要ActiveRecord特性的请改为false gc.setEnableCache(false);// XML 二级缓存 gc.setBaseResultMap(true);// XML ResultMap gc.setBaseColumnList(false);// XML columList gc.setOutputDir("E:\\develop\\Eclipse\\demo-spbt\\src\\main\\java"); //输出文件路径 gc.setAuthor("hzy");// 作者 gc.setOpen(false); gc.setSwagger2(false); //实体属性 Swagger2 注解 mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL); dsc.setUrl("jdbc:mysql://hadoop101:3306/user_profile_manage2022"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); // pc.setModuleName(scanner("模块名")); pc.setParent("com.hzy.userprofile"); pc.setService("service"); pc.setServiceImpl("service.impl"); pc.setMapper("mapper"); pc.setEntity("bean"); 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.setRestControllerStyle(true); // 公共父类 // strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!"); // 写于父类中的公共字段 // strategy.setSuperEntityColumns("id"); strategy.setInclude(new String[] { "customer" }); // 需要生成的表 strategy.setControllerMappingHyphenStyle(true); //strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); mpg.execute(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    运行结果:
    在这里插入图片描述

    6 总结

    • 在service 接口、 serviceImpl 类、Mapper上 增加 extends 类。
    • 直接在service接口 、mapper 中直接使用已经实现的标准插删改查的方法。

    三 多数据源

    目前在application.properties中已经定义了一个JDBC数据库的配置,在实际情况中,一个模块可能连接多个数据库,这时如果没有任何工具,只依靠原生的mybatis,是一件很麻烦的事情。

    想要连接多数据源,在java中需要引入支持多数据源的插件

    1 引入依赖

    
        com.baomidou
        dynamic-datasource-spring-boot-starter
        3.3.2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 配置编写格式(application.properties)

    spring.datasource.dynamic.datasource.mysql2022.url=jdbc:mysql://hadoop101:3306/user_profile_manager2022?characterEncoding=utf-8&useSSL=false
    spring.datasource.dynamic.datasource.mysql2022.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.dynamic.datasource.mysql2022.username=root
    spring.datasource.dynamic.datasource.mysql2022.password=123456
    
    spring.datasource.dynamic.datasource.mysql2021.url=jdbc:mysql://hadoop101:3306/user_profile_manager2021?characterEncoding=utf-8&useSSL=false
    spring.datasource.dynamic.datasource.mysql2021.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.dynamic.datasource.mysql2021.username=root
    spring.datasource.dynamic.datasource.mysql2021.password=123456
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这样就实现了多数据源的连接。

    3 多数据源的使用

    使用时在对应的mapper层的接口上添加注解@DS(“配置中名称”),或者在特定的语句上添加注解,如下:

    @Mapper
    @DS("mysql2022")
    public interface CustomerMapper extends BaseMapper<Customer> {
        @Insert("insert into customer(name,age) values ( #{customer.name},#{customer.age} )")
        public void insertCustomer2022(@Param("customer") Customer customer);
    
        @DS("mysql2021")
        @Insert("insert into customer(name,age) values ( #{customer.name},#{customer.age} )")
        public void insertCustomer2021(@Param("customer") Customer customer);
    
        @Select("select * from customer")
        public List<Customer> selectCustomerList();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    用户分群操作需要连接多数据源,MySQL数据库和ClickHouse数据库,这两个数据库都支持jdbc。

    4 总结

    • 用代码生成器的工具类,其中修改数据库的路径用户名密码 ,表名、代码生成的路径。
    • 简化了多数据源操作。
    • application.properties 配置多数据库源。
    • 在类或者方法上通过@DS(“mysql2022”) 声明该方法或者类默认使用的数据源。

    四 生成分群基本信息

    用户分群需要实现的几个功能如下图:

    在这里插入图片描述

    1 创建分群点击操作

    创建分群需要完成的任务如下图:

    在这里插入图片描述

    2 代码实现

    (1)用户分群表结构

    user_profile_manager_2022库中存在user_group表,表结构如下。

    create table `user_group` (
    	`id` bigint ,
    	`user_group_name` varchar ,
    	`condition_json_str` varchar ,
    	`condition_comment` varchar ,
    	`user_group_num` bigint ,
    	`update_type` varchar ,
    	`user_group_comment` varchar ,
    	`update_time` datetime ,
    	`create_time` datetime 
    ); 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    以下操作移步到user_profile_manager_2022项目中进行。

    (2)UserGroup实体bean

    一般与数据库表一对一对应。

    @Data
    public class UserGroup implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @TableId(value = "id", type = IdType.AUTO)  //声明主键  主键默认的生成方式 Auto= 数据库的auto_increment
        private Long id;
    
        private String userGroupName;
    
        private String conditionJsonStr;
    
        // 一张表对应多个筛选条件,一对多在数据库中的存储方式有两种
        // 1 存储两张表,一张主表,一张明细表
        // 2 将多个筛选条件存储到数据库表中的一个字段中
        //   原始数据为List结构,数据库中无法存储,所以先拿List结构接收,对应下面的tagConditions
        //   转化为String后,存储到数据库中,对应上文的conditionJsonStr
        // tagConditions和conditionJsonStr没有对应关系,需要使用@TableField
        // 表明bean中虽然有这个字段,但并不是向数据库中存储的
        // tagConditions作用,为了在程序中方便接收和计算
        @TableField(exist = false)   //声明 数据表中实际不存在该字段
        private List<TagCondition> tagConditions;
    
        private String conditionComment;
    
    
        private Long userGroupNum;
    
        private String updateType;
    
        private String userGroupComment;
    
        private Date updateTime;
    
    
        private Date createTime;
        @TableField(exist = false)
        // 为了方便测试,在页面中可以随意填写业务日期
        // 实际生产环境应该取当前时间的前一日
        private String busiDate;
    
        // 将不易看懂的JSON串转换为易于理解的中文串
        public String conditionJsonToComment(){
            StringBuilder comment=new StringBuilder();
            for (TagCondition tagCondition : tagConditions) {
                comment.append(tagCondition.tagName+ " "+tagCondition.operatorName+" "+ StringUtils.join(tagCondition.getTagValues(),",")+" ;\n");
            }
            return  comment.toString();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    (3)Controller层

    目的:将页面传来的JSON串封装到UserGroupController类genUserGroup方法的参数userGroup中。

    方法全部封装好,所以可以直接在Controller中实现,见(4)(5)。

    通过userGroupService.saveOrUpdate(userGroup);就可以实现,但是在这之前还有一点其他工作需要实现,即在application.properties中使用动态数据源声明,在写入的时候需要声明默认使用哪个数据源,在Mapper和Service层中添加注解。

    @PostMapping("/user-group")
    public String genUserGroup(@RequestBody UserGroup userGroup){
    
        userGroupService.saveOrUpdate(userGroup);
        return "success";
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    完成后,可以在数据库中查看到相应数据,其中

    • condition_json_str :将条件转成字符串。

    • user_group_comment :将条件转成中文。

    • user_group_num :用户分群实际人数。

    • update_time create_time:更新时间,创建时间

      在这里插入图片描述

    下一步操作见(6),补充空白字段。

    (4)Service层

    public interface UserGroupService  extends IService {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4

    虽然Service层中没有任何代码,但是继承了mybatis-plus中的 IService,其中封装了标准的增删改查,由UserGroupService的实现类UserGroupServiceImpl实现。

    @Service
    @DS("mysql")
    public class UserGroupServiceImpl extends ServiceImpl implements UserGroupService {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ServiceImpl中实现,真正插入数据库的方法在UserGroupMapper中。

    (5)Mapper层

    @DS("mysql")
    @Mapper
    public interface UserGroupMapper extends BaseMapper {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    BaseMapper中实现。

    (6)优化之补充空白字段

    service层中不仅包含上述保存信息的一步操作,若在controller层直接调用方法,其他步骤也需要在此层中编写,所以在service层编写一个方法。

    在UserGroupService接口中声明方法,在其实现类UserGroupServiceImpl中实现。

    public void genUserGroup(UserGroup userGroup);
    
    
    • 1
    • 2

    create_time和update_time存储在bean包的TagCondition类中,如下:

    @Data
    public class TagCondition {
         String tagCode;
         String tagName;
         String operatorName;
         String operator;
         // 标签值,对应条件的包含,如包含男,女,未知
         List<String> tagValues;
         List<String> tagCodePath;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    UserGroupServiceImpl中代码

    @Override
    public void genUserGroup(UserGroup userGroup){
    
        // 1 写入mysql人群的基本定义
        // (1)补充condition_json_str空白字段
        List<TagCondition> tagConditions = userGroup.getTagConditions();
        // 转成json串
        String conditionJson = JSON.toJSONString(tagConditions);
        // 再放回数据库中
        userGroup.setConditionJsonStr(conditionJson);
        // (2)补充condition_commen空白字段,将json串转成一个json说明
        userGroup.setConditionComment(userGroup.conditionJsonToComment());
        // (3)补充create_time空白字段
        userGroup.setCreateTime(new Date());
        // (4)user_group_num和update_time先不处理
        // 调用父类方法
        super.saveOrUpdate(userGroup);
        // 2 写入ClickHouse人群包
    
        // 3 人群包(包含所有uid)以应对高QPS访问
        // redis(bitmap/set)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在controller层中进行调用:

    userGroupService.genUserGroup(userGroup);
    
    
    • 1
    • 2

    执行程序,添加分群信息,可以在数据库中查找到相应信息,如下图。

    在这里插入图片描述

  • 相关阅读:
    22种常用设计模式示例代码
    Day697.Spring框架中的设计模式 -深入拆解 Tomcat & Jetty
    MySQL高级特性篇(3)-全文检索的实现与优化
    和鲸科技创始人范向伟受邀出席“凌云出海,来中东吧”2023华为云上海路演活动
    【计算机网络】socket
    ​计算机的原码, 反码和补码​
    Matlab数值计算(多项式插值)
    vue3 配置生产和开发 非vite
    浅谈ClickHouse安全性和权限管理
    flink实战--大状态任务调优指南
  • 原文地址:https://blog.csdn.net/weixin_43923463/article/details/127629032