Việc làm

05/10 · Hà Nội · Tại văn phòng

Middle/Senior Java Dev (Spring, MySQL, MongoDB)

CÔNG TY TNHH DỊCH VỤ GIA TĂNG GOLDENGATE · Backend Developer

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, 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. 01Một service Spring Boot trên production đột nhiên chậm, CPU cao hoặc bị OOM. Bạn điều tra thế nào?Java · Senior

    Gợi ý trả lời

    Đi từ số liệu đến bằng chứng, đừng đoán rồi sửa.

    1. Xem metrics (Actuator, Micrometer): latency, số request, heap, GC pause, connection pool đang chờ, thời gian gọi DB và API ngoài.
    2. CPU cao: lấy thread dump vài lần cách nhau vài giây (jcmd <pid> Thread.print hoặc jstack), tìm thread luôn RUNNABLE ở cùng chỗ. Có thể là vòng lặp, regex xấu, hoặc GC chạy liên tục.
    3. Chậm mà CPU thấp: thread đang chờ: hết connection DB, lock, gọi API ngoài không có timeout.
    4. OOM hoặc heap tăng dần: bật -XX:+HeapDumpOnOutOfMemoryError, mở heap dump bằng Eclipse MAT, xem ai giữ nhiều bộ nhớ nhất.
    5. Java Flight Recorder (jcmd <pid> JFR.start) cho profile chi phí thấp, dùng được trên production.

    Người phỏng vấn muốn nghe: có quy trình rõ ràng, biết cả cách giảm thiệt hại tạm thời (rollback, scale) trước khi tìm nguyên nhân gốc.

    Ôn thêm câu hỏi Java →
  2. 02Hai người cùng đặt mua sản phẩm cuối cùng trong kho. Bạn xử lý cập nhật đồng thời trong JPA thế nào?Java · Senior

    Gợi ý trả lời

    Đây là bài toán lost update. Có hai hướng chính, chọn theo mức độ tranh chấp:

    • Optimistic locking: thêm field @Version. Khi update, Hibernate kèm điều kiện where version = ?; nếu người khác đã sửa trước, bạn nhận OptimisticLockException và có thể retry hoặc báo lỗi. Hợp khi tranh chấp ít.
    • Pessimistic locking: @Lock(LockModeType.PESSIMISTIC_WRITE) sinh SELECT ... FOR UPDATE, giữ khoá đến hết transaction. Hợp khi tranh chấp nhiều, đổi lại throughput giảm và có nguy cơ deadlock.
    • Đơn giản nhất cho tồn kho: update có điều kiện ngay trong DB:
    UPDATE product SET stock = stock - 1
    WHERE id = ? AND stock > 0;
    

    Kiểm tra số dòng bị ảnh hưởng: bằng 0 nghĩa là hết hàng.

    Hay sai: dùng synchronized trong code Java. Nó vô dụng khi chạy nhiều instance, và cũng không bảo vệ được dữ liệu ở DB.

    Ôn thêm câu hỏi Java →
  3. 03Dependency 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 →
  4. 04Làm sao migrate schema (thêm cột, đổi kiểu, thêm index) trên bảng lớn mà không downtime?SQL & Database · Senior

    Gợi ý trả lời

    Chia thay đổi thành nhiều bước tương thích ngược để phiên bản code cũ và mới chạy song song được (expand rồi contract).

    1. Expand: thêm cột mới cho phép NULL hoặc có default; tránh câu lệnh viết lại cả bảng.
    2. Code mới ghi vào cả cột cũ và mới.
    3. Backfill dữ liệu cũ theo từng lô nhỏ, có nghỉ giữa các lô để không gây lag replica.
    4. Chuyển code sang đọc cột mới, kiểm tra kỹ.
    5. Contract: bỏ cột cũ ở một lần deploy sau.

    Index trên bảng lớn: PostgreSQL dùng CREATE INDEX CONCURRENTLY; MySQL dùng online DDL hoặc công cụ như gh-ost, pt-online-schema-change.

    Người phỏng vấn muốn nghe: bạn biết DDL có thể giữ lock khiến mọi query xếp hàng, nên đặt lock_timeout và luôn có kế hoạch rollback.

    Ôn thêm câu hỏi SQL & Database →
  5. 05Composite index (index nhiều cột) hoạt động ra sao? Thứ tự cột có quan trọng không?SQL & Database

    Gợi ý trả lời

    Có. Composite index sắp xếp theo cột đầu, rồi đến cột thứ hai trong cùng giá trị cột đầu, v.v. Vì vậy nó chỉ dùng hiệu quả khi query dùng các cột từ trái sang (leftmost prefix).

    Với INDEX (status, created_at):

    • WHERE status = 'paid' AND created_at > ...: dùng tốt.
    • WHERE status = 'paid' ORDER BY created_at DESC: dùng cho cả lọc lẫn sắp xếp.
    • WHERE created_at > ... (không có status): thường không dùng được.

    Nguyên tắc chọn thứ tự: cột so sánh bằng (=) đặt trước, cột so sánh khoảng hoặc sắp xếp đặt sau. Nếu index chứa đủ mọi cột query cần (covering index) thì DB không phải đọc lại bảng.

    Hay sai: tạo riêng index cho từng cột rồi nghĩ rằng chúng sẽ kết hợp hiệu quả như một composite index.

    Ôn thêm câu hỏi SQL & Database →
  6. 06@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 →
  7. 07Lỗ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 →
  8. 08Bộ 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 →
  9. 09Các isolation level là gì? Dirty read, non-repeatable read, phantom read khác nhau thế nào?SQL & Database

    Gợi ý trả lời

    Isolation level quyết định một transaction thấy được bao nhiêu thay đổi của transaction khác; mức càng cao càng an toàn nhưng càng dễ tranh chấp.

    • Dirty read: đọc dữ liệu transaction khác chưa commit.
    • Non-repeatable read: đọc lại cùng một dòng thấy giá trị đã đổi.
    • Phantom read: chạy lại cùng điều kiện thấy thêm hoặc mất dòng.

    Bốn mức chuẩn: Read Uncommitted, Read Committed, Repeatable Read, Serializable. Mặc định của PostgreSQL, SQL Server, Oracle là Read Committed; MySQL InnoDB là Repeatable Read.

    Thực tế các DB dùng MVCC nên hành vi có khác lý thuyết: Repeatable Read của PostgreSQL dùng snapshot nên không gặp phantom, còn InnoDB dùng gap lock cho câu đọc có khoá.

    Người phỏng vấn muốn nghe: bạn biết DB mình dùng mặc định ở mức nào và đã từng xử lý lost update, vd. bằng SELECT ... FOR UPDATE hoặc optimistic locking.

    Ôn thêm câu hỏi SQL & Database →
  10. 10Vì sao bạn chọn ứng tuyển vào công ty chúng tôi?Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Câu này kiểm tra bạn có tìm hiểu không hay chỉ rải CV. Nối ba thứ: công ty, vị trí, và bạn.

    • Tìm hiểu trước: sản phẩm, khách hàng, công nghệ, tin tức gần đây, đánh giá của nhân viên cũ và hiện tại.
    • Chọn một hai điểm cụ thể bạn thật sự quan tâm: sản phẩm bạn từng dùng, bài toán kỹ thuật, quy mô người dùng, văn hoá làm việc.
    • Nối với kinh nghiệm hoặc mục tiêu của bạn.

    Câu mẫu: "Em có dùng ứng dụng của bên mình và thấy phần thanh toán rất mượt. Trong JD có nói team đang mở rộng hệ thống xử lý giao dịch, đúng mảng em đã làm hai năm. Em nghĩ mình đóng góp được ngay và cũng học được nhiều ở quy mô lớn hơn."

    Hay sai: "Vì công ty lớn, lương tốt" hoặc khen chung chung áp vào công ty nào cũng được.

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

Bạn đã phỏng vấn ở CÔNG TY TNHH DỊCH VỤ GIA TĂNG GOLDENGATE?

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