后端训练营与技术分享
数据库与SQL
在后端的开发过程中,我们接触最频繁的一定是数据库。如何学好、用好数据库,是完成后端开发最核心的部分之一。
关系型数据库
关系型数据库是指采用了关系模型来组织数据的数据库。简单来说,关系模式就是二维表格模型。
主要代表有:SQL Server,Oracle,Mysql,PostgreSQL。
与之相对的还有非关系型数据库,典型代表为Redis。
本文将以关系型数据库为主展开讲述。
SQL
SQL (Structured Query Language) 是具有数据操纵和数据定义等多种功能的数据库语言,这种语言具有交互性特点,能为用户提供极大的便利,数据库管理系统应充分利用SQL语言提高计算机应用系统的工作质量与效率。SQL语言不仅能独立应用于终端,还可以作为子语言为其他程序设计提供有效助力,该程序应用中,SQL可与其他程序语言一起优化程序功能,进而为用户提供更多更全面的信息。
在后端的开发中,离不开CRUD(Create/Retrieve/Update/Delete),SQL语句的正确使用将极大地提高开发效率。
以下是一些SQL语句的使用示例:
- 查询
select * from user where username = '2021210000'
- 插入
insert into user(username, name, gender) values('2021210000', '张三', '男')
- 修改
update user set gender = '女' where username = '2021210000'
- 删除
delete from user where username = '2021210000'
约束
SQL 约束用于规定表中的数据规则。
如果存在违反约束的数据行为,行为会被约束终止。
约束可以在创建表时规定(通过 CREATE TABLE 语句),或者在表创建之后规定(通过 ALTER TABLE 语句)。
在 SQL 中,我们有如下约束:
- NOT NULL - 指示某列不能存储 NULL 值。
- UNIQUE - 保证某列的每行必须有唯一的值。
- PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。
- FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
- CHECK - 保证列中的值符合指定的条件。
- DEFAULT - 规定没有给列赋值时的默认值。
多表查询
在很多时候,单独查一张表难以满足实际的业务需求,这时候就需要使用多表查询或连表查询。
下图展示了 LEFT JOIN、RIGHT JOIN、INNER JOIN、OUTER JOIN 相关的 7 种用法:
SQL JOIN
SQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段。
最常见的 JOIN 类型:SQL INNER JOIN(简单的 JOIN)。 SQL INNER JOIN 从多个表中返回满足 JOIN 条件的所有行。
语法:
SELECT column1, column2, ...
FROM table1
JOIN table2 ON condition;
不同的 SQL JOIN
- INNER JOIN:如果表中有至少一个匹配,则返回行
- LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行
- RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行
- FULL JOIN:只要其中一个表中存在匹配,则返回行
事务
一般来说,事务是必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
- 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
以MySQL为例,事务处理主要有两种方法:
- 用 BEGIN, ROLLBACK, COMMIT来实现
- BEGIN 开始一个事务
- ROLLBACK 事务回滚
- COMMIT 事务确认
- 直接用 SET 来改变 MySQL 的自动提交模式
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
锁
锁是计算机在执行多线程或线程时用于并发访问同一共享资源时的同步机制,MySQL中的锁是在服务器层或者存储引擎层实现的,保证了数据访问的一致性与有效性。
MySQL锁可以按模式分类为:乐观锁与悲观锁。按粒度分可以分为全局锁、表级锁、页级锁、行级锁。按属性可以分为:共享锁、排它锁。按状态分为:意向共享锁、意向排它锁。按算法分为:间隙锁、临键锁、记录锁。1
Java高级特性
Maven
Maven是一个项目管理工具,它包含了一个对象模型。一组标准集合,一个依赖管理系统。和用来运行定义在生命周期阶段中插件目标和逻辑。
Maven的核心功能是合理叙述项目间的依赖关系,通俗点,就是通过pom.xml文件的配置获取jar包不用手动的去添加jar包。
一个简单的pom.xml依赖项配置示例:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.1.RELEASE</version>
<scope>test</scope>
</dependency>
scope取值 | 有效范围 | 依赖传递 | 例子 |
---|---|---|---|
compile | all | 是 | spring-core |
provided | compile, test | 否 | servlet-api |
runtime | runtime, test | 是 | JDBC驱动 |
test | test | 否 | JUnit |
system | compile, test | 是 |
compile :为默认的依赖有效范围。如果在定义依赖关系的时候,没有明确指定依赖有效范围的话,则默认采用该依赖有效范围。
此种依赖,在编译、运行、测试时均有效。
provided :在编译、测试时有效,但是在运行时无效。
provided意味着打包的时候可以不用包进去,别的设施(Web Container)会提供。
事实上该依赖理论上可以参与编译,测试,运行等周期。相当于compile,但是在打包阶段做了exclude的动作。
例如:servlet-api,运行项目时,容器已经提供,就不需要Maven重复地引入一遍了。
runtime :在运行、测试时有效,但是在编译代码时无效。
说实话在终端的项目(非开源,企业内部系统)中,和compile区别不是很大。比较常见的如JSR×××的实现,对应的API jar是compile的,具体实现是runtime的,compile只需要知道接口就足够了。
例如:JDBC驱动实现,项目代码编译只需要JDK提供的JDBC接口,只有在测试或运行项目时才需要实现上述接口的具体JDBC驱动。
另外runntime的依赖通常和optional搭配使用,optional为true。我可以用A实现,也可以用B实现。
test :只在测试时有效,包括测试代码的编译,执行。例如:JUnit。
PS: test表示只能在src下的test文件夹下面才可以使用,你如果在a项目中引入了这个依赖,在b项目引入了a项目作为依赖,在b项目中这个注解不会生效,因为scope为test时无法传递依赖。
system :在编译、测试时有效,但是在运行时无效。
和provided的区别是,使用system范围的依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。
JDBC
JDBC是Java数据库连接(Java Database Connectivity)技术的简称,提供连接各种常用数据库的能力。
简单使用:
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.通过反射加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获得连接
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/java_web?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8",
"root", "114514");
// 3.编写sql语句
String sql = "select * from user";
// 4.预编译sql语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 5.提交执行并获得结果
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("username"));
}
preparedStatement.close();
connection.close();
}
多线程
Java中的多线程是一种非常重要和常用的编程技术,可以提高程序的效率和性能,但也需要注意线程安全和同步问题,尽量避免出现竞争条件和死锁等问题。
在Java中,多线程可以通过创建Thread对象并调用它的start()方法来实现。也可以通过实现Runnable接口并将其作为参数传递给Thread对象来创建线程。
Java中的多线程有以下几个特点:
- 线程是轻量级的,创建和销毁线程的开销很小。
- 线程可以共享数据,但需要注意线程安全问题。
- 线程之间的通信可以通过wait()、notify()和notifyAll()等方法来实现。
- 线程可以设置优先级,但是并不能保证线程按照优先级顺序执行。
- Java中的多线程可以通过synchronized关键字来实现同步,也可以使用Lock对象等其他方式来实现同步。
Java的多线程可以提高程序的并发性和性能,但也需要注意线程安全和同步问题,否则可能会出现程序运行异常的情况。因此,在编写多线程程序时,需要注意以下几点:
- 避免线程之间的竞争条件,尽量避免多个线程同时访问同一个共享资源。
- 使用线程安全的数据结构和方法,例如ConcurrentHashMap和AtomicInteger等。
- 使用同步机制来保证线程安全,例如synchronized关键字和Lock对象等。
- 了解线程的生命周期和状态,避免出现死锁和饥饿等问题。
- 使用线程池来管理和复用线程,避免创建和销毁线程的开销。
SpringBoot
HTTP相关理论
HTTP(Hypertext Transfer Protocol)是一种基于TCP/IP协议的应用层协议,用于在Web浏览器和Web服务器之间传输数据。下面简单介绍一下HTTP中的一些相关理论:
- 请求和响应:HTTP是一种客户端-服务器协议,客户端向服务器发送请求,服务器返回响应。HTTP请求包括请求行、请求头和请求体等部分;HTTP响应包括状态行、响应头和响应体等部分。
- URL(Uniform Resource Locator):URL是用于标识Web资源的一种格式化字符串,包括协议、主机名、端口号、路径和查询字符串等部分。例如,http://www.example.com/index.html就是一个URL,表示访问www.example.com服务器上的index.html页面。
- 状态码:HTTP响应中包含一个状态码,用于表示服务器对请求的处理结果。常见的状态码包括200(请求成功)、404(请求的资源不存在)、500(服务器内部错误)等。
- Cookie:Cookie是一种在客户端保存用户数据的技术,可以在客户端和服务器之间传递信息。服务器可以通过Set-Cookie响应头发送Cookie给客户端,客户端可以将Cookie保存在本地,并在以后的请求中将Cookie发送给服务器。Cookie通常用于实现用户认证、会话管理和个性化设置等功能。
- 缓存:HTTP缓存是一种机制,用于在客户端和服务器之间缓存Web资源,并且可以在以后的请求中重复使用缓存的资源,以提高性能和减少网络带宽的使用。HTTP缓存通常分为浏览器缓存和代理服务器缓存两种。
- HTTPS:HTTPS(HTTP Secure)是一种基于TLS/SSL协议的安全协议,用于在Web浏览器和Web服务器之间传输加密的数据。HTTPS可以保证数据传输的机密性、完整性和认证性,是一种比较安全的Web传输协议。
SpringBoot
Spring Boot是一个基于Spring框架的开源Java Web开发框架,它可以让开发者更加方便、快速地构建、部署和运行Spring应用程序。Spring Boot提供了一种约定大于配置的方式来构建应用程序,可以快速地搭建Web应用、RESTful服务、批处理应用等。
Spring Boot的主要特点如下:
- 快速入门:Spring Boot提供了很多自动配置,可以让开发者快速地构建一个可运行的Spring应用程序,减少了开发者的配置工作。
- 无XML配置:Spring Boot可以完全基于Java代码进行配置,不需要使用XML配置文件,使得配置更加简洁、易于维护。
- 自动配置:Spring Boot提供了很多自动配置,可以根据应用程序的需要自动配置Spring和第三方库,减少了开发者的配置工作。
- 组件化:Spring Boot支持组件化开发,可以将应用程序拆分成独立的组件,每个组件都可以独立测试、构建和部署。
- 微服务支持:Spring Boot提供了对微服务的支持,可以使用Spring Cloud构建分布式系统,实现服务注册与发现、负载均衡、断路器等功能。
- 监控和管理:Spring Boot提供了很多监控和管理工具,可以帮助开发者更好地监控和管理应用程序,包括健康检查、性能监控、日志管理等。
Spring Boot是一个快速、简单、灵活的Java Web开发框架,可以帮助开发者更加方便、快速地构建、部署和运行Spring应用程序。Spring Boot提供了很多自动配置和组件化开发的功能,可以大大减少开发者的配置工作,同时也提供了对微服务的支持和监控和管理的功能,可以帮助开发者更好地构建和管理应用程序。
MybatisPlus
MybatisPlus是Mybatis的增强工具,它简化了Mybatis的使用,提供了一些常用的功能,例如分页、逻辑删除、自动填充等,可以帮助开发者更加方便、高效地使用Mybatis进行数据库操作。下面给出一个简单的示例,比较使用MybatisPlus和直接写SQL的区别。
假设我们要查询学生表中年龄大于18岁的学生,并按照年龄从小到大进行排序。使用MybatisPlus,我们可以这样写代码:
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public List<Student> getStudentsByAge() {
QueryWrapper<Student> wrapper = new QueryWrapper<>();
wrapper.gt("age", 18).orderByAsc("age");
return studentMapper.selectList(wrapper);
}
}
上面的代码中,我们使用了MybatisPlus提供的QueryWrapper类,可以很方便地构建查询条件。首先创建一个QueryWrapper对象,然后使用gt()方法设置年龄大于18岁的条件,使用orderByAsc()方法设置按照年龄从小到大排序的条件,最后使用selectList()方法执行查询操作。
与之相对比,如果直接使用SQL语句,需要编写如下代码:
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public List<Student> getStudentsByAge() {
String sql = "SELECT * FROM student WHERE age > 18 ORDER BY age ASC";
return studentMapper.selectList(new QueryWrapper<Student>().apply(sql));
}
}
上面的代码中,我们需要手动编写SQL语句,并将其传递给QueryWrapper对象的apply()方法,然后再使用selectList()方法执行查询操作。可以看到,这样的写法并不利于开发者维护,且灵活性较差,使用MybatisPlus可以大大简化代码,提高开发效率。
前后端交互与接口设计
前后端交互与接口设计是Web开发中非常重要的一个主题,尤其是在现今流行前后端分离的时代,如何优雅地实现前后端对接变得尤为重要。
前后端交互逻辑设计
前后端交互逻辑设计是指前端页面和后端接口之间的交互方式和逻辑。在设计前后端交互逻辑时,需要明确数据的传输方式、请求和响应的数据格式、数据校验和异常处理等方面。为了保证前后端交互逻辑的一致性和可维护性,可以使用RESTful API设计原则和Swagger等工具。
接口文档的撰写
接口文档是描述接口功能和使用方式的文档,可以帮助开发者理解接口的使用方式和参数要求。接口文档应该包括接口的URL、请求方式、请求参数、请求示例、响应参数、响应示例等内容。为了提高接口文档的可读性和可维护性,可以使用前后端分离的技术,将接口文档与接口实现分离,使用Swagger等工具来自动生成接口文档。
复杂接口的实现与优化
复杂接口是指需要处理大量数据或者需要进行多次数据库访问的接口。在实现复杂接口时,需要考虑数据库的性能、接口的响应时间和并发访问等方面。为了提高接口的性能和响应时间,可以采用缓存、分页、异步处理等技术进行优化。同时,为了保证接口的可靠性和安全性,需要进行参数校验、异常处理和安全认证等方面的处理。
学习心得
在后端训练营的学习过程中,我们从后端开发接触最多的数据库与SQL切入主题,逐步深入了解了SQL中的约束、多表查询、事务、锁等知识点;之后,我们以Java后端开发为例,进入了Java高级特性、SpringBoot、MybatisPlus等框架的学习,对Java后端的学习路线有了更深一层的了解。现今前后端开发盛行,因此我们又学习了前后端交互及接口设计等相关内容,逐渐熟悉了前后端的开发流程。当然,对于整个后端开发体系来说,仅仅掌握这些知识仍然是不够的。吞吐量优秀的非关系型数据库Redis、容器化管理框架k8s、高并发高可用开发等知识点,同样非常值得我们学习。后端训练营主要以概述的方式引出了后端开发的概念,真正掌握并运用这些知识,还有很长的路要走。