文章目录
- 一、RESTful
- 二、SpringMvc对RESTful的支持
- 1. RESTful的URL路径变量
- 2. RESTful的CRUD
- 3. RESTful的资源表述
- 4. 内容协商的方式有三种
- 三、普通 API与RESTful API(示例)
- 四、HTTP状态码和描述
- 五、JPA
- JPA的注解
- 依赖及配置
- 接口约定命名规则:
- 六、Transaction
- 事务的基本要素(ACID)
- @Transactional参数
一、RESTful
RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。
RESTful的特性
- 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特性的URI。要获取这个资源,访问它的URI就可以,因此URI即为每一个资源的独一无二的识别符。
- 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式。
- 状态转换(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转换”(State Transfer)。而这种转换是建立在表现层之上的,所以就是“表现层状态转换”。具体说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。他们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。
二、SpringMvc对RESTful的支持
1. RESTful的URL路径变量
URL-PATTERN:设置为 / ,方便拦截RESTful请求。
@PathVariable:可以解析出来URL中的模板变量({id}/{name})
2. RESTful的CRUD
@RequestMapping:通过设置method属性的CRUD,可以将同一个URL映射到不同的HandlerMethod方法上。
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping注解同@RequestMapping注解的method属性设置。
3. RESTful的资源表述
RESTful服务中一个重要的特性就是一种资源可以有多种表现形式,在SpringMvc中可以使用ContentNegotiatingManager这个内容协商管理器来实现这种方式。
4. 内容协商的方式有三种
- 扩展名,比如.json表示我要JSON格式数据、.xml表示我要xml格式数据
- 请求参数:默认是“format”
- 请求头设置Accept参数,比如设置Accept为application/json表示要JSON格式数据
现在一般RESTful风格响应的数据一般都是JSON格式,所以一般也不使用内容协商管理器,直接使用 @ResponseBody 注解将数据按照JSON格式返回
三、普通 API与RESTful API(示例)
普通API:
//添加用户
http://localhost/createuser
//删除id为1的用户
http://localhost/deleteuser?userid=1
//获取用户列表
http://localhost/getuser
//获取id为1的用户
http://localhost/getuser?userid=1
//更新id为1的用户
http://localhost/updateuser?userid=1
RESTful API:
- 使用GET的方式请求
http://localhost/user
代表查询用户列表 - 使用GET的方式请求
http://localhost/user/1
代表查询id为1的用户 - 使用POST的方式请求
http://localhost/user
代表创建一个用户 - 使用PUT的方式请求
http://localhost/user/1
代表修改id为1的用户 - 使用DELETE的方式请求
http://localhost/user/1
代表删除id为1的用户
可以看到这种风格看起来要更为优雅与简洁,面向资源,一目了然,具有自解释性,充分的发挥了HTTP协议的优点。
四、HTTP状态码和描述
CODE | HTTP Operation | Body Contents | Decription |
200 | GET,PUT | 资源 | 操作成功 |
201 | POST | 资源,元数据 | 对象创建成功 |
202 | POST,PUT,DELETE,PATCH | N/A | 请求已被接受 |
204 | DELETE,PUT,PATCH | N/A | 操作已经执行成功,但是没有返回结果 |
301 | GET | link | 资源已被移除 |
303 | GET | link | 重定向 |
304 | GET | N/A | 资源没有被修改 |
400 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 参数列表错误(缺少,格式不匹配) |
401 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 未授权 |
403 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 访问受限,授权过期 |
404 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 资源,服务未找到 |
405 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 不允许的HTTP方法 |
409 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 资源冲突,或资源被锁定 |
415 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 不支持的数据(媒体)类型 |
429 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 请求过多被限制 |
500 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 系统内部错误 |
501 | GET,POST,PUT,DELETE,PATCH | 错误提示(消息) | 接口未实现 |
五、JPA
- Java Persistence API(Java 持久层 API):用于对象持久化的 API
- 作用:使得应用程序以统一的方式访问持久层
- 前言中提到了 Hibernate,那么JPA 与 Hibernate究竟是什么关系呢:
- JPA 是 Hibernate 的一个抽象,就像 JDBC 和 JDBC 驱动的关系
- JPA 是一种 ORM 规范,是 Hibernate 功能的一个子集 (既然 JPA 是规范,Hibernate 对 JPA 进行了扩展,那么说 JPA 是 Hibernate 的一个子集不为过)
- Hibernate 是 JPA 的一个实现
- JPA 包括三个方面的技术:
- ORM 映射元数据,支持 XML 和 JDK 注解两种元数据的形式
- JPA 的 API
- 查询语言:JPQL
JPA的注解
注解 | 解释 |
@Entity | 声明类为实体或表。 |
@Table | 声明表名。 |
@Basic | 指定非约束明确的各个字段。 |
@Embedded | 指定类或它的值是一个可嵌入的类的实例的实体的属性。 |
@Id | 指定的类的属性,用于识别(一个表中的主键)。 |
@GeneratedValue | 指定如何标识属性可以被初始化,例如自动、手动、或从序列表中获得的值。 |
@Transient | 指定的属性,它是不持久的,即:该值永远不会存储在数据库中。 |
@Column | 指定持久属性栏属性。 |
@SequenceGenerator | 指定在@GeneratedValue注解中指定的属性的值。它创建了一个序列。 |
@TableGenerator | 指定在@GeneratedValue批注指定属性的值发生器。它创造了的值生成的表。 |
@AccessType | 这种类型的注释用于设置访问类型。如果设置@AccessType(FIELD),则可以直接访问变量并且不需要getter和setter,但必须为public。如果设置@AccessType(PROPERTY),通过getter和setter方法访问Entity的变量。 |
@JoinColumn | 指定一个实体组织或实体的集合。这是用在多对一和一对多关联。 |
@UniqueConstraint | 指定的字段和用于主要或辅助表的唯一约束。 |
@ColumnResult | 参考使用select子句的SQL查询中的列名。 |
@ManyToMany | 定义了连接表之间的多对多一对多的关系。 |
@ManyToOne | 定义了连接表之间的多对一的关系。 |
@OneToMany | 定义了连接表之间存在一个一对多的关系。 |
@OneToOne | 定义了连接表之间有一个一对一的关系。 |
@NamedQueries | 指定命名查询的列表。 |
@NamedQuery | 指定使用静态名称的查询。 |
依赖及配置
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
#数据源配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=utf8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
接口约定命名规则:
六、Transaction
是声明式事务管理 编程中使用的注解
事务的基本要素(ACID)
- 原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
- 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
- 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
- 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
@Transactional参数
value: 一般用来配置指定的事务管理器。
propagation: 事务的传播属性,有七种。见枚举Propagation,默认REQUIRED。
//支持当前事务,如果不存在就创建一个
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
//支持当前事务,如果不存在就以非事务的方式运行
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
//支持当前事务,不存在就抛出异常
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
//创建一个新事务,如果当前有事务就暂停当前事务
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
//以非事务方式运行,如果当前有事务就暂停当前事务
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
//以非事务的方式运行,如果当前有事务就抛出异常
NEVER(TransactionDefinition.PROPAGATION_NEVER),
//如果当前有事务,就加入当前事务。
NESTED(TransactionDefinition.PROPAGATION_NESTED);
isolation: 隔离级别。事务的隔离级别有4种。我们看一下Isolation枚举类。
//使用默认的隔离级别,取决于底层数据库的默认隔离级别
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
//读未提交,这种隔离级别最低,会出现脏读,不可重复读,虚读(幻读)等情况。一般不用。
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
//读已提交,这种隔离级别可以防止脏读的产生,但是无法避免不可重复读和虚读(幻读)的出现。
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
//可重复读,这种隔离级别可以防止脏读、不可重复读的出现,但是无法避免虚读(幻读)的产生。
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
//串行化,这种隔离级别最高,可以避免脏读、不可重复读和虚读(幻读)的产生。
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
Mysql默认隔离级别为可重复读。
关于事务的并发问题
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
timeout : 事务的超时时间,默认为-1,即事务直到完成都不会超时。
readOnly: 是否只读,一般用来标识。拥有这个标识,写入操作不一定会失败,取决于数据库系统。
rollbackFor: 事务回滚条件。参数为继承Throwable的class类。
rollbackForClassName: 事务回滚条件。可以接受String数组。
noRollbackFor: 事务不会回滚条件。
noRollbackForClassName: 事务不会回滚条件。