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

一 数据层mybatis

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

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

1 引入依赖

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

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
     <version>2.2.0</version>
</dependency>

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);
}

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);
    }
}

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

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

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

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.47</version>
</dependency>

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);

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

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

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

在这里插入图片描述

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 引入依赖

<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>

2 代码编写

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

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

在这里插入图片描述

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

customerMapper.insert(customer);

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

在这里插入图片描述

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

@Data
public class Customer {
    @TableId(value = "id",type = IdType.AUTO)
    String id;
    String name;
    int age;
}

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);

4 简化操作

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

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

直接在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();
}

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

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

(1)引入依赖

<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generator</artifactId>
	<version>3.4.1</version>
</dependency>

<dependency>
	<groupId>org.apache.velocity</groupId>
	<artifactId>velocity-engine-core</artifactId>
	<version>2.0</version>
</dependency>

(2)源码

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

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

public class CodeGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    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();
    }
}

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

6 总结

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

三 多数据源

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

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

1 引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>

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

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

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();
}

用户分群操作需要连接多数据源,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 
); 

以下操作移步到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();
    }
}

(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";
}

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

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

  • user_group_comment :将条件转成中文。

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

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

    在这里插入图片描述

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

(4)Service层

public interface UserGroupService  extends IService<UserGroup> {

}

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

@Service
@DS("mysql")
public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {
}

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

(5)Mapper层

@DS("mysql")
@Mapper
public interface UserGroupMapper extends BaseMapper<UserGroup> {
}

BaseMapper<UserGroup>中实现。

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

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

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

public void genUserGroup(UserGroup userGroup);

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

@Data
public class TagCondition {
     String tagCode;
     String tagName;
     String operatorName;
     String operator;
     // 标签值,对应条件的包含,如包含男,女,未知
     List<String> tagValues;
     List<String> tagCodePath;
}

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)
}

在controller层中进行调用:

userGroupService.genUserGroup(userGroup);

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

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneTenTwo76

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值