Việc làm

28/09 · Hồ Chí Minh · Tại văn phòng

Trưởng phòng Kỹ thuật JAVA (OMICall VoIP & AI)

VIHAT Technology · Software/Technical Architect

Xem mô tả & ứng tuyển trên ITviecMô tả công việc, lương và ứng tuyển nằm ở ITviec.

10 câu hỏi có thể gặp khi phỏng vấn

Chọn theo kỹ năng và cấp của tin (Java, AI / Machine Learning, SQL & Database). Gợi ý trả lời do Drama Công Ty biên soạn để bạn ôn nhanh, không phải đề của công ty.

  1. 01Dependency Injection trong Spring là gì? Vì sao nên dùng constructor injection thay cho @Autowired trên field?Java

    Gợi ý trả lời

    IoC container của Spring tạo và quản lý các bean, rồi "tiêm" phụ thuộc vào class cần dùng, thay vì class tự new. Nhờ vậy code ít phụ thuộc cứng, dễ thay implementation và dễ test.

    Constructor injection được khuyên dùng vì:

    • Field có thể là final, object luôn ở trạng thái đầy đủ sau khi tạo.
    • Test unit không cần Spring: chỉ cần new OrderService(mockRepo).
    • Constructor quá nhiều tham số là dấu hiệu class đang ôm nhiều việc.
    • Class chỉ có một constructor thì không cần ghi @Autowired.

    Nên nói thêm về scope: mặc định bean là singleton (một instance cho cả context), ngoài ra có prototype, request, session.

    Hay sai: để state thay đổi được (ví dụ biến đếm, list) trong bean singleton. Nhiều request chạy song song sẽ dùng chung và gây race condition.

    Ôn thêm câu hỏi Java →
  2. 02@Transactional hoạt động thế nào? Vì sao có lúc gắn annotation rồi mà transaction không chạy?Java

    Gợi ý trả lời

    Spring tạo proxy bao quanh bean. Khi gọi method có @Transactional qua proxy, proxy mở transaction, gọi method thật, rồi commit hoặc rollback.

    Những lý do hay gặp khiến nó "không ăn":

    • Self-invocation: method A trong cùng class gọi this.b() có @Transactional, lời gọi không đi qua proxy.
    • Method là private hoặc final: proxy không chặn được lời gọi.
    • Mặc định chỉ rollback với unchecked exception và Error. Checked exception vẫn commit, trừ khi khai báo rollbackFor = Exception.class.
    • Exception bị catch và nuốt bên trong method.

    Nên biết thêm propagation (REQUIRED, REQUIRES_NEW) và readOnly = true cho các truy vấn chỉ đọc.

    Người phỏng vấn muốn nghe: bạn giải thích được bằng cơ chế proxy, không chỉ liệt kê lỗi.

    Ôn thêm câu hỏi Java →
  3. 03Lỗi N+1 query trong JPA/Hibernate là gì và xử lý ra sao?Java

    Gợi ý trả lời

    N+1 xảy ra khi bạn lấy N bản ghi bằng 1 query, rồi mỗi lần truy cập quan hệ lazy lại phát sinh thêm 1 query. Ví dụ lấy 100 đơn hàng, rồi gọi order.getCustomer() trong vòng lặp là thành 101 query.

    Cách xử lý:

    • JOIN FETCH trong JPQL: select o from Order o join fetch o.customer.
    • @EntityGraph(attributePaths = "customer") trên method của repository.
    • @BatchSize hoặc hibernate.default_batch_fetch_size để gom lazy load thành câu IN (...).
    • Với màn hình chỉ đọc, trả thẳng DTO projection thay vì entity.

    Phát hiện bằng cách bật log SQL (spring.jpa.show-sql hoặc log của Hibernate) khi dev, hoặc dùng thống kê của Hibernate.

    Hay sai: đổi sang FetchType.EAGER cho xong. Cách này chỉ đổi chỗ lỗi và làm mọi truy vấn khác nặng hơn. Fetch join nhiều collection cùng lúc cũng dễ gây tích Descartes.

    Ôn thêm câu hỏi Java →
  4. 04Khi nào bạn chọn prompt engineering, RAG hay fine-tuning?AI / Machine Learning

    Gợi ý trả lời

    Bắt đầu từ cách rẻ và nhanh nhất, chỉ nâng cấp khi đo được là chưa đủ.

    • Prompting: thử đầu tiên; chỉ dẫn rõ, ví dụ mẫu (few-shot), định dạng đầu ra có cấu trúc.
    • RAG: khi mô hình thiếu kiến thức (tài liệu nội bộ, dữ liệu thay đổi thường xuyên), cần trích dẫn nguồn.
    • Fine-tuning: khi cần đổi hành vi ổn định (văn phong, định dạng, tác vụ hẹp lặp lại), hoặc muốn dùng mô hình nhỏ rẻ hơn thay mô hình lớn. Kỹ thuật như LoRA giảm chi phí.

    Fine-tuning không phải cách tốt để nhồi kiến thức mới hay thay đổi liên tục; RAG hợp hơn.

    Người phỏng vấn muốn nghe: có bộ đánh giá trước để so sánh các phương án bằng số liệu.

    Ôn thêm câu hỏi AI / Machine Learning →
  5. 05Hallucination của LLM là gì? Bạn giảm thiểu nó trong sản phẩm thế nào?AI / Machine Learning

    Gợi ý trả lời

    Hallucination là khi mô hình sinh ra nội dung nghe hợp lý nhưng sai hoặc không có căn cứ. Không loại bỏ hoàn toàn được, chỉ giảm và kiểm soát.

    • Cung cấp ngữ cảnh đúng qua RAG, yêu cầu chỉ trả lời dựa trên nguồn và trích dẫn.
    • Cho phép và khuyến khích trả lời "không đủ thông tin".
    • Dùng đầu ra có cấu trúc (JSON schema) và kiểm tra hợp lệ bằng code.
    • Với số liệu, tra cứu hoặc tính toán qua tool/API thay vì để mô hình tự nhớ.
    • Kiểm tra sau sinh: đối chiếu câu trả lời với nguồn.
    • Thiết kế UX hiển thị nguồn; tác vụ rủi ro cao có người duyệt.

    Người phỏng vấn muốn nghe: đo tỷ lệ hallucination bằng bộ đánh giá, không chỉ dựa vào cảm giác.

    Ôn thêm câu hỏi AI / Machine Learning →
  6. 06Một API chạy chậm, nghi do query. Bạn điều tra và tối ưu thế nào?SQL & Database

    Gợi ý trả lời

    Đo trước rồi mới sửa: tìm đúng query chậm, đọc execution plan, rồi chỉnh index hoặc cách viết query.

    1. Bật slow query log (MySQL) hoặc pg_stat_statements (PostgreSQL) để biết query nào tốn thời gian nhất.
    2. Chạy EXPLAIN (PostgreSQL nên dùng EXPLAIN (ANALYZE, BUFFERS)) xem có full scan, ước lượng số dòng lệch nhiều so với thực tế, sort trên đĩa không.
    3. Sửa theo nguyên nhân: thêm hoặc đổi composite index, bỏ hàm bọc cột, chỉ SELECT cột cần, phân trang bằng keyset thay cho OFFSET lớn.
    4. Kiểm tra phía ứng dụng: lỗi N+1 query, thiếu connection pool, lock chờ lâu.
    5. Cập nhật thống kê (ANALYZE) nếu planner ước lượng sai.

    Người phỏng vấn muốn nghe: quy trình có số liệu trước/sau, không phải đoán rồi thêm index bừa.

    Ôn thêm câu hỏi SQL & Database →
  7. 07Bộ nhớ JVM gồm những vùng nào? Garbage Collector hoạt động ra sao và Java có bị memory leak không?Java

    Gợi ý trả lời

    Hai vùng chính: stack (mỗi thread một stack, chứa biến cục bộ và tham chiếu) và heap (chứa object, dùng chung). Ngoài ra có Metaspace chứa thông tin class.

    • GC tìm các object không còn được tham chiếu từ "GC roots" (biến trên stack, field static...) và thu hồi.
    • Heap chia theo thế hệ: object mới nằm ở young generation, sống lâu thì được chuyển lên old generation.
    • G1 là GC mặc định; ZGC hợp khi cần pause rất ngắn với heap lớn.

    Java vẫn leak khi object không dùng nữa mà vẫn còn tham chiếu:

    • Cache hoặc static Map chỉ thêm, không bao giờ xoá.
    • ThreadLocal không remove() trong thread pool.
    • Listener đăng ký mà không huỷ.

    Người phỏng vấn muốn nghe: phân biệt được OutOfMemoryError: Java heap space với lỗi Metaspace, và biết dùng heap dump để tìm ai đang giữ object.

    Ôn thêm câu hỏi Java →
  8. 08Virtual threads trong Java 21 là gì? Khi nào nên dùng và cần lưu ý gì?Java · Senior

    Gợi ý trả lời

    Virtual thread là thread nhẹ do JVM quản lý, được gắn lên một số ít platform thread (carrier). Khi gặp I/O blocking, nó nhả carrier để chạy việc khác, nên bạn có thể có hàng trăm nghìn thread mà vẫn viết code blocking dễ đọc.

    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        ids.forEach(id -> executor.submit(() -> callApi(id)));
    }
    
    • Hợp với tải nhiều I/O (gọi DB, HTTP). Không giúp gì với tác vụ nặng CPU.
    • Spring Boot 3.2+ bật bằng spring.threads.virtual.enabled=true.
    • Không đưa virtual thread vào pool: tạo mới cho mỗi task là cách dùng đúng.
    • Giới hạn tài nguyên (connection pool DB) vẫn là giới hạn thật; dùng Semaphore nếu cần.
    • Trên Java 21, blocking bên trong synchronized có thể "pin" carrier; các bản JDK mới hơn đã cải thiện. Cẩn thận với ThreadLocal chứa object lớn.

    Người phỏng vấn muốn nghe: virtual threads tăng throughput, không làm từng request nhanh hơn.

    Ôn thêm câu hỏi Java →
  9. 09So sánh synchronized, volatile, ReentrantLock và ConcurrentHashMap. Bạn tránh race condition thế nào?Java · Senior

    Gợi ý trả lời

    Race condition xảy ra khi nhiều thread đọc-sửa-ghi cùng dữ liệu mà không đồng bộ. Mỗi công cụ giải quyết một phần:

    • volatile: đảm bảo visibility (thread khác thấy giá trị mới nhất), nhưng không làm count++ thành atomic.
    • synchronized: vừa loại trừ lẫn nhau vừa đảm bảo visibility (quan hệ happens-before).
    • ReentrantLock: như synchronized nhưng có tryLock với timeout, lock có thể ngắt, nhiều Condition.
    • AtomicInteger/LongAdder: đếm không cần lock.
    • ConcurrentHashMap: thread-safe với độ tranh chấp thấp. Dùng compute/merge/putIfAbsent cho thao tác kép, đừng get rồi put.

    Hay sai: dùng Collections.synchronizedMap rồi duyệt map mà không lock, hoặc kiểm tra if (!map.containsKey(k)) map.put(k, v) trên map đồng thời: hai bước riêng lẻ vẫn bị chen ngang. Cách tốt nhất vẫn là giảm state dùng chung (object bất biến, mỗi thread một bản).

    Ôn thêm câu hỏi Java →
  10. 10Bạn hãy giới thiệu ngắn về bản thân.Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Đây là câu mở đầu gần như chắc chắn có. Dùng công thức Hiện tại – Quá khứ – Tương lai, gói trong khoảng 1–2 phút.

    • Hiện tại: vị trí, số năm kinh nghiệm, mảng/công nghệ chính.
    • Quá khứ: một hai dự án hoặc thành tích liên quan nhất tới vị trí đang tuyển.
    • Tương lai: vì sao bạn quan tâm tới vị trí này.

    Câu mẫu: "Em là backend developer, khoảng 3 năm kinh nghiệm, chủ yếu làm Java Spring cho hệ thống thanh toán. Ở dự án gần nhất em phụ trách module đối soát và tối ưu các truy vấn báo cáo chạy chậm. Em đang tìm môi trường làm sản phẩm lâu dài để đi sâu hơn về thiết kế hệ thống, nên rất quan tâm tới vị trí này."

    Hay sai: kể từ quê quán, trường cấp ba, hoặc đọc lại nguyên CV.

    Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →

Bạn đã phỏng vấn ở VIHAT Technology?

Kể lại các vòng và câu hỏi đã gặp (ẩn danh) để người sau ôn đúng trọng tâm.

Chia sẻ kinh nghiệm phỏng vấn