这一篇主要讲解我们后台数据库表的设计。
在这里插入图片描述
可以看到我们的数据库表一共有七个,每个表都以TB开头,其实对于一个IM软件,七个表只能勉强实现其功能,还是有很多表需要扩展的。我们来介绍一下七个表分别的作用。

TB_USER:从上面图中也可以看出,这个表示最核心的表了。与其他六个表都有关联。用来存储用户的信息。
TB_GROUP:用来存储群组的信息。
TB_GROUP_MEMBER:用来存储群成员相关的信息。
TB_PUSH_HISTORY:用来存储推送历史信息,因为我们的这个系统是通过个推推送来实现的,所以推送过的历史消息我们也需要存储一下。
TB_MESSAGE:发送的每条消息的具体内容信息。
TB_APPLY:比如申请好友,申请加群这些操作都是存储在这个表中的。
TB_USER_FOLLOW:用户好友信息表。

现在我们详细的介绍一下每个表中各个字段的意义,毕竟数据库设计可以说是整个后台设计最核心的部分了。不光需要知道每个表都做了什么,其内部各个字段的意义,以及和其他表的关联我们都需要了解。

用户表设计分析:

一、先从最核心的TB_USER来分析:
在这里插入图片描述
①id:每条数据唯一id,这个必须可少。
②createAt:用户账号创建的时候,后期可以做个活动,这是您来XXapp的第XXX天,送你一个50块超前点播特权~
③description:相当于个人签名
④lastReceivedAt:最新一次收到信息的时间(这个属性,有待观察)
⑤name:名字(这个不太好,用户昵称和用户账号是两码事,后期我们将这个属性剥离一下)
⑥password:账号密码
⑦phone:绑定的手机号,后续可以再加个邮箱
⑧portrait:头像地址
⑨pushId:推送的id,毕竟每一条消息都要对应到具体的一个人上,如果定位推送的人,就是通过这个ID.采用设备id实现。
⑩sex:性别,这里没有采用boolean值,,嗯,跟谷歌账号注册的时候一样,可能还有那种,emmm,你懂得。
⑪token:用户状态保持必备之Token,没啥说的。
⑫updateAt:用户更新个人信息的时间。
暂且定义这么多属性,其实还是有很多扩展的地方的。
二、用户表之持久化类的编写设计

@Entity
@Table(name = "TB_USER")
public class User {
    //这是一个主键
    @Id
    @PrimaryKeyJoinColumn
    //主键生成存储的类型为UUID
    @GeneratedValue(generator = "uuid")
    //把uuid的生成器定义为uuid2,uuid2是常规的UUID  toString
    @GenericGenerator(name = "uuid",strategy = "uuid2")
    //不允许更改,不允许为null
    @Column(updatable = false,nullable = false)
    private String id;



    //用户名必须唯一
    @Column(nullable = false,length = 128,unique = true)
    private String name;
    //手机号也必须唯一
    @Column(nullable = false,length = 62,unique = true)
    private String phone;

    @Column(nullable = false)
    private String password;
    //用户头像允许为空,因为第一次新建的时候没有头像
    @Column
    private String portrait;
    @Column
    private String description;
    //性别
    @Column(nullable = false)
    private int sex=0;
    //账户名、电话、token都可以唯一确定一个账号
    @Column(unique = true)
    private String token;
    //用于推送的设备ID
    @Column
    private String pushId;


    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt=LocalDateTime.now();


    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt=LocalDateTime.now();


    //最后一次收到消息的时间
    @Column
    private LocalDateTime lastReceivedAt=LocalDateTime.now();



    //我关注的人列表方法,所有originid是我的id
    //对应的数据表字段为TB_USER_FOLLOW.originId
    @JoinColumn(name = "originId")
    //定义为懒加载,默认加载User信息的时候,并不查询这个集合
    @LazyCollection(LazyCollectionOption.EXTRA)
//    /1对多,一个人可以关注多个人
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)//与上边这个是配合使用的
    private Set<UserFollow> following=new HashSet<>();



    //关注我的人的列表
    @JoinColumn(name = "targetId")
    //定义为懒加载,默认加载User信息的时候,并不查询这个集合
    @LazyCollection(LazyCollectionOption.EXTRA)
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)//与上边这个是配合使用的
    private Set<UserFollow> followers=new HashSet<>();

    //我所创建的群
    //对应的字段为Group.ownerId
    @JoinColumn(name = "ownerId")
    //懒加载集合方式为尽可能的不加载具体的数据
    //当访问groups.size()仅仅查询数量,不加载具体的Group信息
    //只有当遍历groups的时候才加载
    @LazyCollection(LazyCollectionOption.EXTRA)
    //FetchType.LAZY:懒加载,加载 用户信息时不加载这个集合,跟群里面正好相反
    //必须为懒加载!!!因为群里面个人信息是急加载,个人
    // 如果这里也是急加载,个人信息里就又有群信息需要急加载,就会陷入无限循环,导致内存崩溃!
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    private Set<Group> groups=new HashSet<>();
//....还有相关的setter和getter ,这里省略了
}

因为个人做的是移动端,碰到这些注解的时候,实际上并不清楚。不清楚那就得学,所以我这里需要对这些注解的来源和使用进行一些分析。
这些注解来自:javax.persistenceorg.hibernate.annotations.*;这个包中。
我们主要看一下这个javax.persistence是来自哪个框架中的:

这个包的作用是用于持久化的,具体的说就是在实体类中进行元数据标签的作用,是ORM框架中用到的。
ORM框架可以通过这个元数据标签,使得实体类与数据库中的表建立映射关系
例如javax.persistence.Column标识实体类中的这个属性对应于数据库中的一个字段等等。
这个好像不是对于hibernate使用的,而是open jpa使用,open jpa也是一种orm框架和hibernate类似。
所以这个看似这个包是由hibernate引入的,属于hibernate,实际并不如此。只不过是hibernate有进入JPA的一些jar包,在Springboot中其实也引入此包。

知道了其来源,那么查找资料就很方便了。
JPA常见注解解析
上面这篇博客对内部的注解介绍的相当详细,可以作为一个很好的参考。
同时也用到了hibernate中的注解:
Hibernate常见注解
这两篇文章看下来,User表中及以后的表中用到的注解,各代表什么意思也就一览无余了。

当使用ManytoOne,OneToMany时,势必要指定关联的外键。

@JoinColumn
1.一对一和多对一的@JoinColumn注解的都是在“主控方”,都是本表指向外表的外键名称。
2.一对多的@JoinColumn注解在“被控方”,即一的一方,指的是外表中指向本表的外键名称。
3.多对多中,joinColumns写的都是本表在中间表的外键名称,
  inverseJoinColumns写的是另一个表在中间表的外键名称。
用户关注表分析设计

在这里插入图片描述
字段解释:

①id:表唯一id
②alias:关注人对被关注人设置的备注名
③createAt:关注某人的时间点
④originId:关注人的id,这个跟User表里的id一致
⑤targetId:被关注人的id,也跟User表里一致
⑥updateAt:关注关系的更新时间。

其实这个表不全,具体还是以实体类为主。

为什么要单独设计这个表而不是直接在User表中直接添加属性呢?
问题就在于用户相互关注之间的复杂性:
A可以关注B,C,D,而B的话,又可以反过来关注A,C,D,同理C,D之间也可以相互关注以及关注AB等。这里的关系是多对多的关系。如果只在User表之间进行操作,实际上逻辑很难实现。如果引入一个中间人的角色,也就是这个用户关注表,那么实现就会简单很多。
这是引入之前的关系图
在这里插入图片描述
引入中间表之后的操作:
在这里插入图片描述
引入之后,就永远是一对多的关系。A只关注于他自身关注了谁,而不用在意谁关注了他。他与这个关注表永远是一对多的关系了。就是将用户之间多对多的关系通过引入这个表,变成了一对多的关系。

@Entity
@Table(name = "TB_USER_FOLLOW")
public class UserFollow {
    @Id
    @PrimaryKeyJoinColumn
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid",strategy = "uuid2")
    @Column
    private String id;

    //定义一个发起人,你关注某人,这里就是你
    //多对1->你可以关注很多人,每一次关注都是一条记录
    //你可以创建很多个关注的信息,所以是多对1
    //这里的多对一指的是:User对应多一个UserFollow
    //optional不可选,必须存储,一条关注记录一定要有一个"你"
    //不要存用户全部信息,只需要存个ID即可
    @ManyToOne(optional = false)//多个UserFollow对应一个User
    //定义关联的表字段名为originId,对应一个User.id
    @JoinColumn(name = "originId")
    private User origin;
    //可以通过ID查找关注人,同理被关注人
    @Column(nullable = false,updatable = false,insertable = false)
    private String originId;
    //定义关注的目标,你关注的人
    //也是多对1,你可以被很多人关注,每次一关注都是一条记录
    //所有就是 多个UserFollow对应一个User的情况
    //
    @ManyToOne(optional = false)
    //定义关联的表字段名为targetId,对应的是User.id
    @JoinColumn(name = "targetId")
    private User target;
    //可以通过ID查找关注人,同理被关注人
    @Column(nullable = false,updatable = false,insertable = false)
    private String targetId;
    //对关注的人起个备注名,可以为空

    @Column
    private String alias;
    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt=LocalDateTime.now();

    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt=LocalDateTime.now();
    //...getter和setter,为了节省篇幅,这里就不贴了。
    }

每一个字段的定义原因上面都有注释。这里我们简要说一下我个人一开始有点迷的点,就是这个:

    @ManyToOne(optional = false)//多个UserFollow对应一个User
    //定义关联的表字段名为originId,对应一个User.id
    @JoinColumn(name = "originId")
    private User origin;

也就是上面的origin(关注人)和target(被关注人),上面都是ManyToOne,我以为应该是OneToMany。
实际上,是多一个UserFollow表对应一个User,因为一个人会有多个关注,每个关注都是一个UserFollow,这里的关系导向应该是UserFollow这个表指向User,而不是User指向这个表。所以是ManyToOne而不是OneToMany。

用户关注表设计好之后,我们就得来完善一下User表了,毕竟我关注人的列表和关注我的人的列表也是属于User信息的一部分。
更新User表:

    //我关注的人列表方法,所有originid是我的id
    //对应的数据表字段为TB_USER_FOLLOW.originId
    @JoinColumn(name = "originId")
    //定义为懒加载,默认加载User信息的时候,并不查询这个集合
    @LazyCollection(LazyCollectionOption.EXTRA)
//    /1对多,一个人可以关注多个人
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)//与上边这个是配合使用的
    private Set<UserFollow> following=new HashSet<>();


    //关注我的人的列表
    @JoinColumn(name = "targetId")
    //定义为懒加载,默认加载User信息的时候,并不查询这个集合
    @LazyCollection(LazyCollectionOption.EXTRA)
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)//与上边这个是配合使用的
    private Set<UserFollow> followers=new HashSet<>();

就是添加两个属性:我关注的人,关注我的人。
这里可以看到关系是OneToMany,数据流向是USER–>USER_FOLLOW.

消息表分析与设计

在这里插入图片描述
①id:消息唯一id
②attach:附件
③content:内容
④createdAt:创建时间
⑤groupId:群组id,可为空,接收人可能为人
⑥receiverId:接收人id,可为空,接收人可能为群
⑦senderId:发送人的id不能为空
⑧type:消息类型
⑨updatedAt:更新时间,非必须
实体类:

@Entity
@Table(name = "TB_MESSAGE")
public class Message {
    public static final int TYPE_STR = 1;//字符串类型
    public static final int TYPE_PIC = 2;//图片类型
    public static final int TYPE_FILE = 3;//文件类型
    public static final int TYPE_AUDIO = 4;//语音
    //这是一个主键
    @Id
    @PrimaryKeyJoinColumn
    //主键生成存储的类型为UUID
    //这里不自动生成UUID,Id由代码写入,由客户端负责生成
    //主要是为了便面复杂的服务器和客户端的映射关系
    // @GeneratedValue(generator = "uuid")
    //把uuid的生成器定义为uuid2,uuid2是常规的UUID  toString
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    //不允许更改,不允许为null
    @Column(updatable = false, nullable = false)
    private String id;
    //内容不允许为空,类型为text
    @Column(nullable = false, columnDefinition = "TEXT")
    private String content;
    //附件可以为空
    @Column()
    private String attach;
    //消息类型
    @Column(nullable = false)
    private int type;
    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt = LocalDateTime.now();

    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt = LocalDateTime.now();


   //发送者,不为空,多个消息对应一个sender
    @JoinColumn(name = "senderId")
    @ManyToOne(optional = false)//跟nullable为false一样
    private User  sender;
    //接收ID,这样就可以懒加载,只加载用户的id而不是全部信息
    //仅仅是为了对应sender的数据库字段senderId,
    //不允许手动的更新或者插入
    @Column(nullable = false,updatable = false,insertable = false)
    private String senderId;

   //接受者可以为空,因为有群
    //多个消息对应一个接受者
    @ManyToOne
    @JoinColumn(name = "receiverId")
    private User receiver;
    @Column(updatable = false,insertable = false)
    private String receiverId;


    @ManyToOne
    @JoinColumn(name = "groupId")
    private Group group;
    @Column(updatable = false,insertable = false)
    private String groupId;
    //...getter和setter
    }

这里有个点需要注意一下:
消息id由客户端生成,而不是由服务端自动生成,是为了避免负责的映射关系。毕竟A给B发消息,A编辑好消息后,实际上这条消息已经有了个唯一id了,只不过是状态还是未发送状态,我们只需要在服务器端发送成功后,返回这个消息的id,通知状态更新即可。假设让服务端生成,就得让服务端生成后通知一下客户端,发送成功后再通知一下客户端。冗余逻辑。

用户表和消息表的关系

一个用户可以接受多条消息,也可以发送多条消息。
用户和消息表之间就是一对多的关系。关系实现就是上面的Message表里的:

   //发送者,不为空,多个消息对应一个sender
    @JoinColumn(name = "senderId")
    @ManyToOne(optional = false)//跟nullable为false一样
    private User  sender;

    //接收ID,这样就可以懒加载,只加载用户的id而不是全部信息
    //仅仅是为了对应sender的数据库字段senderId,
    //不允许手动的更新或者插入
    @Column(nullable = false,updatable = false,insertable = false)
    private String senderId;

同理接收者:

   //接受者可以为空,因为有群
    //多个消息对应一个接受者
    @ManyToOne
    @JoinColumn(name = "receiverId")
    private User receiver;


    @Column(updatable = false,insertable = false)
    private String receiverId;
群组表分析与设计

在这里插入图片描述
这个字段值一目了然,就不再说了。
实体类设计:

@Entity
@Table(name = "TB_GROUP")
public class Group {


    @Id
    @PrimaryKeyJoinColumn
    //主键生成存储的类型为UUID,自动生成
    @GeneratedValue(generator = "uuid")
    //把uuid的生成器定义为uuid2,uuid2是常规的UUID  toString
    @GenericGenerator(name = "uuid",strategy = "uuid2")
    //不允许更改,不允许为null
    @Column(updatable = false,nullable = false)
    private String id;


    //群名
    @Column(nullable = false)
    private String name;


    //群描述
    @Column(nullable = false)
    private String description;


    //群头像
    @Column(nullable = false)
    private String picture;


    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt=LocalDateTime.now();

    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt=LocalDateTime.now();


    @Column(nullable = false,updatable = false,insertable = false)
    private String ownerId;
    //g.s....
用户-群组-消息的关系设计

1.群和用户(群主)之间是有关联关系的

    //群的创建者
    //optional:可选为false,必须有一个创建者
    //fetch:加载方式FetchType.EAGER,急加载,意味着加载群的信息的时候就必须加载owner的信息
    //cascade:联级级别为ALL,所有的更改(更新、删除等)都将进行关系更新
    @ManyToOne(optional = false,fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinColumn(name = "ownerId")
    private User owner;

一个用户可以创建多个群,所以是多对一的关系。关联的列就是ownerId。也就是用户表和群组表是通过ownId来进行关联的,ManyToOne关系的@JoinColumn是在主控方的,这里主控方就是群,群修改了群主,也就是群的拥有者,那么我们通过急加载的方式,立即更新群主信息。

2.用户和群的关系
Group中有关于用户的关系了,那么用户关于群也应该有的,毕竟一个User可能会有多个Group。所以我们需要来更新一个User里的信息:

    //我所创建的群
    //对应的字段为Group.ownerId
    @JoinColumn(name = "ownerId")
    //懒加载集合方式为尽可能的不加载具体的数据
    //当访问groups.size()仅仅查询数量,不加载具体的Group信息
    //只有当遍历groups的时候才加载
    @LazyCollection(LazyCollectionOption.EXTRA)
    //FetchType.LAZY:懒加载,加载 用户信息时不加载这个集合,跟群里面正好相反
    //必须为懒加载!!!因为群里面个人信息是急加载,个人
    // 如果这里也是急加载,个人信息里就又有群信息需要急加载,就会陷入无限循环,导致内存崩溃!
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    private Set<Group> groups=new HashSet<>();

这里是一对多的关系,JoinColumn注解在被控方,也就是当前为一的一方,意思就是这个User和Group的ownerId进行关联。

这样用户和群的关系就好了。

3.群和消息的关系
在Message中添加:

    @ManyToOne
    @JoinColumn(name = "groupId")
    private Group group;
    @Column(updatable = false,insertable = false)
    private String groupId;
群和成员表分析与设计

一个群可以由多个人组成,一个人也可以加入到多个群中,这是个多对多的关系。所以Group和User之间这种多对多的关系,势必要新增一个表使其变成一对多的关系进行处理。
在这里插入图片描述
①id:成员唯一id
②alias:用户别名
③…④…
⑤notifyLevel:通知级别,跟qq那个一样
⑥permissionType:一个人在一个群中的权限,群主,管理员,普通成员等
⑦userId:和用户表的外键关联
实现类:

@Entity
@Table(name = "TB_GROUP_MEMBER")
public class GroupMember {
    public static final  int PERMISSION_TYPE_NONE = 0;//默认权限,普通成员
    public static  final  int PERMISSION_TYPE_ADMIN = 1;//管理员
    public static  final  int PERMISSION_TYPE_ADMIN_SU = 100;//群主


    public static  final  int NOTIFY_LEVEL_INVALID = -1;//默认不接受消息
    public static  final  int NOTIFY_LEVEL_NONE = 0;//默认通知级别
    public static  final  int NOTIFY_LEVEL_CLOSE = 1;//接收消息不提示
    @Id
    @PrimaryKeyJoinColumn
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid",strategy = "uuid2")
    @Column(updatable = false,nullable = false)
    private String id;

    //别名
    @Column
    private String alias;

    //通知级别
    @Column
    private int notifyLevel=NOTIFY_LEVEL_NONE;

    //成员的权限类型
    @Column(nullable = false)
    private int permissionType=PERMISSION_TYPE_NONE;


    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt=LocalDateTime.now();

    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt=LocalDateTime.now();

    //成员信息对应的用户信息
    @JoinColumn(name = "userId")
    @ManyToOne(optional =  false,fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    private User user;

    @Column(nullable = false,updatable = false,insertable = false)
    private String userId;


    //成员信息对应的群信息
    @JoinColumn(name = "groupId")
    @ManyToOne(optional =  false,fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    private Group group;

    @Column(nullable = false,updatable = false,insertable = false)
    private String groupId;
    //..getter.setter
    }

群成员表和群以及用户有关联信息,所以引入User和Group,关系都是多对一。对于User,一个User可能是多个群的成员,所以多个群成员表对应一个成员。对于群组,一个群组里有多个人员,每个人都是一个群成员表,所以也是多对一的关系。

消息历史表与申请表设计

在这里插入图片描述
①id: 消息id
②arrivalAt:消息到达时间
③entity:消息实体(Message转变)
④entityType:实体类型,普通消息,加入群信息,群名修改这种信息,推送级别有很多种
⑤receiverPushId:接收者的推送id

在这里插入图片描述
①id:申请id
②applicateId:申请人的id
③attach:申请好友的时候可能会有的附加信息,比如美照
④targetId:被申请者的id,可能是人或者群
⑤type:申请的是好友,还是其他申请,比如申请做管理员

消息历史表实现:

 @Entity
@Table(name = "TB_PUSH_HISTORY")
public class PushHistory {
    @Id
    @PrimaryKeyJoinColumn
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid",strategy = "uuid2")
    @Column(updatable = false,nullable = false)
    private String id;

    //推送的具体实体存储的都是JSON字符串
    //BLOB是比TEXT更多的一个大字段类型
    @Lob
    @Column(nullable = false,columnDefinition = "BLOB")
    private String entity;

    //推送的实体类型
    @Column(nullable = false)
    private int entityType;

    //接收者不允许为空
    //一个接收者可以接收很多推送消息
    //FetchType.EAGER:加载一条推送消息的时候加载用户信息
    @ManyToOne(optional = false,fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinColumn(name = "receiverId")
    private User receiver;



    @Column(nullable = false,updatable = false,insertable = false)
    private String receiverId;


    //发送者,可为空,因为有可能是系统消息
    //一个发送者可以发送很多推送消息
    //FetchType.EAGER:加载一条推送消息的时候加载用户信息
    @ManyToOne(optional = false,fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinColumn(name = "senderId")
    private User sender;


    @Column(updatable = false,insertable = false)
    private String senderId;

    //接收者当前状态下的设备推送ID
    //User.pushId可为null
    @Column
    private String receiverPushId;

    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt=LocalDateTime.now();

    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt=LocalDateTime.now();


    //消息送达的时间,可为空
    @Column
    private LocalDateTime arriveAt;
//...gettter和setter

这里注意点就是有个信息的数据类型BLOB,因为这个发送的信息本身就有很多的属性,我们需要将其包装成一个json字符串保存一下。其他的跟之前的都差不多。

申请表实现:

@Entity
@Table(name = "TB_APPLY")
public class Apply {
    public  static  final  int TYPE_ADD_USER=1;//添加好友
    public  static  final  int TYPE_ADD_GROUP=2;//加入群
    @Id
    @PrimaryKeyJoinColumn
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid",strategy = "uuid2")
    @Column(updatable = false,nullable = false)
    private String id;

    //描述部分,对我们的申请信息做描述
    //eg:我想加你为好友
    @Column(nullable = false)
    private String description;


    //附件
    //可以附带图片地址,或者其他
    @Column(columnDefinition = "TEXT")
    private String attach;


    //当前申请的类型
    @Column(nullable = false)
    private int type;


    //目标Id,不进行强关联,不建立主外键关系
    //type-->TYPE_ADD_USER User.Id
    //type-->TYPE_ADD_GROUP Group.Id
    @Column(nullable = false)
    private String targetId;



    //定义为创建时间戳,在创建的时候就已经写入
    @CreationTimestamp
    @Column
    private LocalDateTime createAt=LocalDateTime.now();


    //定义为更新时间戳,在更新的时候就已经写入
    @UpdateTimestamp
    @Column
    private LocalDateTime updateAt=LocalDateTime.now();


    //申请人,可为空,为系统信息
    //一个人可以有很多个申请
    @ManyToOne()
    @JoinColumn(name="applicantId")
    private User applicant;

    @Column(updatable = false,insertable = false)
    private String applicantId;
    //...getter &&setter
    }

至此,第五章节关于数据库的设计就结束了。
还是应该在本子上画画物理模型,然后好好研究一下JPA和Hibernate的注解。
MySQL操作:
接着就是打开我们的Mysql了,新建一个数据库,对应配置文件中:
在这里插入图片描述
新建库名为:DB_I_T_PUSH_TEST。
字符集为utf-8,utf-8-general.ci.
建好后,在idea的右侧连接数据库:
在这里插入图片描述
在这里插入图片描述
点击Apply按钮。连接上之后的样子:
在这里插入图片描述
然后添加映射:
在这里插入图片描述

接下来就是实现我们后台相关的接口了。

更多推荐