1、Mysql集成
本文主要描述了以下几个问题:
Mysql 集成:包括使用 Docker 部署 Mysql 的关键运行命令,如拉取镜像、创建保存数据及日志的目录、运行并配置相关参数。还举例说明了创建相关库表,如创建数据库和 sys_user
表。
SpringBoot + SpringData JPA 配置:在 application.yml
中进行数据源配置及 JPA 的配置,如配置驱动、URL、用户名、密码等。以及实体类注解、ID生成器等相关代码说明
配置问题说明:包括 Mysql 链接的时区配置、ddl-auto
的配置习惯、懒加载问题。
1.1、Docker部署Mysql
docker部署mysql比较简单,网上一大堆,本文只描述一些关键的运行命令,建议使用版本8.0
## 拉取mysql镜像
docker pull mysql
## 在宿主机创建几个目录用以保存mysql数据及日志,方便查看
# data、log、config三个文件
## docker运行
# 命名、端口映射、后台运行、挂载目录、root密码
docker run --name mysql -p 3306:3306 -d \
-v /home/docker_data/mysql/data:/var/lib/mysql \
-v /home/docker_data/mysql/log:/var/log/mysql \
-v /home/docker_data/mysql/config:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root
1.2、创建相关库表
本文只举例说明,主键统一使用SnowFlake(单机版)生成的32位ID,由SpringDataJPA主键策略配置并由业务服务生成。
-- 创建数据库
CREATE DATABASE IF NOT EXISTS account_center ;
-- 创建表
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`TENANT_ID` bigint NOT NULL COMMENT '租户号',
`ORG_ID` bigint NOT NULL COMMENT '机构ID',
`CREATED_BY` bigint NULL DEFAULT NULL COMMENT '创建人',
`CREATED_TIME` datetime NULL DEFAULT NULL COMMENT '创建时间',
`UPDATED_BY` bigint NULL DEFAULT NULL COMMENT '更新人',
`UPDATED_TIME` datetime NULL DEFAULT NULL COMMENT '更新时间',
`DELETED` bit(1) NULL DEFAULT b'0' COMMENT '删除标识',
`USER_ID` bigint NOT NULL COMMENT '用户id',
`USER_NAME` varchar(90) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
`STATUS` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '状态',
`PASSWORD` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码,加密后',
`NICK_NAME` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '昵称',
`HEADER` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '头像',
`PHONE_NO` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '手机号',
`ADDRESS` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '地址',
`EMAIL` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邮箱地址',
`EXPIRED_TIME` datetime NULL DEFAULT NULL COMMENT '失效时间',
`TYPE` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '类型',
PRIMARY KEY (`USER_ID`) USING BTREE,
INDEX `idx_tenant_id`(`TENANT_ID` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic;
2、SpringBoot+SpringData JPA配置
springdata jpa比较不符合咱们国服开发者的使用习惯,不管是从库表结构维护、表关系维护(国服大多数系统的物理层模型,已经不太建议做外键关联了)、懒加载策略等等,不过此处是为了折腾,也算是增长下见识。
2.1、SpringBoot配置
springboot的数据源配置及jpa的配置均在application.yml中进行配置,具体如下
spring: application: name: AcStarter datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/account_center?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: root jpa: show-sql: true hibernate: ddl-auto: none database: mysql open-in-view: true properties: hibernate: enable_lazy_load_no_trans: true
2.2、实体类注解及ID生成器
因为本文使用的项目不涉及表结构自动生成,所以一些注解的实际作用并没有用到,大家可百度具体的参数说明
2.2.1、基类及ID生成器
将一些通用字段放到一个父类中,其他实体集成该父类可大大减少代码量,并提高代码的可读性。
@MappedSuperclass:是标识该类为父类,不使用该注解,jpa获取不到父类中的字段映射关系
@Id:主键标识
@GenericGenerator及GeneratedValue:可指定具体的主键生成策略,本文使用的是自定义的主键生成策略(SnowFlake算法,见下方代码)
@CreatedDate及@LastModifiedDate:数据创建时间及最后修改时间赋值标识
@Column:字段映射配置(该处的nullable等其他配置在关闭auto-dll后不生效)
/**
* 实体基类
*
* @Author: changjiang
* @date: 2024/7/6 11:01 in beijing
*/
@MappedSuperclass
@Data
public abstract class BaseEntity {
@Id
@Comment("id")
@Column(name = "ID", nullable = false)
@GenericGenerator(name = "snowFlakeGenerator", strategy ="com.cj.ac.module.SnowFlakeGenerator")
@GeneratedValue(generator = "snowFlakeGenerator")
private Long id;
@Comment("租户号")
@Column(name = "TENANT_ID", nullable = false)
private Long tenantId;
@Comment("创建人")
@Column(name = "CREATED_BY")
private Long createdBy;
@Comment("创建时间")
@Column(name = "CREATED_TIME")
@CreatedDate
private Instant createdTime;
@Comment("更新人")
@Column(name = "UPDATED_BY")
private Long updatedBy;
@Comment("更新时间")
@Column(name = "UPDATED_TIME")
@LastModifiedDate
private Instant updatedTime;
@Comment("删除标识")
@ColumnDefault("b'0'")
@Column(name = "DELETED")
private Boolean deleted = false;
}
/**
* 雪花算法Id生成
*
* @Author: changjiang
* SnowFakeGenerator
* @date: 2024/7/6 11:05 in beijing
*/
public class SnowFlakeGenerator implements IdentifierGenerator, Configurable {
@Override
public Serializable generate(SharedSessionContractImplementor session, Object o) throws HibernateException {
SnowflakeGenerator generator = new SnowflakeGenerator();
return generator.next();
}
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
}
}
2.2.2、业务类配置
业务类配置主要包含表映射、字段映射、查询及逻辑删除等配置,具体如下:
@Entity以及@Table:实体与表映射
@SQLRestriction:查询时增加的条件
@SQLDelete:物理删除转逻辑删除配置(是不如mybatis-plus注解好使)
@EntityListeners:开启监听,开启后@CreatedDate及@LastModifiedDate生效
@Getter
@Setter
@Comment("系统用户")
@Entity
@Table(name = "sys_user")
@SQLRestriction("deleted = 0")
@SQLDelete(sql = "UPDATE `sys_user` set DELETED = 1 where ID = ?")
@EntityListeners(AuditingEntityListener.class)
public class User extends BaseEntity implements BeanConvertor<User, UserDTO> {
@Comment("用户名")
@Column(name = "USER_NAME", nullable = false, length = 90)
private String userName;
@Comment("账号")
@Column(name = "ACCOUNT", nullable = false, length = 90)
private String account;
@Comment("状态")
@Column(name = "STATUS", nullable = false, length = 50)
private String status;
@Comment("密码,加密后")
@Column(name = "PASSWORD")
private String password;
@Comment("昵称")
@Column(name = "NICK_NAME", length = 125)
private String nickName;
@Comment("头像")
@Column(name = "HEADER")
private String header;
@Comment("手机号")
@Column(name = "PHONE_NO", nullable = false)
private String phoneNo;
@Comment("地址")
@Column(name = "ADDRESS")
private String address;
@Comment("邮箱地址")
@Column(name = "EMAIL")
private String email;
@Comment("失效时间")
@Column(name = "EXPIRED_TIME")
private Instant expiredTime;
@Comment("类型")
@Column(name = "TYPE", length = 32)
private String type;
@Override
public User convertT(UserDTO userDTO) {
return null;
}
@Override
public UserDTO convertS() {
return BeanUtil.copyProperties(this, UserDTO.class);
}
}
2.2.3、启动入口配置
启动入口增加@EnableJpaAuditing注解,否则@CreatedDate及@LastModifiedDate不生效
3、配置问题说明
datasource-url
注意mysql的链接,其中时区配置容易忽略,这个在较高版本的mysql驱动中,是需要额外配置的,配置GMT+8或者Asia/Shanghai,具体配置参考配置文件
ddl-auto
我们国服一般的研发习惯是先进行数据库设计,再进行开发,进行编码的时候,其实库表结构已经存在了,不需要springdata jpa替我们创建,所以尽量关闭这个配置
懒加载问题
jpa使用了hibernate的懒加载策略,这个策略可以减少系统运行过程的内存消耗,但是以此带来的session问题严重影响了开发节奏,开发者需要额外关心各实体之间的关系,比如说要查询用户的菜单,不使用主外键关系的情况下(此项目物理层模型不设计主外键关系),查询流程为:用户->角色->权限->菜单,在开启懒加载的策略下,同一个service线程中,查完用户,session就回收了,后续查询角色时就会报错。
此时如果只是web访问模式,可以开启open-in-view: true这个策略,该配置是spring为了解决该问题提出的方案,即第一次查询用户后,session只是关闭,并不回收,第二次查询角色时,session开启,request结束,session回收。
若项目内还有rpc调用,定时任务调用等服务调用该功能,open-in-view: true就不够用了,需要使用enable_lazy_load_no_trans: true来关闭懒加载策略。
本系列文章一般不考虑资源消耗的问题,只是单纯的进行技术梳理,所以直接关闭了懒加载策略,当然也会导致其他的问题出现,比如查询用户到菜单的流程,springdata jpa调用的查询的次数为1(用户)+n(角色)+ n*m(权限)+n*m*t(菜单),具体原因及解决方案,本文不再描述,后续具体到用户角色设计时会详细说明。