日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

spring-session用mysql实现session共享实践

發布時間:2025/4/5 数据库 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring-session用mysql实现session共享实践 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前段時間,寫了篇<spring-session-data-redis解決session共享的問題>文章,介紹了spring-session使用redis存儲實現session共享的內部機制,

遇到很多人提問到jdbc的實現或者為什么只有理論沒有實踐?索性就實踐一下jdbc方式。

1.spring-session實現了使用不同存儲介質保存共享的session的api

spring-session實現session共享的實現有三種:

jdbc:使用數據庫做介質,支持多種數據,如oracle,sqlserver,mysql等,對應的實現類

RedisOperationsSessionRepository

?

                  <圖一 支持的數據庫類型及腳本>

redis:使用redis做存儲介質,對應的實現類為:

JdbcOperationsSessionRepository

Hazelcast:使用內存做存儲介質,對應的實現類為:

HazelcastSessionRepository

Hazelcast作為一個高度可擴展的數據分發和集群平臺,提供了高效的、可擴展的分布式數據存儲、數據緩存。Hazelcast是開源的,在分布式技術方面,Hazelcast提供了十分友好的接口供開發者選擇,如Map,Queue,ExecutorService, Lock和Jcache。
Hazelcast的穩定性很高,分布式應用可以使用Hazelcast進行存儲數據、同步數據、發布訂閱消息等。Hazelcast是基于Java開發的,其客戶端有Java, C/C++, .NET以及REST。Hazelcast同時也支持memcache協議。它很好的支持了Hibernate,可以很容易的在當今流行的數據庫系統中應用。

2.spring-session-jdbc使用mysql保存共享session的實現實踐

2.0 準備工作

  如<圖一 支持的數據庫類型及腳本>所示,找到schema-mysql.sql腳本,放入sql-client客戶端執行,如sqlyog,紅色部分是我自己添加的,為了可以重復執行的。

DROP TABLE IF EXISTS SPRING_SESSION_ATTRIBUTES; DROP TABLE IF EXISTS SPRING_SESSION; CREATE TABLE SPRING_SESSION (PRIMARY_ID CHAR(36) NOT NULL,SESSION_ID CHAR(36) NOT NULL,CREATION_TIME BIGINT NOT NULL,LAST_ACCESS_TIME BIGINT NOT NULL,MAX_INACTIVE_INTERVAL INT NOT NULL,EXPIRY_TIME BIGINT NOT NULL,PRINCIPAL_NAME VARCHAR(100),CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ) ENGINE=INNODB ROW_FORMAT=DYNAMIC;CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);CREATE TABLE SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID CHAR(36) NOT NULL,ATTRIBUTE_NAME VARCHAR(200) NOT NULL,ATTRIBUTE_BYTES BLOB NOT NULL,CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) ENGINE=INNODB ROW_FORMAT=DYNAMIC;

此時創建了兩張表

  SPRING_SESSION

  SPRING_SESSION_ATTRIBUTES

 通過PRIMARY_ID關聯,執行結果如下:

?

2.1 使用sts創建spring-boot項目,項目名稱session-jdbc,使用jdbc,mysql,web(方便測試)的start,創建完項目如下:

2.2 添加spring-session-jdbc依賴

<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-jdbc</artifactId></dependency>

2.3 配置jdbc屬性application.properties

spring.session.store-type=JDBC spring.datasource.url=jdbc:mysql://localhost:3306/www?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false spring.datasource.username=root spring.datasource.password=wangwei456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.session.jdbc.cleanup-cron=0 * * * * *

注意,新版mysql的url需要增加

serverTimezone選項

而且,driver-class-name也變為com.mysql.cj.jdbc.Driver,否則有報警。

?2.4 創建測試controller

package com.example.demo;import javax.servlet.http.HttpSession;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController @RequestMapping("/jdbc") public class TestController {@RequestMapping("/welcome")public String welcome(HttpSession httpSession) {httpSession.setAttribute("hello", "world");return "hello world !";} }

2.5 測試

啟動spring-boot項目session-jdbc,訪問http://localhost:8080/jdbc/welcome/,返回"hello world".

?

查看數據庫數據信息

SPRING_SESSION表信息

SPRING_SESSION_ATTRIBUTES表信息

2.6 Q&A

? ?2.6.1?session_id是如何產生的?

? 斷點調試進入

此時的cookie和請求的一致。

進入HttpSessionAdapter的setAttribute屬性方法,再調用JdbcOperationsSessionRepository的setAttribute方法

@Overridepublic void setAttribute(String attributeName, Object attributeValue) {boolean attributeExists = (this.delegate.getAttribute(attributeName) != null);boolean attributeRemoved = (attributeValue == null);if (!attributeExists && attributeRemoved) {return;}if (attributeExists) {if (attributeRemoved) {this.delta.merge(attributeName, DeltaValue.REMOVED, (oldDeltaValue,deltaValue) -> (oldDeltaValue == DeltaValue.ADDED) ? null: deltaValue);}else {this.delta.merge(attributeName, DeltaValue.UPDATED,(oldDeltaValue,deltaValue) -> (oldDeltaValue == DeltaValue.ADDED)? oldDeltaValue: deltaValue);}}else {this.delta.merge(attributeName, DeltaValue.ADDED,(oldDeltaValue, deltaValue) -> (oldDeltaValue == DeltaValue.ADDED)? oldDeltaValue: DeltaValue.UPDATED);}this.delegate.setAttribute(attributeName, value(attributeValue));if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) ||SPRING_SECURITY_CONTEXT.equals(attributeName)) {this.changed = true;}}

調用內部類JdbcSession的構造方法

JdbcSession() {this.delegate = new MapSession();this.isNew = true;this.primaryKey = UUID.randomUUID().toString();}

其中primarykey的產生,是隨機產生的,而jdbcSession的一個成員變量delegate是MapSession的實例

/*** Creates a new instance with a secure randomly generated identifier.*/public MapSession() {this(generateId());}

而generateId()方法,調用了隨機uuid的產生

private static String generateId() {return UUID.randomUUID().toString();}

2.6.2 為何和cookie的不一致?

response中返回的cookie值為:NDM1Mjg1YjAtMmVjMi00MmQ0LWJjY2UtYzFjY2U4NzQzNDNm

數據庫中sessionId為435285b0-2ec2-42d4-bcce-c1cce874343f

為什么會這樣呢?

@Overridepublic List<String> readCookieValues(HttpServletRequest request) {Cookie[] cookies = request.getCookies();List<String> matchingCookieValues = new ArrayList<>();if (cookies != null) {for (Cookie cookie : cookies) {if (this.cookieName.equals(cookie.getName())) {String sessionId = (this.useBase64Encoding? base64Decode(cookie.getValue()): cookie.getValue());if (sessionId == null) {continue;}if (this.jvmRoute != null && sessionId.endsWith(this.jvmRoute)) {sessionId = sessionId.substring(0,sessionId.length() - this.jvmRoute.length());}matchingCookieValues.add(sessionId);}}}return matchingCookieValues;}

從代碼中我們可以知道,中間查了一個base64

435285b0-2ec2-42d4-bcce-c1cce874343f base64加密后即為:NDM1Mjg1YjAtMmVjMi00MmQ0LWJjY2UtYzFjY2U4NzQzNDNm

3.總結

? ?1.瀏覽器第一次請求的時候,服務端創建一個session,并且將名為SESSION的屬性作為響應cookie返回瀏覽器

? ?2. 瀏覽器保存名稱為SESSION的cookie作為唯一標識,下次訪問服務端時帶上此cookie

? ?3.服務端session中的名為SESSION的屬性和瀏覽器保存的cookie是不一致的,為保密原因,進行了base64加密。

? ?4.spring-session使用了簡單的配置,可以實現session持久化到數據庫。

參考文獻:

【1】https://angelbill3.iteye.com/blog/2342989

轉載于:https://www.cnblogs.com/davidwang456/p/10361550.html

總結

以上是生活随笔為你收集整理的spring-session用mysql实现session共享实践的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。