From 44b38fd07ed490584f6f68b6a3c949b77a05a41e Mon Sep 17 00:00:00 2001 From: yennanliu Date: Sat, 17 Feb 2024 18:29:31 +0800 Subject: [PATCH 01/13] update lock logic, dml --- springBank/springBankApp/sql/dml.sql | 2 + .../service/BalanceServiceRedisson.java | 38 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/springBank/springBankApp/sql/dml.sql b/springBank/springBankApp/sql/dml.sql index 6054a3e1b..e2032a595 100644 --- a/springBank/springBankApp/sql/dml.sql +++ b/springBank/springBankApp/sql/dml.sql @@ -4,6 +4,8 @@ -- select * from balance; -- truncate balance; +use spring_bank; + INSERT INTO `balance` (id, user_id, balance) VALUES (1, 1, 5000), diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java index feb71c12d..9f31bc30a 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java @@ -35,6 +35,27 @@ public List getBalances() { return balanceRepository.findAll(); } + public Balance getBalanceById(Integer id) { + + Balance balance = new Balance(); + + // lock + RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); + rwLock.readLock().lock(); + try{ + if (balanceRepository.findById(id).isPresent()){ + return balanceRepository.findById(id).get(); + } + throw new RuntimeException("can not get balance with ID = " + id); + }catch (Exception e){ + e.printStackTrace(); + }finally { + // unlock + rwLock.readLock().unlock(); + } + return balance; + } + public Balance getBalanceByUserId(Integer userId) { List balanceList = balanceRepository.findAll(); @@ -167,10 +188,12 @@ public void transferMysql(DeductBalanceDto deductBalanceDto) { log.info(">>> (BalanceServiceRedisson) transferMysql start ..."); // get lock - RLock lock = redissonClient.getLock("lock"); + //RLock lock = redissonClient.getLock("lock"); + RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); // lock - lock.lock(); + //lock.lock(); + rwLock.writeLock().lock(); try{ // V2 : Mysql @@ -178,8 +201,12 @@ public void transferMysql(DeductBalanceDto deductBalanceDto) { Thread.sleep(10000); - Balance balance1 = balanceRepository.findById(1).get(); - Balance balance2 = balanceRepository.findById(2).get(); +// Balance balance1 = balanceRepository.findById(1).get(); +// Balance balance2 = balanceRepository.findById(2).get(); + // getBalanceById + Balance balance1 = this.getBalanceById(1); + Balance balance2 = this.getBalanceById(2); + // update to DB if (balance1.getBalance() > 0 && balance2.getBalance() > 0){ balance1.setBalance(balance1.getBalance() - 1); @@ -192,7 +219,8 @@ public void transferMysql(DeductBalanceDto deductBalanceDto) { e.printStackTrace(); }finally { // unlock - lock.unlock(); + //lock.unlock(); + rwLock.writeLock().lock(); } } From 5470399873f75184cdb4e8d86dfc45ec7cdf629a Mon Sep 17 00:00:00 2001 From: yennanliu Date: Sun, 18 Feb 2024 10:26:12 +0800 Subject: [PATCH 02/13] data platform add nginx conf, update docker-compose --- SpringDataPlatform/docker-compose.yml | 13 ++++++++++ SpringDataPlatform/nginx/Dockerfile | 4 +++ SpringDataPlatform/nginx/default.conf | 13 ++++++++++ SpringDataPlatform/nginx/index.html | 7 ++++++ SpringDataPlatform/nginx/nginx.conf | 36 +++++++++++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 SpringDataPlatform/nginx/Dockerfile create mode 100644 SpringDataPlatform/nginx/default.conf create mode 100644 SpringDataPlatform/nginx/index.html create mode 100644 SpringDataPlatform/nginx/nginx.conf diff --git a/SpringDataPlatform/docker-compose.yml b/SpringDataPlatform/docker-compose.yml index 6b9fb6bb0..770f55140 100644 --- a/SpringDataPlatform/docker-compose.yml +++ b/SpringDataPlatform/docker-compose.yml @@ -45,5 +45,18 @@ services: volumes: - mysql-data:/var/lib/mysql + nginx: + image: nginx + restart: always + ports: + #- "8080:80" + - "8081:8081" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/index.html:/app/html:ro + depends_on: + - app + #- app2 + volumes: mysql-data: \ No newline at end of file diff --git a/SpringDataPlatform/nginx/Dockerfile b/SpringDataPlatform/nginx/Dockerfile new file mode 100644 index 000000000..8150df049 --- /dev/null +++ b/SpringDataPlatform/nginx/Dockerfile @@ -0,0 +1,4 @@ +# FROM nginx:alpine +# +# COPY default.conf /etc/nginx/conf.d/ +# COPY index.html /usr/share/nginx/html/ diff --git a/SpringDataPlatform/nginx/default.conf b/SpringDataPlatform/nginx/default.conf new file mode 100644 index 000000000..5eba6d100 --- /dev/null +++ b/SpringDataPlatform/nginx/default.conf @@ -0,0 +1,13 @@ +server { + listen 80; + server_name localhost; + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + ssi on; +} diff --git a/SpringDataPlatform/nginx/index.html b/SpringDataPlatform/nginx/index.html new file mode 100644 index 000000000..c92ee8ccc --- /dev/null +++ b/SpringDataPlatform/nginx/index.html @@ -0,0 +1,7 @@ + + +

Host:

+ Version: 1.1 +

helloooooo worldddddd

+ + diff --git a/SpringDataPlatform/nginx/nginx.conf b/SpringDataPlatform/nginx/nginx.conf new file mode 100644 index 000000000..6761e0140 --- /dev/null +++ b/SpringDataPlatform/nginx/nginx.conf @@ -0,0 +1,36 @@ +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + sendfile on; + keepalive_timeout 65; + + upstream dataPlatform { + server app:9999; + #server app2:9998; + } + + server { + listen 8081; + server_name localhost; + + location / { + proxy_pass http://dataPlatform; + root /usr/share/nginx/html; + index index.html index.htm; + } + + #error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# root html; +# } + } + + include servers/*; +} From 14167523145f92cd912f5fa1ceb734599497db3d Mon Sep 17 00:00:00 2001 From: yennanliu Date: Sun, 18 Feb 2024 10:33:10 +0800 Subject: [PATCH 03/13] backend uses jdk 8, make BE app work in docker-compose --- .../backend/DataPlatform/FlinkRestService/pom.xml | 12 +++++++++--- SpringDataPlatform/backend/DataPlatform/pom.xml | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/SpringDataPlatform/backend/DataPlatform/FlinkRestService/pom.xml b/SpringDataPlatform/backend/DataPlatform/FlinkRestService/pom.xml index 74db5b3de..8d497a5cf 100644 --- a/SpringDataPlatform/backend/DataPlatform/FlinkRestService/pom.xml +++ b/SpringDataPlatform/backend/DataPlatform/FlinkRestService/pom.xml @@ -19,10 +19,16 @@ FlinkRestService + + + + + + - 11 - 11 - + 1.8 + 1.8 + diff --git a/SpringDataPlatform/backend/DataPlatform/pom.xml b/SpringDataPlatform/backend/DataPlatform/pom.xml index fe79f14f5..34e921fbd 100644 --- a/SpringDataPlatform/backend/DataPlatform/pom.xml +++ b/SpringDataPlatform/backend/DataPlatform/pom.xml @@ -20,10 +20,16 @@ DataPlatform Demo project DataPlatform + + + + + + - 11 - 11 - + 1.8 + 1.8 + From 908981088fa3c4cd6a76501e92fb34c5ef19d958 Mon Sep 17 00:00:00 2001 From: yennanliu Date: Sun, 18 Feb 2024 11:12:01 +0800 Subject: [PATCH 04/13] add BE app2 in docker-compose, update config, nginx conf --- .../src/main/resources/application.properties | 2 +- SpringDataPlatform/docker-compose.yml | 34 ++++++++++++++----- SpringDataPlatform/nginx/nginx.conf | 4 +-- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/SpringDataPlatform/backend/DataPlatform/FlinkRestService/src/main/resources/application.properties b/SpringDataPlatform/backend/DataPlatform/FlinkRestService/src/main/resources/application.properties index de4a0f685..de70959e6 100644 --- a/SpringDataPlatform/backend/DataPlatform/FlinkRestService/src/main/resources/application.properties +++ b/SpringDataPlatform/backend/DataPlatform/FlinkRestService/src/main/resources/application.properties @@ -1,5 +1,5 @@ # spring -server.port=9999 +server.port=${SERVER_PORT:9999} # upload file server.tomcat.max-http-form-post-size=20MB diff --git a/SpringDataPlatform/docker-compose.yml b/SpringDataPlatform/docker-compose.yml index 770f55140..8837b168c 100644 --- a/SpringDataPlatform/docker-compose.yml +++ b/SpringDataPlatform/docker-compose.yml @@ -1,11 +1,12 @@ version: '3' services: - app: + app1: restart: always - build: ./backend/DataPlatform + build: ./backend/DataPlatform/FlinkRestService # backend dockerfile working_dir: /app volumes: - ./backend/DataPlatform:/app + - ~/.m2/repository:/root/.m2/repository # Mount Maven local repository ports: - "9999:9999" environment: @@ -16,7 +17,27 @@ services: - SPRING_JPA_SHOW_SQL=true - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here - SPRING_JPA_GENERATE_DDL=true - #- JAVA_HOME=/usr/local/openjdk-11 + depends_on: + - mysql + command: mvn clean spring-boot:run -DskipTests + + app2: + restart: always + build: ./backend/DataPlatform/FlinkRestService # backend dockerfile + working_dir: /app + volumes: + - ./backend/DataPlatform:/app + - ~/.m2/repository:/root/.m2/repository # Mount Maven local repository + ports: + - "9998:9998" # Port mapping for app2 + environment: + - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/data_platform + - SPRING_DATASOURCE_USERNAME=root + - SPRING_DATASOURCE_PASSWORD= + - SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver + - SPRING_JPA_SHOW_SQL=true + - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here + - SPRING_JPA_GENERATE_DDL=true depends_on: - mysql command: mvn clean spring-boot:run -DskipTests @@ -35,8 +56,6 @@ services: image: mysql:5.7 restart: always environment: - #https://stackoverflow.com/questions/66831863/mysql-docker-container-keeps-restarting - #MYSQL_USER: root # NO NEED to create root user, since it is created automatically MYSQL_DATABASE: data_platform MYSQL_ROOT_PASSWORD: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" @@ -49,14 +68,13 @@ services: image: nginx restart: always ports: - #- "8080:80" - "8081:8081" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/index.html:/app/html:ro depends_on: - - app - #- app2 + - app1 + - app2 volumes: mysql-data: \ No newline at end of file diff --git a/SpringDataPlatform/nginx/nginx.conf b/SpringDataPlatform/nginx/nginx.conf index 6761e0140..d05a9e78b 100644 --- a/SpringDataPlatform/nginx/nginx.conf +++ b/SpringDataPlatform/nginx/nginx.conf @@ -12,8 +12,8 @@ http { keepalive_timeout 65; upstream dataPlatform { - server app:9999; - #server app2:9998; + server app1:9999; + server app2:9998; } server { From ad40b310fb9c9ecffb6762a6c63bcc4d3e8bad41 Mon Sep 17 00:00:00 2001 From: yennanliu Date: Sun, 18 Feb 2024 17:25:05 +0800 Subject: [PATCH 05/13] add server port in docker-compose env var, make BE app 2 can run --- SpringDataPlatform/README.md | 6 ++++++ SpringDataPlatform/docker-compose.yml | 2 ++ 2 files changed, 8 insertions(+) diff --git a/SpringDataPlatform/README.md b/SpringDataPlatform/README.md index fb7d643cc..49f2ca8a6 100644 --- a/SpringDataPlatform/README.md +++ b/SpringDataPlatform/README.md @@ -53,6 +53,12 @@ ARCHITECTURE : ```bash docker-compose up + +# rebuild (use updated java code) and run +docker-compose up --build + +# restart +docker-compose restart ``` diff --git a/SpringDataPlatform/docker-compose.yml b/SpringDataPlatform/docker-compose.yml index 8837b168c..2a721f6b1 100644 --- a/SpringDataPlatform/docker-compose.yml +++ b/SpringDataPlatform/docker-compose.yml @@ -17,6 +17,7 @@ services: - SPRING_JPA_SHOW_SQL=true - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here - SPRING_JPA_GENERATE_DDL=true + - SERVER_PORT=9999 depends_on: - mysql command: mvn clean spring-boot:run -DskipTests @@ -38,6 +39,7 @@ services: - SPRING_JPA_SHOW_SQL=true - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here - SPRING_JPA_GENERATE_DDL=true + - SERVER_PORT=9998 depends_on: - mysql command: mvn clean spring-boot:run -DskipTests From b3269d62e2c3b059f98534e44113db7662276c5f Mon Sep 17 00:00:00 2001 From: yennanliu Date: Wed, 21 Feb 2024 22:20:50 +0800 Subject: [PATCH 06/13] fix conflict --- SpringDataPlatform/README.md | 13 +++++ SpringDataPlatform/docker-compose-m1.yml | 66 ++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 SpringDataPlatform/docker-compose-m1.yml diff --git a/SpringDataPlatform/README.md b/SpringDataPlatform/README.md index 49f2ca8a6..814cbc747 100644 --- a/SpringDataPlatform/README.md +++ b/SpringDataPlatform/README.md @@ -59,6 +59,19 @@ docker-compose up --build # restart docker-compose restart + +#-------------------------- +# Macbook m1 +#-------------------------- + +# run +docker-compose -f docker-compose-m1.yml up + +# rebuild (use updated java code) and run +docker-compose -f docker-compose-m1.yml up --build + +# restart +docker-compose -f docker-compose-m1.yml restart ``` diff --git a/SpringDataPlatform/docker-compose-m1.yml b/SpringDataPlatform/docker-compose-m1.yml new file mode 100644 index 000000000..a988348bb --- /dev/null +++ b/SpringDataPlatform/docker-compose-m1.yml @@ -0,0 +1,66 @@ +version: '3' +services: + app: + restart: always + build: ./backend/DataPlatform + working_dir: /app + volumes: + - ./backend/DataPlatform:/app + ports: + - "9999:9999" + platform: linux/amd64 + environment: + - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/data_platform + - SPRING_DATASOURCE_USERNAME=root + - SPRING_DATASOURCE_PASSWORD= + - SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver + - SPRING_JPA_SHOW_SQL=true + - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here + - SPRING_JPA_GENERATE_DDL=true + #- JAVA_HOME=/usr/local/openjdk-11 + depends_on: + - mysql + command: mvn clean spring-boot:run -DskipTests + + vue: + restart: always + build: ./frontend/data-platform-ui + working_dir: /app + platform: linux/amd64 + ports: + - "8080:8080" # Map host port 8080 to container port 8080 + volumes: + - ./frontend/data-platform-ui:/app # Mount the current directory into the container + command: npm run serve + + mysql: + image: mysql:5.7 + restart: always + platform: linux/amd64 + environment: + #https://stackoverflow.com/questions/66831863/mysql-docker-container-keeps-restarting + #MYSQL_USER: root # NO NEED to create root user, since it is created automatically + MYSQL_DATABASE: data_platform + MYSQL_ROOT_PASSWORD: + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + ports: + - "3306:3306" + volumes: + - mysql-data:/var/lib/mysql + + nginx: + image: nginx + restart: always + platform: linux/amd64 + ports: + #- "8080:80" + - "8081:8081" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/index.html:/app/html:ro + depends_on: + - app + #- app2 + +volumes: + mysql-data: \ No newline at end of file From b99560b3d793c48a9b114da92ebbef3b9972f2eb Mon Sep 17 00:00:00 2001 From: yennanliu Date: Sun, 18 Feb 2024 17:46:58 +0800 Subject: [PATCH 07/13] fix all FE app code use base_url --- SpringDataPlatform/frontend/data-platform-ui/src/App.vue | 2 +- .../frontend/data-platform-ui/src/views/Job/AddJob.vue | 3 ++- .../data-platform-ui/src/views/Zeppelin/AddNotebook.vue | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/SpringDataPlatform/frontend/data-platform-ui/src/App.vue b/SpringDataPlatform/frontend/data-platform-ui/src/App.vue index 0ec5b0580..6b7c35276 100644 --- a/SpringDataPlatform/frontend/data-platform-ui/src/App.vue +++ b/SpringDataPlatform/frontend/data-platform-ui/src/App.vue @@ -20,7 +20,7 @@ import Navbar from "./components/Navbar.vue"; export default { data() { return { - baseURL: "http://localhost:9999", + baseURL: "http://localhost:8081", //nginx port : 8081, BE port : 9999, 9998, "http://localhost:9999", users: null, departments: null, key: 0, diff --git a/SpringDataPlatform/frontend/data-platform-ui/src/views/Job/AddJob.vue b/SpringDataPlatform/frontend/data-platform-ui/src/views/Job/AddJob.vue index 727b0a5da..9aae84d18 100644 --- a/SpringDataPlatform/frontend/data-platform-ui/src/views/Job/AddJob.vue +++ b/SpringDataPlatform/frontend/data-platform-ui/src/views/Job/AddJob.vue @@ -72,7 +72,8 @@ export default { await axios({ method: "post", - url: "http://localhost:9999/" + "job/add", + //url: "http://localhost:9999/" + "job/add", + url: `${this.baseURL}/job/add`, data: JSON.stringify(newJob), headers: { "Content-Type": "application/json", diff --git a/SpringDataPlatform/frontend/data-platform-ui/src/views/Zeppelin/AddNotebook.vue b/SpringDataPlatform/frontend/data-platform-ui/src/views/Zeppelin/AddNotebook.vue index 0f779ae17..05a8e7ad3 100644 --- a/SpringDataPlatform/frontend/data-platform-ui/src/views/Zeppelin/AddNotebook.vue +++ b/SpringDataPlatform/frontend/data-platform-ui/src/views/Zeppelin/AddNotebook.vue @@ -87,7 +87,8 @@ export default { async getSchemas() { // fetch users await axios - .get("http://localhost:9999/schema/active/") + //.get("http://localhost:9999/schema/active/") + .get(`${this.baseURL}/schema/active/`) .then((res) => { this.schemas = res.data.filter((x) => x.schemaName === "interpreter"); console.log( From 71ec0641a3a8a2b182128179db79280c04a4f4bd Mon Sep 17 00:00:00 2001 From: yennanliu Date: Wed, 21 Feb 2024 22:00:06 +0800 Subject: [PATCH 08/13] make springBankApp/docker-compose.yml work --- springBank/springBankApp/docker-compose.yml | 42 +++++++++++++-------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/springBank/springBankApp/docker-compose.yml b/springBank/springBankApp/docker-compose.yml index 19ef4f7ec..2b2b3faaa 100644 --- a/springBank/springBankApp/docker-compose.yml +++ b/springBank/springBankApp/docker-compose.yml @@ -6,10 +6,9 @@ services: working_dir: /app volumes: - .:/app + - ~/.m2/repository:/root/.m2/repository # Mount Maven local repository ports: - "9999:9999" -# expose: -# - "9999" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/spring_bank - SPRING_DATASOURCE_USERNAME=root @@ -19,8 +18,12 @@ services: - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here - SPRING_JPA_GENERATE_DDL=true - SERVER_PORT=9999 + - SPRING_REDIS_HOST=redis # Set Redis host + - SPRING_REDIS_PORT=6379 + - REDIS_URL=redis://redis:6379 depends_on: - mysql + - redis command: mvn clean spring-boot:run -DskipTests app2: @@ -29,10 +32,9 @@ services: working_dir: /app volumes: - .:/app + - ~/.m2/repository:/root/.m2/repository # Mount Maven local repository ports: - "9998:9998" -# expose: -# - "9998" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/spring_bank - SPRING_DATASOURCE_USERNAME=root @@ -42,20 +44,25 @@ services: - SPRING_JPA_HIBERNATE_DDL_AUTO=create # Set the Hibernate ddl-auto property here - SPRING_JPA_GENERATE_DDL=true - SERVER_PORT=9998 + - SPRING_REDIS_HOST=redis # Set Redis host + - SPRING_REDIS_PORT=6379 + - REDIS_URL=redis://redis:6379 depends_on: - mysql + - redis command: mvn clean spring-boot:run -DskipTests - # nginx: - # image: nginx - # restart: always - # ports: - # - "8080:80" - # volumes: - # - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - # depends_on: - # - app1 - # - app2 + nginx: + image: nginx + restart: always + ports: + - "8080:8080" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/index.html:/app/html:ro + depends_on: + - app1 + - app2 mysql: image: mysql:5.7 @@ -68,6 +75,11 @@ services: - "3306:3306" volumes: - mysql-data:/var/lib/mysql + redis: + image: redis:latest + restart: always + ports: + - "6379:6379" # Expose Redis port volumes: - mysql-data: + mysql-data: \ No newline at end of file From 842eecb659fc5c4385860e483df727ef46af07ef Mon Sep 17 00:00:00 2001 From: yennanliu Date: Wed, 21 Feb 2024 22:19:43 +0800 Subject: [PATCH 09/13] fix, add endpoint, update readme --- springBank/README.md | 6 ++++++ .../yen/springBankApp/controller/BalanceController.java | 7 +++++++ .../yen/springBankApp/service/BalanceServiceRedisson.java | 2 ++ 3 files changed, 15 insertions(+) diff --git a/springBank/README.md b/springBank/README.md index 395a22458..dabb3a60a 100644 --- a/springBank/README.md +++ b/springBank/README.md @@ -119,6 +119,12 @@ docker-compose up # restart docker-compose restart +# run +docker-compose -f docker-compose.yml up + +# rebuild (use updated java code) and run +docker-compose -f docker-compose.yml up --build + #--------------------------- # Macbook apple M1 chip #--------------------------- diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java index 0257c934f..c7291f755 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java @@ -39,6 +39,13 @@ public ResponseEntity getDepartmentByUserId(@PathVariable("userId") Int return new ResponseEntity<>(balance, HttpStatus.OK); } + @GetMapping("/v1/{userId}") + public ResponseEntity getDepartmentByUserIdWithLock(@PathVariable("userId") Integer userId){ + + Balance balance = balanceServiceRedisson.getBalanceById(userId); + return new ResponseEntity<>(balance, HttpStatus.OK); + } + // @PostMapping("/update") // public ResponseEntity updateDepartment(@RequestBody DepartmentDto departmentDto) { // diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java index 9f31bc30a..d249200b9 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java @@ -37,6 +37,8 @@ public List getBalances() { public Balance getBalanceById(Integer id) { + System.out.println("(BalanceServiceRedisson) getBalanceById start ... Id = " + id); + Balance balance = new Balance(); // lock From f73c88b74e441b38dcfbb843951563d2e44f9c1b Mon Sep 17 00:00:00 2001 From: yennanliu Date: Wed, 21 Feb 2024 23:46:49 +0800 Subject: [PATCH 10/13] init rwLock in constructor, make methods using same rwLock, avoid dead lock --- .../service/BalanceServiceRedisson.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java index d249200b9..8d5d8de75 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java @@ -29,6 +29,13 @@ public class BalanceServiceRedisson { @Autowired private RedissonClient redissonClient; + private final RReadWriteLock rwLock; + + // constructor + public BalanceServiceRedisson(RedissonClient redissonClient) { + this.redissonClient = redissonClient; + this.rwLock = redissonClient.getReadWriteLock("rwLock"); + } public List getBalances() { @@ -42,8 +49,9 @@ public Balance getBalanceById(Integer id) { Balance balance = new Balance(); // lock - RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); - rwLock.readLock().lock(); +// RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); +// rwLock.readLock().lock(); + this.rwLock.readLock().lock(); try{ if (balanceRepository.findById(id).isPresent()){ return balanceRepository.findById(id).get(); @@ -53,7 +61,7 @@ public Balance getBalanceById(Integer id) { e.printStackTrace(); }finally { // unlock - rwLock.readLock().unlock(); + this.rwLock.readLock().unlock(); } return balance; } @@ -191,17 +199,17 @@ public void transferMysql(DeductBalanceDto deductBalanceDto) { // get lock //RLock lock = redissonClient.getLock("lock"); - RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); + //RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); // lock //lock.lock(); - rwLock.writeLock().lock(); + this.rwLock.writeLock().lock(); try{ // V2 : Mysql if (balanceRepository.findById(1).isPresent() && balanceRepository.findById(2).isPresent()){ - Thread.sleep(10000); + Thread.sleep(5000); // 5 sec // Balance balance1 = balanceRepository.findById(1).get(); // Balance balance2 = balanceRepository.findById(2).get(); @@ -222,7 +230,7 @@ public void transferMysql(DeductBalanceDto deductBalanceDto) { }finally { // unlock //lock.unlock(); - rwLock.writeLock().lock(); + this.rwLock.writeLock().unlock(); } } From 742f062f2e84c5af370c701f26c3fad2a93b199a Mon Sep 17 00:00:00 2001 From: yennanliu Date: Thu, 22 Feb 2024 18:21:59 +0800 Subject: [PATCH 11/13] split controller with lock, no lock, update BalanceServiceRedisson, add controller --- .../controller/BalanceController.java | 27 ++----- .../controller/BalanceControllerLock.java | 68 ++++++++++++++++ .../service/BalanceServiceRedisson.java | 77 +++++++++++++------ 3 files changed, 131 insertions(+), 41 deletions(-) create mode 100644 springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceControllerLock.java diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java index c7291f755..d370bd65d 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceController.java @@ -22,9 +22,6 @@ public class BalanceController { @Autowired private BalanceService balanceService; - @Autowired - private BalanceServiceRedisson balanceServiceRedisson; - @GetMapping("/") public ResponseEntity> getBalanceList(){ @@ -39,13 +36,6 @@ public ResponseEntity getDepartmentByUserId(@PathVariable("userId") Int return new ResponseEntity<>(balance, HttpStatus.OK); } - @GetMapping("/v1/{userId}") - public ResponseEntity getDepartmentByUserIdWithLock(@PathVariable("userId") Integer userId){ - - Balance balance = balanceServiceRedisson.getBalanceById(userId); - return new ResponseEntity<>(balance, HttpStatus.OK); - } - // @PostMapping("/update") // public ResponseEntity updateDepartment(@RequestBody DepartmentDto departmentDto) { // @@ -63,17 +53,16 @@ public ResponseEntity addBalance(@RequestBody AddBalanceDto addBala @PostMapping("/deduct") public ResponseEntity deductBalance(@RequestBody DeductBalanceDto deductBalanceDto){ - //balanceService.deductBalance(deductBalanceDto); - balanceServiceRedisson.deductBalance(deductBalanceDto); + balanceService.deductBalance(deductBalanceDto); return new ResponseEntity<>(new ApiResponse(true, "Balance has been deducted !!!"), HttpStatus.CREATED); } - @PostMapping("/transfer") - public ResponseEntity transfer(@RequestBody DeductBalanceDto deductBalanceDto){ - - //balanceServiceRedisson.transferRedis(deductBalanceDto); - balanceServiceRedisson.transferMysql(deductBalanceDto); - return new ResponseEntity<>(new ApiResponse(true, "Balance has been transferred !!!"), HttpStatus.CREATED); - } +// @PostMapping("/transfer") +// public ResponseEntity transfer(@RequestBody DeductBalanceDto deductBalanceDto){ +// +// //balanceServiceRedisson.transferRedis(deductBalanceDto); +// balanceService.transferMysql(deductBalanceDto); +// return new ResponseEntity<>(new ApiResponse(true, "Balance has been transferred !!!"), HttpStatus.CREATED); +// } } diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceControllerLock.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceControllerLock.java new file mode 100644 index 000000000..010c6663b --- /dev/null +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/controller/BalanceControllerLock.java @@ -0,0 +1,68 @@ +package com.yen.springBankApp.controller; + +import com.yen.springBankApp.common.ApiResponse; +import com.yen.springBankApp.model.dto.Balance.DeductBalanceDto; +import com.yen.springBankApp.service.BalanceServiceRedisson; +import lombok.extern.slf4j.Slf4j; +import com.yen.springBankApp.model.Balance; +import com.yen.springBankApp.model.dto.Balance.AddBalanceDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import com.yen.springBankApp.service.BalanceService; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/balance_lock") +public class BalanceControllerLock { + + @Autowired + private BalanceServiceRedisson balanceServiceRedisson; + + @GetMapping("/") + public ResponseEntity> getBalanceList(){ + + List balanceList = balanceServiceRedisson.getBalances(); + return new ResponseEntity<>(balanceList, HttpStatus.OK); + } + + @GetMapping("/{userId}") + public ResponseEntity getDepartmentByUserIdWithLock(@PathVariable("userId") Integer userId){ + + Balance balance = balanceServiceRedisson.getBalanceById(userId); + return new ResponseEntity<>(balance, HttpStatus.OK); + } + +// @PostMapping("/update") +// public ResponseEntity updateDepartment(@RequestBody DepartmentDto departmentDto) { +// +// departmentService.updateDepartment(departmentDto); +// return new ResponseEntity(new ApiResponse(true, "Department has been updated"), HttpStatus.OK); +// } + + @PostMapping("/add") + public ResponseEntity addBalance(@RequestBody AddBalanceDto addBalanceDto){ + + balanceServiceRedisson.addBalance(addBalanceDto); + return new ResponseEntity<>(new ApiResponse(true, "Balance has been added"), HttpStatus.CREATED); + } + + @PostMapping("/deduct") + public ResponseEntity deductBalance(@RequestBody DeductBalanceDto deductBalanceDto){ + + balanceServiceRedisson.deductBalance(deductBalanceDto); + return new ResponseEntity<>(new ApiResponse(true, "Balance has been deducted !!!"), HttpStatus.CREATED); + } + + @PostMapping("/transfer") + public ResponseEntity transfer(@RequestBody DeductBalanceDto deductBalanceDto){ + + //balanceServiceRedisson.transferRedis(deductBalanceDto); + balanceServiceRedisson.transferMysql(deductBalanceDto); + return new ResponseEntity<>(new ApiResponse(true, "Balance has been transferred !!!"), HttpStatus.CREATED); + } + +} diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java index 8d5d8de75..145557511 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java @@ -39,7 +39,17 @@ public BalanceServiceRedisson(RedissonClient redissonClient) { public List getBalances() { - return balanceRepository.findAll(); + System.out.println("(BalanceServiceRedisson) getBalances"); + // lock + this.rwLock.readLock().lock(); + try{ + return balanceRepository.findAll(); + }catch (Exception e){ + e.printStackTrace(); + }finally { + this.rwLock.readLock().unlock(); + } + return null; // return default val ? } public Balance getBalanceById(Integer id) { @@ -68,30 +78,49 @@ public Balance getBalanceById(Integer id) { public Balance getBalanceByUserId(Integer userId) { - List balanceList = balanceRepository.findAll(); - return balanceList.stream().filter(x -> {return x.getUserId().equals(userId);} - ).collect(Collectors.toList()).get(0); + // lock + this.rwLock.readLock().lock(); + try{ + List balanceList = balanceRepository.findAll(); + return balanceList.stream().filter(x -> {return x.getUserId().equals(userId);} + ).collect(Collectors.toList()).get(0); + }catch (Exception e){ + e.printStackTrace(); + }finally { + // unlock + this.rwLock.readLock().unlock(); + } + return null; } public void addBalance(AddBalanceDto addBalanceDto) { - - Balance balance = new Balance(); - balance.setUserId(addBalanceDto.getUserId()); - balance.setBalance(addBalanceDto.getAmount()); - balance.setCreateTime(new Date()); - balance.setUpdateTime(new Date()); - balanceRepository.save(balance); + // lock + this.rwLock.readLock().lock(); + try{ + Balance balance = new Balance(); + balance.setUserId(addBalanceDto.getUserId()); + balance.setBalance(addBalanceDto.getAmount()); + balance.setCreateTime(new Date()); + balance.setUpdateTime(new Date()); + balanceRepository.save(balance); + }catch (Exception e){ + e.printStackTrace(); + }finally { + // unlock + this.rwLock.readLock().unlock(); + } } public void topUpBalance(){ log.info(">>> (BalanceServiceRedisson) topUpBalance start ..."); - - // get lock - RLock lock = redissonClient.getLock("lock"); +// // get lock +// RLock lock = redissonClient.getLock("lock"); +// // lock +// lock.lock(); // lock - lock.lock(); + this.rwLock.writeLock().lock(); try{ // V2 : Mysql @@ -107,7 +136,7 @@ public void topUpBalance(){ e.printStackTrace(); }finally { // unlock - lock.unlock(); + this.rwLock.writeLock().unlock(); } } @@ -115,13 +144,16 @@ public void deductBalance(DeductBalanceDto deductBalanceDto) { log.info(">>> (BalanceServiceRedisson) deductBalance start ..."); - // get lock - //RLock lock = redissonClient.getLock("lock"); - RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); +// // get lock +// //RLock lock = redissonClient.getLock("lock"); +// RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); +// +// // lock +// //lock.lock(); +// rwLock.writeLock(); // lock - //lock.lock(); - rwLock.writeLock(); + this.rwLock.writeLock().lock(); try{ // sleep 10 sec @@ -149,7 +181,8 @@ public void deductBalance(DeductBalanceDto deductBalanceDto) { }finally { // unlock //lock.unlock(); - rwLock.writeLock().unlock(); + //rwLock.writeLock().unlock(); + this.rwLock.writeLock().unlock(); } } From adb6ce1a23536890b3044356acfe6dcb8a560fbc Mon Sep 17 00:00:00 2001 From: yennanliu Date: Thu, 22 Feb 2024 18:37:15 +0800 Subject: [PATCH 12/13] add lock timeout, add comment --- .../yen/springBankApp/service/BalanceServiceRedisson.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java index 145557511..37bd65e93 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java @@ -14,6 +14,7 @@ import java.util.Date; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @@ -41,7 +42,7 @@ public List getBalances() { System.out.println("(BalanceServiceRedisson) getBalances"); // lock - this.rwLock.readLock().lock(); + this.rwLock.readLock().lock(3, TimeUnit.SECONDS); // default expire time : 3 sec try{ return balanceRepository.findAll(); }catch (Exception e){ @@ -52,6 +53,10 @@ public List getBalances() { return null; // return default val ? } + + // retry if process can't get lock (? + // https://medium.com/@htyesilyurt/distributed-lock-with-redisson-rlock-and-spring-boot-redis-pub-sub-86d51fd83e8b + //@Retryable(value = org.redisson.client.RedisTimeoutException.class, maxAttempts = 2, backoff = @Backoff(delay = 2000)) public Balance getBalanceById(Integer id) { System.out.println("(BalanceServiceRedisson) getBalanceById start ... Id = " + id); From 835569aa645c4ecd49d91442909d7714f9614508 Mon Sep 17 00:00:00 2001 From: yennanliu Date: Thu, 22 Feb 2024 18:45:53 +0800 Subject: [PATCH 13/13] backup code --- .../service/BalanceServiceRedisson.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java index 37bd65e93..49c8ae86f 100644 --- a/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java +++ b/springBank/springBankApp/src/main/java/com/yen/springBankApp/service/BalanceServiceRedisson.java @@ -4,6 +4,7 @@ import com.yen.springBankApp.model.dto.Balance.AddBalanceDto; import com.yen.springBankApp.model.dto.Balance.DeductBalanceDto; import com.yen.springBankApp.repository.BalanceRepository; +import io.swagger.models.auth.In; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RReadWriteLock; @@ -13,7 +14,10 @@ import org.springframework.stereotype.Service; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -32,10 +36,14 @@ public class BalanceServiceRedisson { private final RReadWriteLock rwLock; + // lock for id level + private final Map rwlocks; + // constructor public BalanceServiceRedisson(RedissonClient redissonClient) { this.redissonClient = redissonClient; this.rwLock = redissonClient.getReadWriteLock("rwLock"); + this.rwlocks = new ConcurrentHashMap<>(); } public List getBalances() { @@ -64,9 +72,13 @@ public Balance getBalanceById(Integer id) { Balance balance = new Balance(); // lock + // lock with id level, TODO : validate if it works +// RLock lock = rwlocks.computeIfAbsent(id, k -> redissonClient.getLock("lock-" + k)); +// lock.lock(); // RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); // rwLock.readLock().lock(); this.rwLock.readLock().lock(); + try{ if (balanceRepository.findById(id).isPresent()){ return balanceRepository.findById(id).get(); @@ -235,11 +247,22 @@ public void transferMysql(DeductBalanceDto deductBalanceDto) { log.info(">>> (BalanceServiceRedisson) transferMysql start ..."); - // get lock - //RLock lock = redissonClient.getLock("lock"); - //RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock"); +// // lock +// this.rwlocks.computeIfAbsent(1, k -> redissonClient.getLock("lock-" + k)); +// this.rwlocks.computeIfAbsent(2, k -> redissonClient.getLock("lock-" + k)); +// if (lock1.tryLock() && lock2.tryLock()) { +// try { +// // Your transfer logic here +// } catch (Exception e) { +// e.printStackTrace(); +// } finally { +// lock2.unlock(); +// lock1.unlock(); +// } +// } else { +// // Handle if locks cannot be acquired +// } - // lock //lock.lock(); this.rwLock.writeLock().lock();