对数据库进行操作时,实现并发控制
并发控制:当程序中可能出现并发的情况时,就要考虑到并发情况下数据的准确性,要做到多个用户一起操作时,所得到的的结果和他单独操作时的结果一样,避免产生脏读,幻读和不可重复读等问题。
悲观锁
悲观锁是一种悲观的态度类来防止一切数据冲突,它是一种预防的姿态在修改数据之前就把数据锁住,然后对数据进行读写。在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁才可对数据进行加锁。
特点:
可以完全保证数据的独占性和正确性,因为每次请求都会先对数据加锁,而加锁解锁过程会造成资源消耗,性能不高。
手动加悲观锁:读锁LOCK tables test_db read 释放锁 UNLOCK TABLES;
写锁:LOCK tables test_db WRITE 释放锁 UNLOCK TABLES;
乐观锁
乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁,只有当数据提交时才通过一种机制来验证数据是否存在冲突。
特点:
乐观锁是一种并发类型的锁,本身不对数据加锁,通过业务实现锁的功能。但是当并发量特别大时,会造成大量请求冲突,导致大部分请求操作无功而返,造成资源浪费。所以在高并发情况下,乐观锁的性能反而不如悲观锁。
实现:
1.在表中添加一个版本号字段,记录数据库表的操作次数(版本号)。版本号不同视为数据过期。
2.CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。
session和cookie的底层
客户端第一次访问Session的时候,会在服务器端生成一个Session对象并生成一个唯一标识JSessionId,服务器端会将JSessionID存放在Cookie中响应给客户端,客户端之后的每一次请求都会JSessionID,服务器端从Cookie中获得JSessionID,去查找对应的session对象。如果没有查找到就会创建一个新的session对象,查找到就可以进行后续操作
http比较重要的特性之一: 无状态
http协议是无状态的,客户端与浏览器之间基于请求-响应实现数据交互,响应结束之后两者之间会断开连接,由于每次会话都是一次新的连接,所以服务器无法从连接上获取会话状态。因此称为无状态。这样的协议保持了http的简单性,能够处理大量的事务,提高了效率。
然而无状态性,意味着页面发生跳转之后服务器无从得知用于在上一个页面的输入,也无从得知用户是否登录。
解决方法:
由于http在请求时一般会分为三部分:状态行、请求头、请求体(只有在post和get请求方法中有)。与http请求相似,响应也可以分为状态行、响应头、响应体(响应体只存在于部分http请求方法的响应中)。根据这一特征,可以在请求头中加一个记录用户状态信息请求头。就可以实现用户状态的传递。
这也正是Cookie的实现方式,Cookie是存储在客户端的一个特殊的字符串,在发送HTTP请求时,这个字符串会添加到一个名为Cookie的请求头中一同发送到服务器。Session的实现方式也类似,不同的是状态信息存储在了服务器中,而只在客户端的Cookie中存储了一个表示该会话标识的SessionId。
Cookie
Cookie通过Cookie请求头和Set-Cookie响应头实现:
Set-Cookie- 服务器响应头,用于告诉客户端要设置Cookie。
Cookie- 请求头,根据Set-Cookie设置并保存到客户端的Cookie值,会在再次发送HTTP请求时通过这个请求头一同发送到服务器。
Session
Session同样是为了记录用户状态,对于每个用户来说都会有相应的一个状态值保存在服务器中,而只在客户端记录一个sessionID用于区分是哪个用户的Session。
如果cookie被禁用,还能用session吗?
如果浏览器禁用了 cookie,浏览器请求服务器无法携带 sessionid,服务器无法识别请求中的用户身份,session失效。但是可以通过其他方法在禁用 cookie 的情况下,可以继续使用session。
1.通过url重写,把 sessionid 作为参数追加的原 url 中,后续的浏览器与服务器交互中携带 sessionid 参数。
2.服务器的返回数据中包含 sessionid,浏览器发送请求时,携带 sessionid 参数。
3.通过 Http 协议其他 header 字段,服务器每次返回时设置该 header 字段信息,浏览器中 js 读取该 header 字段,请求服务器时,js设置携带该 header 字段。