1. 程式人生 > 實用技巧 >瞭解http協議跳過beart程式碼的環境,解決甲開發者的高併發需求

瞭解http協議跳過beart程式碼的環境,解決甲開發者的高併發需求

websocket服務端往往需要和服務層打交道,因此需要將服務層的一些bean注入到websocket實現類中使用,但是呢,websocket實現類雖然頂部加上了@Component註解,依然無法通過@Resource和@Autowire注入spring容器管理下的bean。後來就想用ApplicationContext獲取spring容器管理下的bean。但是無法獲取ApplicationContext的例項,因為該例項也是在spring下管理的,有點小奔潰。找到解決辦法,那就是在初始化ApplicationContext例項的時候將該引用儲存到websocket類裡。如下

@Component
@ServerEndpoint(value = "/messageSocket/{userId}")
public class MessageWebSocket {
        /**
     * 此處是解決無法注入的關鍵
     */
    private static ApplicationContext applicationContext;


    public static void setApplicationContext(ApplicationContext applicationContext) {
        MessageWebSocket.applicationContext = applicationContext;
    }

  @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId) {
    }

  @OnClose
    public void onClose() {
  }

  @OnMessage
    public void onMessage(String messageStr, Session session, @PathParam("userId") Integer userId) throws IOException {
        //applicationContext使用
        ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor)applicationContext.getBean("defaultThreadPool");
  }

  @OnError
    public void onError(Session session, Throwable error) {
  }
}

然後在初始化ApplicationContext時(在springboot啟動類中)對該類的MessageWebSocket進行賦值

public class WebApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(WebApplication.class);
        ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
        //解決WebSocket不能注入的問題
        MessageWebSocket.setApplicationContext(configurableApplicationContext);
    }
}

思考:

  為什麼websocket注入不進bean呢(已經將其加入了spring管理了,而且其他類是能夠注入websocket的實現bean)?

    網上也沒有這個問題的具體解釋,我的感覺是websocket連線是需要建立多個執行緒的,其與spring自動注入有某種衝突,因此@Resource和@Autowire無法注入bean的引用。

MySQL的CRUD操作

從Terminal中,可以對資料庫進行連結,無需GUI介面就可以對資料庫進行相關操作。對於Linux、Windows、MacOS,也可以使用視覺化軟體Navicat、MySQL Workbench進行GUI操作。

資料庫命令列部分(使用終端操作資料庫):

使用Terminal可以進行CRUD操作,即對資料進行增刪改查操作。CRUD=Create增、Retrieve查、Update改、Delete刪。在下面的小節中,將不會按照市面上大部分文章中按照關鍵字的使用進行書寫,而會按照語句的功能所對應的CRUD操作進行梳理,更便於今後使用的查詢。因此,CRUD操作之間可能會存在重複。

使用者及設定Log in &Settings:

登入資料庫伺服器:使用命令mysql -uroot -pPASSWORD可以利用終端登入資料庫伺服器。登陸後,Terminal中會顯示“mysql>”來表示使用者在和mysql進行互動。可以用長引數--host=localhost --user=root --password=PASSWORD來代替短引數-t -u -p


增加新使用者:不想使用root這麼高的許可權,但是又需要分配一個新使用者給普通使用者,這時候可以使用grant進行分配。
如果想增加一個使用者user1,密碼是passwd1,讓他可以在任何主機上登入,並對所有資料庫有查詢、插入、修改、刪除的許可權,在root使用者連入MySQL後,鍵入以下命令:
grant select,insert,update,delete on *.* to user1@"%" identified by "passwd1";
grant後可以加select、insert、update、delete、create、drop、index、alter、grant、references、reload、shutdown、process、file這14個許可權,如果想要加上全部許可權,用all或者all privileges;*.*表示資料庫.資料表,可以指定可訪問的資料庫中的資料表;"%"表示任何連線地址,可以使localhost、ip地址、機器名字、域名,但不能為空。
但這樣的壞處是,任何知道這個使用者的人,只要可以連線上你的主機,就可以遠端登入,修改你任何的資料庫中資料表中的內容。我們常使用下面的命令增加普通使用者:
grant select,insert,update,delete on Programme.* to Jack@localhost identified by "HiJack";
這樣,使用者Jack就只能在本機修改Programme資料庫中的相關內容了。另外,也可以不設定密碼,只要將原來輸入密碼的地方改成空字串""即可。


修改密碼:使用mysqladmin -uXXX -pPASSWORD password NEWPASSWORD可以對使用者的密碼進行修改。

檢視使用者許可權:使用show grants for "XXX"@"localhost"可以檢視使用者XXX的許可權,localhost表示連線地址。

解除使用者許可權:使用revoke privileges on 資料庫名[.表名] from 使用者名稱對此使用者在某資料庫中的某許可權進行解除。

刪除使用者:在root登入MySQL後,可以使用drop user 'XXX'@'localhost';來刪除資料庫中的本地使用者XXX。刪除使用者不會刪除此使用者操作過的資料庫資料表。

檢視關鍵字幫助文件:登入MySQL後,可以使用? KEYWORD來檢視關鍵字的幫助文件。

六張自動建立的資料表:在資料庫中,有四張表(是資料表還是資料庫)是自動建立的,分別是:

  • INFORMATION_SCHEMA:資訊資料庫,儲存了MySQL伺服器所維護的所有其他資料庫的資訊。
  • PERFORMANCE_SCHEMA:主要用於收集資料庫伺服器的效能引數、提供程序等待的詳細資訊(鎖、互斥變數、檔案資訊)、儲存歷史事件的彙總資訊、可以容易的新增和刪除監控事件點和MySQL伺服器監控週期。
  • MYSQL:儲存MySQL的許可權、引數、物件和狀態資訊(許可權、DB引數、外掛、主從等)
  • SYS:可以快速的瞭解系統的元資料資訊。
  • SAKILA:是MySQL的一個樣本資料庫,裡面都是一些例子。

檢視儲存引擎:使用命令show engines;可以檢視系統支援的儲存引擎。

選中資料庫:使用命令use DATABASE1;可以對 DATABASE1進行操作,如果成功選中,mysql會回覆Database changed。如果沒有這張資料表,會顯示Empty set

退出資料庫伺服器:使用命令exit;可以退出資料庫伺服器,停止使用者和mysql的互動。

MySQL增操作Create:

在資料庫伺服器中建立資料庫:使用命令create database NAME1;可以在資料庫伺服器中建立一個名為NAME1的資料庫。一旦建立成功,mysql會回覆Query OK

建立資料表:使用命令create table TABLENAME1(name varchar(20), species varchar(20), birth date, ......);可以在當前資料庫中創建出一張名為TABLENAME1,表頭(即資料欄位)為name、species、birth等專案的一張空資料表。其中規定了name列中需要的資料是varchar型別,最多20字元;species列中需要的資料是varchar型別,最多20字元;birth列中需要date型別的資料。建立成功後,mysql會回覆Query OK。
當然,每個欄位都可以更為詳細,如create table TABLENAME1 (COLNAME1 TYPE CONSTRAINT DEFAULTVALUE);
要注意:欄位名之間要用逗號進行隔開,逗號後要新增空格,最後一個欄位後不加逗號。

資料表插入新欄位(新增列):使用alter table NAME add column COLUMN_NAME TYPE;可以在名為NAME的資料表最後新增一個名為COLUMN_NAME、型別為TYPE的欄位。如果在資料表的中間加入新欄位(新列),使用alter table NAME add column COLUMN_NAME TYPE after ORIGIN_COLUMN;可以將新欄位新增到指定原欄位ORIGIN_COLUMN的後面,如果要插入在表格最前面,使用first來替代after ORIGIN_COLUMN即可。

向資料表中插入資料記錄(新增資料記錄):使用命令insert into TABLE1 values('Peter','Edward','2020-02-02',....);可以向資料庫中的資料表中新增資料記錄。插入的資料需要按照建立資料表時的順序和型別要求,進行輸入。如果插入資料記錄是全的,可以用上面一種形式,如果插入亂序或者不全的資料記錄,使用insert into TABLE1(field1,field2,......,fieldN) values(value1,value2,......,valueN);,其中只需前後括號中的欄位和欄位值的N相等即可,N和資料表的欄位總數可以不一致(前提是不書寫的欄位可以預設是空)(即插入資料記錄時,只需填寫不能為空的欄位)。
也可以使用set關鍵字進行資料插入,使用insert into TABLE1 set field1=value1, field2=value2,......,fieldN=valueN;
set和insert into的主要區別在於:insert能一次插入多條資料記錄:insert into TABLE1(field1,field2,......,fieldN) values(value1,value2,......,valueN①),(value1,value2,......,valueN②),(value1,value2,......,valueN③);

複製資料表(新增資料記錄):複製已有的資料表,用兩個語句實現:①create table TABLE2 like TABLE1;複製資料表格式;②insert into TABLE2 select * from TABLE1;複製資料表資料記錄。如果資料表在不同的資料庫中,在use DB2;的情況下,將上文的TABLE1改成DB1.TABLE1即可。
如果需要再已有空表中複製進另一張資料表,可以先刪除表,再用之前的名字新建一張資料表。

MySQL查操作Retrieve:

查詢資料庫伺服器中的資料庫:使用命令show databases;可以將資料庫伺服器中的資料庫列在終端上。
進一步,要知道資料庫使用的字元編碼,使用show create database DB01;就可以看到DB01使用的字元編碼。

檢視資料庫中的資料表:使用命令show tables;可以得到選中資料庫中所有的資料表。

檢視資料表單的詳情:使用命令describe TABLE1;desc TABLE1可以檢視建立好的資料表的結構。其中資料表中的欄位和其相應屬性等會列在輸出中。Field表示欄位,Type表示變數型別,Null表示是否支援空值,Key表示約束條件相關內容,Default表示預設值,Extra表示備註。
另外,可以使用show create table TABLE1 \G;檢視更全面的表定義資訊,如資料庫儲存引擎和字符集編碼。

查詢表單內容(查資料記錄):使用命令select * from TABLE1 [where header1=1];可以在選中資料庫後檢視資料庫中的表單。中括號中可以新增查詢條件,也可以不加。(這裡的一個*表示一條資料記錄的全部內容)如果只需要部分欄位的欄位值,可以將*改成指定的欄位名,多個欄位名之間用逗號分隔。
利用as或空格可以進行別名。如select COL1 A1,COL2 A2 from TABLE1;select COL1 as A1,COL2 as A2 from TABLE1;就可以將COL1和COL2列的欄位名稱變成A1和A2。
完整的select語法如下:select [all/distinct] COL/* [as XXX] from TABLE where CONDITION group by CONDITION having CONDITION order by CONDITION limit CONDITION;要按照相對順序進行書寫,不然會報錯。如果別名有MySQL保留關鍵字或者有空格,必須加引號,MySQL中單引號和雙引號等效。XXX表示欄位別名,並不修改欄位名,只是將欄位或者欄位表示式在顯示時使用別名。同樣,更改顯示順序也只需要將COL1和COL2等欄位的順序在上述查詢語句中掉換即可。
下面重點說說select查操作的附加條件子句:

  • COL1和COL2這些欄位可以進行運算,換而言之,select後可以跟的不止欄位本身,也可以是和欄位有關或無關的欄位表示式(及函式)。
  • all/distinct:表示查詢顯示的資料記錄是否顯示重複資料,distinct表示去重;all或者不加此選項表示不去重,顯示重複資料。
  • order by COL asc/desc:表示展示資料的順序是按照COL欄位進行升序/降序排列,desc表示降序排列,asc或只用order by表示(預設)升序排列。
  • limit:表示展示資料記錄的條數,limit的語法為limit offset_start,row_count兩個引數表示從第offset_start行開始,取row_count條資料記錄。如果只寫一個引數,表示取row_count條資料記錄。
  • where:表示條件,select所展示的資料必須是滿足where後面條件的資料記錄,不滿足的資料記錄將會被直接過濾掉。條件的書寫必須能得到一個布林值。

MySQL改操作Update:

為資料庫改名:登入MySQL後,可以使用rename database OldName to NewName;將資料庫OldName改名為NewName。請注意,在進入資料庫(use)後無法進行資料庫改名操作。

對現存資料表改名:使用alter table NAME1 rename to NAME2;就可以把原來名為NAME1的列改為NAME2。

對現存表的列改名(修改欄位名):使用alter table TABLENAME change OLD_COLUMN_NAME NEW_COLUMN_NAME TYPE;可以把名為TABLENAME的資料表中的列OLD_COLUMN_NAME改為NEW_COLUMN_NAME,其中列的型別為TYPE。

設定欄位預設值(修改欄位預設值):可以使用alter table TABLE1 modify COLUMN_NAME TYPE default DEFAULT_VALUE;

修改欄位資料型別:可以使用alter table TABLE1 change NAME1 NAME2 TYPE_TOBE;對現有資料表TABLE1的NAME1欄位進行欄位名和資料型別的修改,(如果NAME1=NAME2,則只進行資料型別的修改)將資料型別改為TYPE_TOBE,將欄位名改為NAME2
也可以使用alter table TABLE1 modify NAME1 TYPE_TOBE表示將TABLE1資料表中的NAME1欄位改為TYPE_TOBE

修改資料表中欄位的順序(修改列的順序):可以使用alter table TABLE1 modify COL1 TYPE1 after ORIGIN_COL;可以將原有的COL1欄位移動到原有欄位ORIGIN_COL的後面,如果需要移動到最前面,使用first替代after ORIGIN_COL,如果在最後,直接省略after ORIGIN_COL即可。

修改資料記錄中的欄位值(修改單元格的值):使用update TABLE1 set COL1="VALUE1" where CONDITION;表示在TABLE1中,如果滿足CONDITION1的條件,將COL1的欄位改成VALUE1。如果有多個需要修改的單元格,將所有需要改的欄位都寫在set後面,如update TABLE1 set COL1="VALUE1" , COL2="VALUE2",...... where CONDITION;
如果根據不同的CONDITION決定同一列中的欄位值,使用下面的語句進行修改:

update TABLE1 set COL1=(

網友解答(推薦):

  本質原因:spring管理的都是單例(singleton),和websocket(多物件)想衝突。

  詳細解釋:專案啟動時初始化,會初始化websocket(非使用者連線的),spring同時會為其注入service,該物件的service不是null,被成功的注入。但是,由於spring預設管理的是單例,所以只會注入一次service。當新使用者進入聊天時,系統又會建立一個新的websocket物件,這是矛盾出現了:spring管理的都是單例,不會給第二個websocket物件注入service,所以導致只要是使用者連線建立的websocket物件,都不能再注入了。

  像controller裡面有service,service裡面有dao。因為controller,service,dao都是單例,所以注入時不會報null。但是websocket不是單例,所以使用spring注入一次後,後面的物件就不會再注入了,會報null。