2024年12月30日 星期一

海科面試問題

 1 關於 java中的spring 有ioc和aop可以介紹一下分別是在做什麼嗎?

在Java的Spring框架中,IoC(控制反轉)和AOP(面向切面編程)是兩個非常重要的概念。

1. IoC(控制反轉)

IoC是一種設計模式,主要用於改進代碼的可維護性和可測試性。在IoC中,對象的創建和管理脫離了外部組件的控制,而是由Spring容器來進行管理。這意味著對象的依賴關係(例如,依賴於其他對象的服務)不再由對象自己負責,而是由IoC容器在運行時動態注入。

這樣的好處包括:

  • 減少了代碼的耦合度。
  • 使得測試更容易,可以使用Mock對象來替代真實對象。
  • 促進了代碼的可重用性和清晰性。

2. AOP(面向切面編程)

AOP是一種程序設計範式,用於分離橫切關注點(cross-cutting concerns),例如日誌記錄、性能監控和安全控制等。這些功能通常跨越多個類,而在每個類中重複實現會導致代碼複雜性。

在Spring中,AOP允許你定義“切面”(aspect),這是由一系列的“通知”(advice)和“切入點”(pointcuts)組成的。通知是實際要執行的行為,切入點則是一組條件,用於指定哪些方法應該被通知影響。

AOP的好處包括:

  • 提高代碼的模塊化,將橫切關注點與業務邏輯分離。
  • 使得代碼更清晰易讀。
  • 方便在需要時添加或修改功能,而不需要改變核心業務邏輯。

總結來說,IoC專注於對象的創建和管理,而AOP則專注於橫切關注點的處理。這兩者共同協作,可以讓你的應用程序更加靈活和可維護。


2那關於IOC中, DI是指什麼, 有什麼用處?


在IoC(控制反轉)中,DI指的是依賴注入(Dependency Injection)。這是一種設計模式,旨在實現對象及其依賴之間的解耦。

依賴注入(DI)的概念

依賴注入的核心思想是將對象所需的依賴(其他對象)由外部注入,而不是由該對象自己創建或查找依賴。這通常通過以下三種方式來實現:

  1. 構造函數注入通過類的構造函數傳遞需要的依賴。
  2. Setter方法注入通過setter方法來注入依賴。
  3. 接口注入通過實現某個接口來獲取依賴(這種方式相對少見)。

依賴注入的用處

  1. 降低耦合度:由於對象不再直接創建其依賴,它們變得更獨立,這使得系統的各個部分之間的耦合度降低。

  2. 提高可測試性:在測試中,可以通過注入mock或stub對象來替代真實的依賴,從而簡化單元測試的過程。

  3. 促進代碼重用:當對象及其依賴都能相對獨立時,將更容易重複使用這些對象。

  4. 簡化配置管理:通過使用IoC容器來管理依賴,可以減少手動配置這些依賴的方法,並且讓它們集中管理,便於維護。

  5. 靈活性:可以在運行時輕鬆替換依賴,以滿足不同的需求,這對於高可擴展性且變化頻繁的項目非常有用。

總結來說,依賴注入作為IoC的一部分,幫助實現碼的模塊化和靈活性,同時也提升了測試的便利性和可靠性。


3 spring如何解決循環依賴問題, 為什麼autowired不會因循環依賴產生問題?


在Spring框架中,循環依賴(Circular Dependency)問題指的是兩個或多個bean相互依賴,形成一種循環關係。Spring通過不同的方式來解決這個問題,尤其是在使用Autowired進行依賴注入時。

Spring解決循環依賴的方法

  1. 使用暫時的代理對象

    • Spring使用的主要方法是建立一個“暫時的代理”對象,這是一個不完整的bean引用,當一個bean在創建的過程中遇到另一個依賴時,Spring能夠立即返回這個代理對象,而不是等待完整的對象創建完成。這樣,即使存在循環依賴,至少還可以提供一個參考來完成bean的注入。
  2. 構造器依賴注入的限制

    • 當使用構造器注入時,如果存在循環依賴,Spring容器在創建bean時會無法完成整個對象的創建,因此會拋出 BeanCurrentlyInCreationException。這意味著循環依賴在構造器注入中無法解決,因此通常推薦使用setter方法注入。
  3. 使用@Lazy註解

    • Spring提供了 @Lazy 注解,可以在依賴注入中延遲加載。當一個bean使用 @Lazy 注解時,它不會在應用啟動時立即創建,而是在首次用到這個bean時才創建。這在一定程度上可以緩解循環依賴問題。

為什麼@Autowired不會因循環依賴產生問題?

使用@Autowired進行依賴注入時,當Spring容器處理bean的創建時,對於需要的依賴,Spring可以首先創建該bean的代理對象,然後再進行依賴的注入。這意味著,即使某些bean在創建時互相依賴,只要不是在構造函數中直接依賴,Spring仍然能夠解決這個問題。

例如:

  • 假設有兩個類 A 和 B,它們互相依賴:

@Component
public class A {
    @Autowired
    private B b; // A 依賴於 B
}

@Component
public class B {
    @Autowired
    private A a; // B 依賴於 A
}

在這種情況下,Spring首先會創建 A 的代理對象,在注入 B 時,又會創建 B 的代理對象。由於這是一種基於接口的依賴,因此可以在建構過程中解決這種循環關係。

總結來說,Spring利用了代理機制和懶加載的特性來優雅地解決循環依賴問題,使得使用@Autowired的依賴注入不會產生困擾。


4 關於spring @Transactional的預設機制及有幾種機制?



在Spring中,@Transactional 用於管理事務,提供了一種簡單而靈活的方式來開發具有事務控制的應用。使用 @Transactional 標註的類或方法可以自動處理事務的開始、提交和回滾。

預設機制

當你在類或方法上使用 @Transactional 註解時,Spring的事務管理器會在該方法被調用時自動處理以下步驟:

  1. 開始事務:當方法被調用時,Spring會啟動一個新的事務。
  2. 執行方法:調用被標註的方法並執行其業務邏輯。
  3. 提交或回滾
    • 如果方法正常完成(即沒有拋出受檢異常),則提交該事務。
    • 如果方法拋出運行時異常(如 RuntimeException)或是 Error,則回滾該事務。
    • 如果拋出受檢異常(如 SQLException),則可以根據配置選擇回滾或提交。

事務傳播機制

Spring提供了多種事務傳播行為來控制事務的邊界和行為,共有以下幾種常用的傳播機制:

  1. REQUIRED(預設)

    • 如果已經有事務在運行,則加入該事務;如果沒有,則創建一個新的事務。
  2. REQUIRES_NEW

    • 無論是否已有事務,總是創建一個新的事務。如果有現有事務,則會暫停它。
  3. NESTED

    • 如果已有事務,則這個方法會在一個嵌套事務中運行。如果沒有事務,則類似於 REQUIRED
  4. SUPPORTS

    • 如果有事務在運行,就加入該事務;否則在無事務的狀況下正常執行。
  5. NOT_SUPPORTED

    • 總是以非事務方式執行,若已經有事務,則會暫停它。
  6. NEVER

    • 總是以非事務方式執行,如果已經有事務,則會拋出異常。
  7. MANDATORY

    • 如果已有事務,則只在該事務中運行;如果沒有,則拋出異常。

其他設定

除了傳播機制,@Transactional 還有其他一些配置選項,例如:

  • 隔離級別:定義不同事務之間的隔離級別。
  • 超時:指定事務最大執行時間。
  • 只讀事務:標記該事務為只讀,以優化性能。
  • 回滾規則:定義哪些異常應該導致事務回滾。

總結來說,@Transactional 在Spring中是一個強大的註解,允許開發者以簡單的方式控制事務的行為,並且提供各種機制來應對不同的事務場景。


5關於spring data JPA, 是否有遇到save但是沒存入資料庫的問題, 要如何解決這問題?

在使用 Spring Data JPA 時,發生 save 方法未將資料存入資料庫的問題可能由多種原因造成。以下是一些可能的原因及其解決方案:

1. 事務未正確管理

  • 問題:如果 @Transactional 註解沒有正確使用,可能會導致資料未能提交到資料庫。
  • 解決方案:確保在調用 save 方法的服務層方法上標註 @Transactional。例如:
@Service
public class YourService {
    @Autowired
    private YourRepository repository;

    @Transactional
    public void saveEntity(YourEntity entity) {
        repository.save(entity);
    }
}

2. 錯誤的 Entity 狀態

  • 問題:若要保存的實體(Entity)未被正確設置狀態(如主鍵未設置),可能導致 save 方法不起作用。
  • 解決方案:確保實體的主鍵在進行保存前已正確設置,且所有必要的字段皆已填寫。

3. 資料庫約束問題

  • 問題:當您嘗試儲存的資料違反資料庫約束(如唯一性約束、外鍵約束等)時,可能會導致保存失敗。
  • 解決方案:檢查資料庫的約束條件,確保保存的資料不會違反這些約束。此外,可以通過捕捉異常來獲取具體錯誤信息。
try {
    repository.save(entity);
} catch (DataIntegrityViolationException e) {
    // 處理符合約束條件錯誤的情況
}

4. 資料庫連接問題

  • 問題:若資料庫offline或連接配置錯誤,則資料不能成功保存。
  • 解決方案:檢查資料庫服務是否運行,以及您在 application.properties 或 application.yml 中的資料庫連接配置是否正確。

5. 使用了錯誤的 Repository

  • 問題:如果意外使用了錯誤的 Repository 進行資料操作,可能會導致資料未存入預期的資料表。
  • 解決方案:確認您正在使用的 Repository 是正確對應於所需的實體。

6. Entity 沒有被 managed

  • 問題:如果實體不是由 EntityManager 管理,則 save 不會生效。
  • 解決方案:確保實體是從持久上下文中獲得並且已被持久化。

偵錯建議

  • Log:在執行保存操作時加上日誌,記錄保存前後的資訊,以便於檢查問題。
  • DataSource Configuration:通過配置等級或顯示SQL查詢來查看是否有進行真正的插入操作。

若檢查以上項目後問題仍未解決,可以查看資料庫日誌,或增加更多的日誌輸出以獲取詳細的失敗原因。


6在使用java Threadpool 的時候, 如果每次都去取Thread是否會被取完而造成沒有Thread可以使用? 如何在使用完時關閉Thread?


在Java中,使用線程池(如 ExecutorService)時,線程池會管理一組線程以供重覆使用。這種方式減少了每次創建和銷毀線程的開銷,提高了性能。但你提到的情況,如果線程池中的線程被“取完”,就可能會導致沒有可用的線程來處理新的任務。這與線程池的大小、任務的執行時間以及提交任務的速率等多個因素有關。 1. 線程池的大小 線程池通常會設定一個最大線程數(maximumPoolSize)。當線程池中的線程達到這個最大值,並且隊列(BlockingQueue)在處理新任務時沒有空閒線程可用,就會發生任務被阻塞,直到有線程完成其任務並返回池中。 如何處理:你可以根據應用的需求調整線程池的大小。在創建線程池時,可以使用 Executors.newFixedThreadPool(int nThreads) 或 ThreadPoolExecutor 來設置核心線程數和最大線程數。 2. 關閉線程池 在使用完線程池後,建議關閉線程池以釋放資源。ExecutorService 提供了兩種關閉方式: shutdown():會停止接收新任務,並等待已提交的任務完成執行。這是一種優雅的關閉方式。 java executorService.shutdown(); shutdownNow():會試圖停止所有正在執行的任務,並返回未執行的任務。它是一種強制的關閉方式。 java List<Runnable> pendingTasks = executorService.shutdownNow(); 示例 以下是一個簡單的示例,展示如何使用線程池、提交任務並在使用完池後關閉它:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交一些任务
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executorService.submit(() -> {
                System.out.println("Executing task " + taskId);
                try {
                    // 模拟任务处理时间
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭线程池
        executorService.shutdown();
        try {
            // 等待所有任务完成
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                executorService.shutdownNow(); // 强制关闭
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
            Thread.currentThread().interrupt(); // 恢复中断状态
        }
    }
}

總結 線程池會管理一定數量的線程允許並發執行任務,而不是每次都創建新線程。 任務將在達到最大線程數時被阻塞,直到有線程完成。 在使用完線程池後,務必通過 shutdown() 或 shutdownNow() 方法來關閉它,以便釋放資源。 通過合理配置線程池的大小以及妥善管理其生命周期,可以有效避免線程不足的問題。

2024年10月31日 星期四

invalid packging for parent POM com.xxxxxx:1.0SNAPSHOT must be "pom" but is "jar"

 出現在專案上面冒紅線, 並有紅字invalid packing......



在本專案的原因是, 這裡有母子專案

有在子專案pom檔中聲明parent

<parent>
<artifactId>heima-leadnews-test</artifactId>
<groupId>com.heima</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

但是母專案pom檔中漏掉

<modules>
<module>freemarker-demo</module>
<module>minio-demo</module>
</modules>

補上後刷新maven就解決了

2024年10月28日 星期一

docker安裝nacos

 使用docker拉取鏡像

        docker pull nacos/nacos-server:1.2.0

創建容器

docker run --env MODE=standalone --name nacos --restart=always -d -p 8848:8848 nacos/nacos-server:1.2.0


MODE=standalone 單機版

--restart=always 開機啟動

-p 8848:8848 映射端口

-d 創建一個守護式容器在後台運行


查看容器
docker images 

查看日誌
docker logs -f 0506d2631165

跳出
ctrl+c



2024年10月25日 星期五

2024年7月4日 星期四

侑城一家第一次吃飯

今天被侑城夫婦邀請吃飯, 他們還約了區裡的弟兄姊妹來

算是年輕人的一區

大約三個感想

1 其中一位弟兄分享大學時母親過世後, 後來因為參加聚會, 學校生活才慢慢走上正常的道路, 我的感受是, 其實這個弟兄有個broken heart, 那時候接觸信仰, 的確部份轉移了他對於母親過世的悲傷思維, 反而使他後面能正常過生活

2 其中一個弟兄有老婆, 有兩個小孩, 看起來很平平淡淡, 但是我以為是一級戰場, 會過得很辛苦, 但是他看起來的確不是特別操勞或花力氣, 平靜而有力量, 我是覺得, 連我上班都很操, 這個人有個家還有小孩, 能運作的樣貌, 能像這個樣子, 他可能成功的運作是值得學習, 或者他有些不同的價值觀

3 回家路上想到羅得&他妻子的畫面, 他就漸漸搬移帳篷, 搬到所多瑪, 然後習慣各種罪惡而不覺得有什麼特別, 而我也很像這個樣子, 我住在林森北旁邊, 時常看到這些, 也融入這些, 難道偏要等到神審判告知來到, 然後接受一切不能回頭的結局嗎? 這是跟我有準備想要買房子有關, 如果生活圈都是這些, 或是就是過這些生活, 假設真有終局, 我的結局也會因我的決定而定, 若是早知道能避開這些, 羅得當初應該搬回去和亞伯拉罕一起住

小結

神用了一些你不知道的方式保全or save那些人, 那些你所認為的不working, 有些方面是有在working, 也或著以你不知道的方式working

兩個角度解讀自己認為神沒有幫我預備

1 當初在的就是在年長區, 要結婚很難working, 其實就應該換區

2 如果30歲結婚, 相對來說有些事情還沒學習, 直接結婚會人生爆炸

2024年6月26日 星期三

事務優化及一種事務失效的改正

內容來自學成在線的媒資管理事務優化

目前的邏輯是方法uploadFile中包含兩個動作

1 將文件上傳到minio

2 將文件信息存儲到資料庫

原本是整個方法上加@transactional

但是1的這部分, 你並不能保證上傳的時間會有多長

以至於說整個方法如果綁transactional會導致占用資料庫資源

現在有個想法, 打算只在2的步驟上加入transactional

然後在2的程式碼中加入會報錯的程式碼, 看看是否會回滾



部分程式碼



  //將文件上傳到minio
  boolean result = addMediaFilesToMinIO(localFilePath, mimeType, bucket_files, objectName);
  if(!result)XueChengPlusException.cast("上傳文件失敗");
  //文件大小
  uploadFileParamsDto.setFileSize(file.length());
  //將文件信息存儲到數據庫
  MediaFiles mediaFiles = addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);
  if(mediaFiles==null)XueChengPlusException.cast("上傳後保存文件信息失敗");

方法片段



@Transactional
 public MediaFiles addMediaFilesToDb(Long companyId, String fileMd5, UploadFileParamsDto uploadFileParamsDto, String bucket, String objectName) {
  //從數據庫查詢文件
  MediaFiles mediaFiles = mediaFilesMapper.selectById(fileMd5);
  if (mediaFiles == null) {
   mediaFiles = new MediaFiles();
   //拷貝基本信息
   BeanUtils.copyProperties(uploadFileParamsDto, mediaFiles);
   mediaFiles.setId(fileMd5);
   mediaFiles.setFileId(fileMd5);
   mediaFiles.setCompanyId(companyId);
   mediaFiles.setUrl("/" + bucket + "/" + objectName);
   mediaFiles.setBucket(bucket);
   mediaFiles.setFilePath(objectName);
   mediaFiles.setCreateDate(LocalDateTime.now());
   mediaFiles.setAuditStatus("002003");
   mediaFiles.setStatus("1");
   //保存文件信息到文件表
   int insert = mediaFilesMapper.insert(mediaFiles);
   int a=1/0;
   if (insert <=0) {
    log.error("保存文件信息到數據庫失敗,{}", mediaFiles.toString());
    XueChengPlusException.cast("保存文件信息失敗");
   }
   log.debug("保存文件信息到數據庫成功,{}", mediaFiles.toString());

  }
  return mediaFiles;

 }

這時發現雖然會報錯誤, 但是事務沒有回滾, 事務失效




簡單敘述目前狀況

就是controller調用service時, 第一層是調代理對象的方法

但是方法中再調用其他方法, 則會是原對象方法, 如下圖

這裡有個技巧, 可以在方法調service中的方法前加上this.用debug斷點去看this就會發現並非proxy

而這不滿足事務的兩個要求

1 需要是代理對象調方法

2 在調的方法上加@Transactional註解

因為要求沒滿足, 事務沒法生效

課程提供一個解法

就是將當前類再注入進來, 使其變成代理對象

步驟

1 注入本service作為代理對象


@Autowired
MediaFileService currentProxy;

2 將需要事務管理的方法提成接口


public MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,UploadFileParamsDto uploadFileParamsDto,String bucket,String objectName);

3 調用代理對象call方法


//寫入文件表
MediaFiles mediaFiles = currentProxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);



2024年6月7日 星期五

課程了解

尚品甄選

有包含架Harbor操作


udemy上搜尋large scale system可以找到kubernetes架構的專案教學


感覺可以看一下

黑馬頭條

裡面有spring cloud elasticSearch redis docker kafka


瑞吉外賣

有示範數據庫讀寫分離 linux安裝教學


閃聚支付

有示範分庫分表Sharding-JDBC 對交易服務進行分庫分表 分片鍵 插入數據根據商戶id決定要入哪個庫 短信驗證使用騰訊雲 上傳資質證件使用七牛雲


蒼窮外賣

有用到websocket

海科面試問題

 1 關於 java中的spring 有ioc和aop可以介紹一下分別是在做什麼嗎? 在Java的Spring框架中,IoC(控制反轉)和AOP(面向切面編程)是兩個非常重要的概念。 1. IoC(控制反轉) IoC是一種設計模式,主要用於改進代碼的可維護性和可測試性。在IoC中...