运行时动态建表

  1. 底层构建一个creatMysqlTablesMapper xml文件与creatMysqlTablesMapper 接口映射
  2. 实现了以下几个方法:
    1. 创建表
    2. 根据表名查询该表是否存在
    3. 根据表名查询库中该表的字段结构
    4. 增加字段
    5. 根据表名删除表
  3. 自动建表过程,首先获取表后缀(当前用户的accessKeyId)
  4. 扫描要自动建表的pojo包,获取class对象集合
  5. 创建两个map,一个是更新表map,一个是创建表map
    1. key:要创建或更新表的表名
    2. value:要创建或更新表的字段信息列表(该对象封装了字段名、字段类型、是否为主键、是否可以为空等属性)
  6. 构建两个map
    1. 遍历原来得到的class对象
    2. 根据当前用户的accessKeyId和class对象拼接要生成表的表名
    3. 调用底层mapper根据表名查看当前表是否已经存在
      1. 表不存在需要新建
        1. 这时要根据当前class对象生成一个字段信息列表
          1. 用反射获取class对象的字段表,将每个字段都封装成一个commonColumn对象,存到新的字段信息表当中
          2. 如何获取某个字段创建时的属性(not null,是否为主键等信息) 创建pojo的时候通过jpa的@column注解标注这些属性,jpa可以读取这些属性信息。
        2. 将这个字段信息列表放到新建表的map当中去
      2. 表已经存在,需要更新
        1. 对应当前的class对象生成一个字段信息表
        2. 调用底层mapper返回原本存在表的字段信息
        3. 对比新生成的字段信息表和原来的字段信息
          1. 如果有不同的字段信息,就将该字段信息对象存到新增字段信息列表中
        4. 如果新增字段信息列表长度不为0,就把当前字段信息列表传到map当中去
    4. 遍历所有的class对象就得到完整新增表map和更新表map了
  7. 分别新增表和更新表
    1. 新增表调用底层的mapper的新增表方法,根据map里面的表名和字段信息名可以拼接出创建表的sql语句
    2. 调用底层mapper的更新表方法,同样能够通过map里面的内容拼接更新表的sql语句(用一个tablesql对象来代表拼接的语句,列也有一个columnsql来代表创建列拼接的语句)

动态表名如何实现

使用mybatis-plus 动态表名插件,用法如下:
mybatis-plus提供了一个接口TableNameHandler,作为表名处理器,其中有个dynamicTableName方法,重写这个方法,返回值就是表名。

  1. 创建一个配置类,比如说就叫myBatisPlusConfig
  2. 里面创建一个mybatisPlusInterceptor拦截器对象,并将其注册到容器当中
  3. mybatisPlusInterceptor 对象可以添加内部拦截器,mybatis-plus提供的动态表名内部拦截器,这个拦截器可以设置表和表名处理器的映射关系(map)
  4. myBatisPlus提供了TableNameHandler接口,实现这个接口并重写其中的dynamicTableName方法,就可以实现自己的动态表名逻辑,返回值就是表名。
  5. 我得动态表名逻辑,在config中创建一个静态的threadlocal,用来存储动态的表名。在动态表名处理器里面,我先创建一个局部变量myTableName把threadlocal值保存起来,我再把threadlocal值设为null,然后返回这个局部变量。这个局部变量就是当前数据库操作的表名。
  6. 为什么要用aop呢,因为所有的表名对应的都是同一个threadlocal,我需要在每次调用处理数据的service之前都重新设置一遍表名。使用aop的前置通知可以解决这个问题。

    spring怎么使用aop

    三个步骤

  7. 使用@aspect和@component注解定义切面

  8. 使用@Pointcut定义切入点 后面用execution定义具体哪个包下的类的哪些方法
  9. 使用@after before 等定义是什么类型的通知,通知下面是具体的aop业务逻辑

aop基本概念

  1. 接入点:被接入扩展功能的连接点
  2. 通知:具体业务逻辑
  3. 连接点:允许使用通知的地方
  4. 切面:切入点和通知的结合
  5. 目标:被通知的对象

    aop底层原理

    jdk动态代理

    1. 被代理类要实现一个接口
    2. 创建一个动态代理处理器实现invocationHandler,重写其中的invoke方法,需要增加的功能在invoke中实现。
    3. invocationHandler里面要创建一个object类的成员变量,作为将被代理的真实对象
    4. invoke方法有三个参数
      1. proxy:代理对象,该参数的作用
        1. 这个是动态生成的代理对象,这个参数表示我们可以在invoke方法里面通过反射获取代理对象的信息,从而进行一些判断什么的
        2. 我们可以在invoke把代理对象返回
      2. method:被代理类的method对象
      3. args:被代理类被代理方法的参数
      4. method.invoke(args)就是执行被代理类的方法
    5. 生成被代理类使用Proxy这个动态代理工具类,一般使用它的newProxyInstence方法结合多态生成一个动态代理类对象,动态代理类是被动态代理类接口的实现类。
      1. newProxyInstence方法三个参数
        1. 类加载器
        2. 类接口集合
        3. invokcationHandler
    6. 动态代理类对象调用相应的方法完成动态代理。

本质是创建一个与被代理类实现相同接口的代理类,底层通过调用被代理类的method对象,使用被代理类的方法。

cglib动态代理

  1. 创建一个cglib代理类实现MethodInterceptor接口
  2. 重写接口中的intercept方法,也是和invoke方法差不多调用了
  3. 写一个生成代理类对象的方法,返回被代理类的子类对象
  4. 子类对象的方法覆盖了被代理类的方法,实现扩展

本质是修改代理类对象字节码,生成一个被代理类的子类重写父类的方法。