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, Python, Golang). 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.
01
@Transactionalhoạt động thế nào? Vì sao có lúc gắn annotation rồi mà transaction không chạy?JavaGợi ý trả lời
Ôn thêm câu hỏi Java →Spring tạo proxy bao quanh bean. Khi gọi method có
@Transactionalqua 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à
privatehoặcfinal: 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áorollbackFor = Exception.class. - Exception bị
catchvà nuốt bên trong method.
Nên biết thêm
propagation(REQUIRED,REQUIRES_NEW) vàreadOnly = truecho 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.
- Self-invocation: method A trong cùng class gọi
02Lỗi N+1 query trong JPA/Hibernate là gì và xử lý ra sao?Java
Gợi ý trả lời
Ôn thêm câu hỏi Java →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 FETCHtrong JPQL:select o from Order o join fetch o.customer.@EntityGraph(attributePaths = "customer")trên method của repository.@BatchSizehoặchibernate.default_batch_fetch_sizeđể gom lazy load thành câuIN (...).- 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-sqlhoặc log của Hibernate) khi dev, hoặc dùng thống kê của Hibernate.Hay sai: đổi sang
FetchType.EAGERcho 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.03Bộ 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
Ôn thêm câu hỏi Java →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 Mapchỉ thêm, không bao giờ xoá. ThreadLocalkhôngremove()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 spacevới lỗi Metaspace, và biết dùng heap dump để tìm ai đang giữ object.04Trong Django ORM, lỗi N+1 query là gì? Phân biệt
select_relatedvàprefetch_related.PythonGợi ý trả lời
Ôn thêm câu hỏi Python →N+1 là khi lấy danh sách bằng 1 query, rồi mỗi phần tử truy cập quan hệ lại sinh thêm 1 query. Ví dụ duyệt 50 bài viết và in
post.author.namesẽ thành 51 query.select_related: dùng SQLJOIN, cho quan hệ trỏ tới một object (ForeignKey,OneToOne).prefetch_related: chạy query riêng rồi ghép trong Python, cho quan hệ nhiều (ManyToMany, reverseForeignKey).
posts = (Post.objects .select_related("author") .prefetch_related("tags"))Phát hiện bằng Django Debug Toolbar, hoặc
assertNumQueriestrong test.Hay sai: gọi
.filter()trên quan hệ đã prefetch bên trong vòng lặp. Lệnh đó tạo query mới và bỏ qua dữ liệu prefetch; dùngPrefetch(..., queryset=...)để lọc ngay từ đầu.05Context manager (
with) là gì? Làm sao tự viết một context manager?PythonGợi ý trả lời
Ôn thêm câu hỏi Python →Context manager đảm bảo việc "mở" và "dọn dẹp" luôn đi cùng nhau, kể cả khi có exception: đóng file, trả connection, nhả lock, rollback transaction.
Cách nhanh nhất là dùng
contextlib.contextmanager:from contextlib import contextmanager @contextmanager def db_transaction(conn): try: yield conn conn.commit() except Exception: conn.rollback() raise- Cách đầy đủ: viết class có
__enter__và__exit__(self, exc_type, exc, tb). Nếu__exit__trả vềTruethì exception bị nuốt. - Bản async:
async with,__aenter__/__aexit__hoặcasynccontextmanager.
Hay sai: quên
raiselại exception trong khốiexcept, khiến lỗi bị che mất và code phía sau tưởng mọi thứ đã thành công.- Cách đầy đủ: viết class có
06
deferhoạt động thế nào? Vòng lặpforkết hợp goroutine và closure có thay đổi gì từ Go 1.22?GolangGợi ý trả lời
Ôn thêm câu hỏi Golang →deferhoãn lời gọi hàm đến khi hàm bao ngoài kết thúc (kể cả khi panic), chạy theo thứ tự LIFO. Tham số của lời gọi được tính ngay lúc gặpdefer, không phải lúc chạy.for i := 0; i < 3; i++ { defer fmt.Println(i) // in 2, 1, 0 }- Đừng
defer f.Close()trong vòng lặp mở hàng nghìn file: chúng chỉ đóng khi hàm kết thúc. Tách thân vòng lặp thành hàm riêng.
Về vòng lặp: trước Go 1.22, biến vòng lặp dùng chung cho mọi lần lặp nên goroutine hay closure thường thấy giá trị cuối cùng. Từ Go 1.22, mỗi lần lặp có biến riêng (khi
go.modkhai báo 1.22 trở lên), nên lỗi này không còn.Người phỏng vấn muốn nghe: bạn biết thay đổi này phụ thuộc phiên bản trong
go.mod.- Đừng
07Virtual 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
Ôn thêm câu hỏi Java →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
Semaphorenếu cần. - Trên Java 21, blocking bên trong
synchronizedcó thể "pin" carrier; các bản JDK mới hơn đã cải thiện. Cẩn thận vớiThreadLocalchứ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.
08So sánh
synchronized,volatile,ReentrantLockvàConcurrentHashMap. Bạn tránh race condition thế nào?Java · SeniorGợi ý trả lời
Ôn thêm câu hỏi Java →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àmcount++thành atomic.synchronized: vừa loại trừ lẫn nhau vừa đảm bảo visibility (quan hệ happens-before).ReentrantLock: nhưsynchronizednhưng cótryLockvới timeout, lock có thể ngắt, nhiềuCondition.AtomicInteger/LongAdder: đếm không cần lock.ConcurrentHashMap: thread-safe với độ tranh chấp thấp. Dùngcompute/merge/putIfAbsentcho thao tác kép, đừnggetrồiput.
Hay sai: dùng
Collections.synchronizedMaprồi duyệt map mà không lock, hoặc kiểm traif (!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).09Mộ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
Ôn thêm câu hỏi Java →Đi từ số liệu đến bằng chứng, đừng đoán rồi sửa.
- Xem metrics (Actuator, Micrometer): latency, số request, heap, GC pause, connection pool đang chờ, thời gian gọi DB và API ngoài.
- CPU cao: lấy thread dump vài lần cách nhau vài giây (
jcmd <pid> Thread.printhoặcjstack), 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. - Chậm mà CPU thấp: thread đang chờ: hết connection DB, lock, gọi API ngoài không có timeout.
- 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. - 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.
10Mức lương mong muốn của bạn là bao nhiêu?Câu hỏi hành vi & văn hoá
Gợi ý trả lời
Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →Tìm hiểu trước mặt bằng lương cho vị trí và số năm kinh nghiệm (dữ liệu lương trên Drama Công Ty, bạn bè cùng ngành), rồi đưa ra một khoảng có căn cứ.
- Nói rõ gross hay net. Gross là lương trước khi trừ bảo hiểm bắt buộc và thuế thu nhập cá nhân; net là số thực nhận.
- Hỏi tổng thu nhập: lương tháng 13 (không bắt buộc theo luật), thưởng, chu kỳ review lương, bảo hiểm sức khoẻ.
- Lương thử việc theo luật tối thiểu bằng 85% lương chính thức; nhiều công ty trả 100%, cứ hỏi rõ.
Câu mẫu: "Dựa trên kinh nghiệm và mặt bằng thị trường, em mong muốn khoảng X đến Y triệu gross. Em cũng muốn hiểu thêm về thưởng và review lương bên mình."
Hay sai: nói "tuỳ công ty" (dễ bị trả thấp), hoặc khai khống lương hiện tại.
Bạn đã phỏng vấn ở RONTECH?
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