数据库设计规约
注意:数据库设计规约并不是数据库设计的严格规范,根据不同团队的不同要求设计
本项目参考《阿里巴巴Java开发手册》:五、MySQL数据库
1、库名与应用名称尽量一致
2、表名、字段名必须使用小写字母或数字,禁止出现数字开头,
3、表名不使用复数名词
4、表的命名最好是加上“业务名称_表的作用”。如,edu_teacher
5、表必备三字段:id, gmt_create, gmt_modified
6、单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
7、表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否)。
说明:任何字段如果为非负数,必须是 unsigned。
注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀。数据库表示是与否的值,使用 tinyint 类型,坚持 is_xxx 的 命名方式是为了明确其取值含义与取值范围。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
8、小数类型为 decimal,禁止使用 float 和 double。 说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
9、如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
10、varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
11、唯一索引名为 uk_字段名(unique key);普通索引名则为 idx_字段名(index)。
说明:uk_ 即 unique key;idx_ 即 index 的简称
12、不得使用外键与级联,一切外键概念必须在应用层解决。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
image.pngmybatisPlus学习
本文参照狂神的视频编写https://www.bilibili.com/video/BV17E411N7KN
在此特别感谢狂神陪伴我度过无聊的2020的上半年。
本文使用springBoot来整合mybatisPlus进行使用
1.快速开始(第一个hello world)
1.1 创建一个user表
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
1.2 导入依赖
<dependencies>
<!-- springboot 的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus -->
<!-- mybatis-plus 是自己开发,并非官方的! -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
</dependencies>
1.3 在application.properties中配置对应的数据库连接
spring.datasource.username=StudyDatabase
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/StudyDatabase?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
注意:
1、这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more
2、这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息
mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
1.4 编写pojo类(user)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private int age;
private String email;
}
1.5 编写接口(UserMapper)
@Repository
public interface UserMapper extends BaseMapper<User> {
}
1.6 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
@SpringBootApplication
@MapperScan("com.summer.mapper")
public class MybatisPlusApplication {
......
}
1.7测试
@SpringBootTest
class MybatisplusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
我看完当时学完的表情
v2-ba22e4ebc42b37bbb2140dce9a76105c_720w.jpg仔细想想其实就是以下几步
- 导入依赖mybatis-plus的依赖
- 编写pojo类
- 编写接口
- 测试
一定要记得在启动类上面加上@MapperScan注解 用来扫描mapper文件
比起mybatis原版的操作这里少了什么?
少了编写xml文件,不需要编写SQL语句,
为什么我们可以少写这一步呢?
我们在接口上面继承了一个抽象类 extends BaseMapper<T>
T 是一个泛型,往这上面丢入我们想要操作的pojo类,就可以自动生成对应的方法。
2. 配置日志
日志为了让我们去查看执行的sql语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3.CRUD扩展
3.1插入操作
@SpringBootTest
class MybatisplusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
User user = new User();
user.setAge(20);
user.setEmail("1260570909@qq.com");
user.setName("summer");
userMapper.insert(user);
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
1586605871205.png
我们发现我们没有设置id,但是mybatis-plus却给我们生成这么一串的id?
3.2主键生成策略
1.如何配置主键生成策略?
我们在id上面添加主键 @TableId(type = IdType.ID_WORKER),就可以配置。
public class User {
@TableId(type = IdType.ID_WORKER)
private Long id;
}
-
主键生成策略的种类:
我们可以根据需求去选择,mybatis-plus中默认的是 ID_WORKER。
使用的是一个雪花算法的方法计算出的id。
一般我们也会选择自增的策略AUTO,不过我们要记得在数据库的主键上添加自增的属性
AUTO(0),
NONE(1),
INPUT(2),
ID_WORKER(3),
UUID(4),
ID_WORKER_STR(5);
注意点:
1.id 要写为long 类型的数据 不然会报错
private Long id;
mybatis-plus中会自动帮我们生产id,但是id类型是long ,不是int型的
- 在配置id自增的时候一定要保证数据库里面id是自增的!!!!
@TableId(type = IdType.AUTO)
private Long id;
- UUID对应的是字符串不是我们平时的int类型
3.3更新操作
@Test
void updatamybatis(){
User user = new User();
user.setId(20L);
user.setName("summer");
int update = userMapper.updateById(user);
System.out.println(update);
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
mybatis-plus 会帮我们自动生成SQL语句
3.4自动填充
在我们的数据库字段中都会有create_time, update_time这两个字段,我们希望他可以自己改变,而不是我们手动的改变
1.数据库级别
我们在数据中将这两个字段设置为如下就数据库就会自动更新了
Snipaste_2020-04-11_22-28-11.png2.代码级别
以往我们都会用new Data来更新,这样又笨重有麻烦,而且会忘记。
现在我们可以自动填充了
1.在代码上写上注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2.编写配置类
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
3.测试运行
@Test
void contextLoads() {
User user = new User();
user.setAge(20);
user.setEmail("1260570909@qq.com");
user.setName("summer");
userMapper.insert(user);
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
Snipaste_2020-04-12_09-30-14.png
自动填充成功!!
3.5乐观锁
乐观锁:认为什么都不会出现问题,什么都不会加锁,只有出现问题之后才会去更新对应的值。
悲观锁:认为什么都是会出问题的,什么操做都会加锁。
mysql 中我们如何实现乐观锁?
1.我们在表中的加入字段version
2.在spring中注册乐观锁
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
3.模拟插队的情况:
@Test
void versionTest() {
User user = userMapper.selectById(20L);
user.setAge(20);
user.setEmail("212121@qq.com");
user.setName("pppnut");
User user2 = userMapper.selectById(20L);
user.setAge(20);
user.setEmail("212121@qq.com");
user.setName("蜜桃");
userMapper.updateById(user2);
userMapper.updateById(user);
}
UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
上述是执行的sql语句,先查数据库中的版本好是否和现在的一致,一致就说明之前没有人对我的数据进行修改,不一致就说明我们的数据被修改,现在的操作取消
3.6查询操作
@Test
void selectTest() {
//根据id查询
User user = userMapper.selectById(20L);
//根据id批量查询
List<User> users = userMapper.selectBatchIds(Arrays.asList(26L,27L,28L));
//根据map的条件查询
HashMap<String, Object> map = new HashMap<>();
map.put("name","夏天");
map.put("age",0);
List<User> users1 = userMapper.selectByMap(map);
System.out.println(user);
users.forEach(System.out::println);
users1.forEach(System.out::println);
}
3.7分页查询
如何使用?
1.在mybatis-plus中添加分页插件
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2.测试
@Test
void pageTest() {
Page<User> userPage = new Page<>(1,4);
userMapper.selectPage(userPage, null);
userPage.getRecords().forEach(System.out::println);
System.out.println(userPage.getTotal());
System.out.println(userPage.getSize());
}
3.8删除操作
@Test
void deleteTest(){
//通过id删除
int i = userMapper.deleteById(1);
//批量删除
int i1 = userMapper.deleteBatchIds(Arrays.asList(11,12,13));
HashMap<String, Object> map = new HashMap<>();
map.put("name","夏天");
map.put("age",20);
//条件删除
int i2 = userMapper.deleteByMap(map);
System.out.println(i);
System.out.println(i1);
System.out.println(i2);
}
3.9逻辑删除
管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!
1.在数据库中添加字段deleted
2.添加类
@TableLogic //逻辑删除
private Integer deleted;
3.配置
// 逻辑删除组件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4.条件构造器wrapper
写一些复杂的sql就可以使用它来替代!
Wrapper<User> Wrapper = new Wrapper<>();
基本的条件:
-
大于 > Greater than #gt
-
小于 < Less than #lt
-
等于 = Equals #qe
类比ge,le,ne
-
between
-
notBetween
-
like
......
其他去官网查找
网友评论