Java学习笔记-全栈-Java基础-13-JavaWeb基础

1. 前后端交互基础

  • 通过超链接跳转传递数据

www.test.com?id=1
与form表单不同的是,uri中的id=1可能是从a标签中直接获取的

  • 通过form表单

1.1 form

  • aciton:请求服务器资源(URL),对应控制器的Mapping
  • name:后端使用,区分唯一(可重名,后端用容器接收)
  • id:前端使用,区分唯一

1.2 引用路径的区别

  • 1)href:指定资源路径,将当前元素与资源之间建立联系
  • 2)src:指向外部资源路径,将该资源应用到当前元素中替换作用
  • 3)action:将本页面的请求传递给目标路径

1.3 RESTful

RESTful是一种前后端交互的规范API。可以理解为“一种约定成俗的编程习惯”。

通常情况,只涉及到前后端请求方法上的约定。

本质上是通过幂等来区分

幂等:概念源于离散数学,用于判断两个关系是否幂等。可理解为“重复操作不改变结果”。

GET、PUT、DELETE都是幂等的

  • 同一个GET无论多少次,获得的资源都是一样的
  • 同一个PUT无论多少次,更新结果依旧一样
  • 同一个DELETE结果都是一样的,那就是“该对象”被删除,不会有副作用。

POST非幂等

  • 同一个POST,请求多次,每个请求都会各自生成一个结果,因此非幂等。

一般情况下,可以按照功能区分。

增:POST
删:DELETE
改:PUT
查:GET

REST-CRUD设计实例

会涉及到一点点后端控制器的知识

功能请求Uri对应返回视图请求方式访问后的操作
查找所有userusersuserlistGet从数据库获得数据,在页面显示所有user
来到添加页面useruseraddget从数据库中获取必要的提示数据(比如可以填写的部门)在页面展示
添加useruser重定向:userlistpost提交后从user中实现Dao增加,然后回到userlist显示最新数据
来到修改页面(回显)User/1useraddget利用PathVariable查询数据,然后将其回显到ueradd页面
修改userUser重定向:userlistput在useradd中修改完毕后put到user,user中更新后返回到userlist显示最新数据
删除一个userUser/1重定向:userlistdelete利用PathVariable实现删除,并返回uselist显示最新数据

添加页面和修改页面可以一页两用
浏览器单击“添加”按钮的时候,只能回显部分必要的提示数据(model为null);
单击“修改”按钮的时候,能通过@pathvariable(Spring注解)查询到对应model:可通过model是否为null,分别展示不同的细节。

由于浏览器版本:
对于put、delete请求,需要在post表单内使用进行请求转换(固定写法)
<input type=“hidden” name="_method" value=“delete”/>

在springboot2.x以上,Delete请求还得配置
spring.mvc.hiddenmethod.filter.enabled=true

1.4 GET和POST在报文上的区别

GET:URL后跟参数
POST:报文中空一行,再跟参数
在这里插入图片描述

1.5 URL中的特殊字符

序号特殊字符含义十六进制值
1.+URL 中+号表示空格%2B
2.空格URL中的空格可以用+号或者编码%20
3./分隔目录和子目录%2F
4.?分隔实际的 URL 和参数%3F
5.%指定特殊字符%25
6.#表示书签%23
7.&URL 中指定的参数间的分隔符%26
8.=URL 中指定参数的值%3D

中文会自动进行编码

2. 手写web服务器

流程如下

2.1 获取请求协议

  • 创建serversocket
  • 建立连接,获取客户端的socket
  • 通过输入流获取请求协议
  • 分解请求协议中的内容

2.2 返回响应协议

  • 准备内容
  • 获取字节数组长度
  • 拼接响应协议,注意空格与换行
    • \r : return 到当前行的最左边。
    • \n: newline 向下移动一行,并不移动左右
    • Linux中\n表示回车+换行;
    • Windows中\r\n表示回车+换行。
    • Mac中\r表示回车+换行。
  • 使用输出流输出

封装式代码结构:

  • 内部:
    - 动态添加content
    - 根据字节码拼接响应头
    - 根据状态码返回相应协议
  • 外部:
    - 传入content和状态码

2.3 Servlet,XML

  • 通过url获取配置文件,反射成所需的class,再用servlet处理业务。
  • 使用servlet(response,request),解耦代码,实现封装

以上内容作为总结性的文字参考,没有具体代码。
具体代码可查看尚硅谷java300集进行学习

3. JDBC的使用

JDBC只是Java提供的对外接口,具体的实现由数据库公司来实现。比如mysql或Oracle。

3.1 建立连接

//1.加载驱动类
Class.forName("com.mysql.jdbc.Driver");

//2.使用manager链接数据库,实际时使用socket进行远程连接,较耗时,真正开发中都是用连接池来管理连接对象
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/study?serverTimezone=UTC","root","123456");

凡是引入mysql-url的(无论是直接使用JDBC还是框架中引入mysql),都要加上serverTimezone=UTC,否则报错!

3.2 常用接口

  • 1.Statement:用于执行静态的SQL语句并返回它生成结果的对象,

    • a)三种实现类
      • i.Statement:只能发送不带参数的简单sql语句,一般只用于批处理
        • 1.addBatch(“sql语句”),插入语句
        • 2.executeBatch(),执行批量插入
      • ii.preparedStatement:效率高,防止SQL注入,普通需求使用这个
      • iii.CallableStatement:继承自ii,由方法prePareCall创建,用于调用存储过程
    • b)常用Statement方法
      • i.Execute(),运行所有语句,返回是否有结果集
      • ii.executeQuery();运行select语句,然后resultSet结果集
      • iii.executeUpdate();运行insert/update/delete操作,返回更新行数
  • 2.ResultSet接口:

    • a)Statement执行sql语句时返回resultset结果集
    • b)Resultset提供的检索不同类型字段的方法,常用的有
      • i.getString();获得在数据库里面时varchar、char等类型对象
      • ii.getFloat();
      • iii.getDate();
      • iv.getBoolean();
  • 3.依序关系使用对象及连接

    • a)Resultset->statement->connection

3.3 事务

将多个事情组成一个事件集,这个事件集内的所有事件要么同时执行成功,要么同时失败,则称为事务。
是数据库操作的一个执行单元

mysql默认自动提交事务,且每条语句都在单独的事务中
mysql相关操作

  • start transaction 开启事务
  • Rollback 回滚事务
  • Commit 提交事务

ACID

  • A:atomicity原子性
    • 象征事件集是一个整体,不可分可,同生共死(要么…要么…)。
  • C:consistency一致性
    • 无论执行失败或成功,事务执行前后,数据应当是完整的,一致的。
  • I:isolation隔离性
    • 通过数据串行化,使得在同一时间仅有一个请求用于同一数据。保证在并发的情况下,多个用户对同一个数据进行操作的时候,不会相互影响。
  • D:durability持久性
    • 在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。即使数据库发生故障也不应该对其有任何影响。

事务的隔离级别

隔离级别分为:

  • (脏读)READ UNCOMMITTED
  • (不可重复读)READ COMMITTED
  • (虚读\幻读)REPEATABLE READ
  • (序列化)SERIALIZABLE

不看定义,我们通过名字来理解。
个人以为英语更容易解释:

首先确定一个前提,既然称为“隔离”,那肯定至少有两个对象,一个“被隔离者”,一个“未被隔离者”。
因此,隔离级别都是用于描述两个事务之间的关系。


read uncommitted --> 读取了未提交的(数据)(oracle默认):一个事务读取了另一个事务未提交的数据,这就是“脏”(引用于汉语中的“贪脏了不属于你的东西”)


read committed --> 读取了已提交的(数据):这个比较难理解,事实上他还有个发生前提:先读了一个数据,然后再读的时候,才读取了已提交的。也就是说,在这个过程中,有第二者插手。
例子
A读取到存款还有10元,准备进行消费;
B此时消费了5元;
A消费的时候,本来刚刚查询的是10元,但是消费的时候(也进行了查询操作)却余额不足两次一样的查询数据却不一样此时就是读取了已提交的,因此也称为“不可重复读”(重复读出现了不一致数据)

mysql默认级别是repeatable read,是可以解决这个问题的,所以初学者可能有疑惑,为什么会发生这种事情。因为这个级别,是允许两个事务同时对数据进行修改的


repeatable read --> 可重复读(mysql默认):既然可重复读,也就是说,当一个事务在进行读取的时候,不允许被其他事务修改
还是上面那个例子:
A读取到存款还有10元,准备进行消费;
B此时想进行消费(修改操作),但是由于A正在操作,因此B操作失败
A成功进行消费。
repeatable read用于锁定修改操作(Update),但是无法锁定插入操作(Insert)
当A进行重复读的时候,若在重复读期间,第三方进行了插入操作(这是被允许的),此时就出现了“幻觉”。
如:
A查询存款为10元;但他有点不放心,决定再查一次
此时B存了5元;
A刷新查询,发现变成了15!刚才出现幻觉了吗?(幻读)


serializable --> 序列化:此处的序列化跟java的对象序列化不是一个东西。“序列”最常见的含义是“有顺序的列”,因此,他的意思就是指,所有事务按顺序执行,一旦对一个数据开启了事务,其他人就只能排队等候
这种自然能够排除任何数据错误,同样的,效率最低,几乎不使用


  • 1、READ UNCOMMITTED: 赃读、不可重复读、虚读都有可能发生。
  • 2、READ COMMITTED: 避免赃读。不可重复读、虚读都有可能发生。(oracle默认的)
  • 4、REPEATABLE READ:避免赃读、不可重复读。虚读有可能发生。(mysql默认)
  • 8、SERIALIZABLE: 避免赃读、不可重复读、虚读。
    级别越高,性能越低,数据越安全

JDBC中的事务隔离级别设置

在这里插入图片描述

设置隔离级别:必须在开启事务之前。
Connection.setTransactionIsolation(int level);

JDBC中的事务

事务开始于:

  • 执行一条DML语句(INSERT、UPDATE或DELETE)
  • 前一个事务结束后,又输入了另一条DML语句

事务结束于:

  • 执行COMMIT(提交)或ROLLBACK(回滚)语句
  • 执行DDL语句(create、alter、drop和 truncate),将自动执行COMMIT。
  • 断开数据库连接
  • 执行DML语句,该语句失败了,则会自动执行ROLLBACK。

注意:
JDBC默认自动提交事务,若设为手动提交,只有提交之后才会真正执行DDL语句。
因此:
commit()才是事务的结束,execute和statement不是。

一般来说,通过try-catch,在catch中回滚。

JDBC使用事务

  • Connection.setAutoCommit(false); 开启事务
  • Connection.rollback(); 回滚事务
  • Connection.commit(); 提交事务

在这里插入图片描述

Savepoint

java.sql提供的方法,通过Savepoint可以实现部分提交、部分回滚

需求:AB(必须),CD(可选)

Connection conn = null;
Savepoint savepoint = null;  //保存点,记录操作的当前位置,之后可以回滚到指定的位置。(可以回滚一部分)
try{
  //1 获得连接
  conn = ...;
  //2 开启事务
  conn.setAutoCommit(false);
  A
  B
  savepoint = conn.setSavepoint();
  C
  D
  //3 提交事务
  conn.commit();
} catche(){
  if(savepoint != null){   //CD异常
     // 回滚到CD之前
     conn.rollback(savepoint);
     // 提交AB
     conn.commit();
  } else{   //AB异常
     // 回滚AB
     conn.rollback();
  }
}

3.4 JDBC中的特殊对象

CLOB

Character Large Object,顾名思义,用于存储大量的文本数据。

大字段有些特殊,不同的数据库处理的方式不一样,大字段的操作常常以流的方式来处理,而非一般的字段,一次即可读出数据。

mysql中对应的相关类型:

  • TINYTEXT
  • TEXT
  • MEDIUMTEXT
  • LONGTEXT

BLOB

Binary Large Object,顾名思义,用于存储大量的二进制数据

也是通过流来处理

mysql中对应的相关类型:

  • TINYBLOB
  • BLOB
  • MEDIUMBLOB
  • LONGBLOB

3.5 数据库连接池

原理

"池"这个概念,不应该陌生。接触最早的“池”就是常量池:用于存放常量,当程序使用该常量的时候,直接从常量池中取,而不是新建一个。因此多个常量(如String指向的字符串常量)具有相同地址。
因此,“连接池”是用于存放数据库连接的,当程序需要连接的时候,就从连接池中获取,不需要就放回。

在这里插入图片描述目的:与数据库建立连接实际上非常耗费资源,提前构建连接池能够大大提高数据交互效率。

常用数据库连接池

DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

由于Spring的缘故,因此博主学习的时候用的是C3P0。但是不同的连接池的使用方法基本上没啥差别。

目前在用阿里的druid

使用步骤:

  1. 添加jar包
  2. 编写配置文件c3p0-config.xml,放在classpath中,或classes目录中
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
  <default-config>
	<property name="driverClass">com.mysql.jdbc.Driver</property>
	<property name="jdbcUrl">jdbc:mysql://localhost:3306/day12</property>
	<property name="user">root</property>
	<property name="password">123456</property>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
  </default-config>
</c3p0-config>

配置的属性可以通过顾名思义理解(如maxPoolSize就是指池中最大连接数),在此不再赘述,不懂得可以百度。

<property name=“driverClass”>com.mysql.jdbc.Driver</property> 这句话在高版本的框架会警告已经完成自动配置,可以不写

  1. 编写工具类,使用

此处无需耗费过多的时间,掌握连接池的原理,以及xml配置生效原理即可,后面学习框架配置会更加简单。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值