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 (C# & .NET, 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.
01Dependency Injection trong ASP.NET Core: phân biệt Transient, Scoped và Singleton.C# & .NET
Gợi ý trả lời
Ôn thêm câu hỏi C# & .NET →ASP.NET Core có DI container sẵn; lifetime quyết định khi nào tạo instance mới.
- Transient: mỗi lần resolve tạo mới. Hợp với service nhẹ, không trạng thái.
- Scoped: một instance cho mỗi request (mỗi scope).
DbContextmặc định là scoped. - Singleton: một instance cho cả vòng đời ứng dụng. Phải thread-safe.
builder.Services.AddScoped<IOrderService, OrderService>(); builder.Services.AddSingleton<IClock, SystemClock>();Hay sai: inject service scoped (như
DbContext) vào singleton, gọi là captive dependency: DbContext bị giữ mãi và dùng chung giữa nhiều thread. Môi trường Development sẽ báo lỗi khi validate scope. Nếu singleton cần dữ liệu scoped, hãy injectIServiceScopeFactoryvà tự tạo scope.02Middleware trong ASP.NET Core là gì? Thứ tự đăng ký có quan trọng không?C# & .NET
Gợi ý trả lời
Ôn thêm câu hỏi C# & .NET →Middleware là các bước nối thành pipeline xử lý request: mỗi bước có thể xử lý, gọi bước kế tiếp, rồi xử lý tiếp response trên đường về. Thứ tự rất quan trọng vì request đi qua đúng theo thứ tự đăng ký.
app.UseExceptionHandler("/error"); app.UseHttpsRedirection(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers();- Exception handler phải đứng đầu để bắt lỗi của mọi bước sau.
UseAuthenticationphải trướcUseAuthorization, nếu không user luôn là ẩn danh.- Middleware có thể "short-circuit", vd. trả cache hoặc 401 mà không gọi
next.
Người phỏng vấn muốn nghe: bạn từng viết middleware riêng, vd. gắn correlation id hoặc log thời gian xử lý, và phân biệt được middleware với filter của MVC.
03Lỗi N+1 query trong Entity Framework Core là gì và xử lý thế nào?C# & .NET
Gợi ý trả lời
Ôn thêm câu hỏi C# & .NET →N+1 là khi lấy danh sách N bản ghi bằng 1 query, rồi mỗi bản ghi lại phát sinh thêm 1 query để lấy dữ liệu liên quan, thường do lazy loading hoặc truy vấn trong vòng lặp.
Cách xử lý:
- Eager loading:
.Include(o => o.Items). - Tốt hơn nữa là projection chỉ lấy cột cần:
.Select(o => new OrderDto(o.Id, o.Items.Count)). - Include nhiều collection gây "cartesian explosion" thì dùng
.AsSplitQuery(). - Màn hình chỉ đọc thì thêm
.AsNoTracking()để giảm chi phí change tracking.
Để phát hiện, bật log SQL của EF Core khi phát triển, hoặc dùng công cụ APM xem số query mỗi request.
Người phỏng vấn muốn nghe: bạn kiểm tra SQL thực sự được sinh ra thay vì tin LINQ trông gọn là chạy nhanh.
- Eager loading:
04Cá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
Ôn thêm câu hỏi SQL & Database →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 UPDATEhoặc optimistic locking.05Mộ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
Ôn thêm câu hỏi SQL & Database →Đ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.
- Bật slow query log (MySQL) hoặc
pg_stat_statements(PostgreSQL) để biết query nào tốn thời gian nhất. - Chạy
EXPLAIN(PostgreSQL nên dùngEXPLAIN (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. - Sửa theo nguyên nhân: thêm hoặc đổi composite index, bỏ hàm bọc cột, chỉ
SELECTcột cần, phân trang bằng keyset thay choOFFSETlớn. - Kiểm tra phía ứng dụng: lỗi N+1 query, thiếu connection pool, lock chờ lâu.
- 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.
- Bật slow query log (MySQL) hoặc
06Garbage Collector của .NET hoạt động thế nào? Khi nào cần IDisposable?C# & .NET
Gợi ý trả lời
Ôn thêm câu hỏi C# & .NET →GC quản lý heap theo thế hệ: object mới ở Gen 0, sống sót qua lần thu gom thì lên Gen 1, Gen 2. Phần lớn object chết trẻ nên thu gom Gen 0 rất rẻ. Object lớn (khoảng từ 85 KB) vào Large Object Heap và chỉ được thu cùng Gen 2.
GC chỉ thu hồi bộ nhớ managed. Tài nguyên khác như file, socket, kết nối DB cần giải phóng chủ động qua
IDisposable:await using var conn = new NpgsqlConnection(cs); using var stream = File.OpenRead(path);- Finalizer chỉ là lưới an toàn, chạy không xác định thời điểm và tốn chi phí.
Hay sai: tạo mới
HttpClientcho mỗi request rồi dispose, dễ cạn socket. Hãy dùngIHttpClientFactoryhoặc một instance dùng chung.07Ứng dụng ASP.NET Core bị memory leak hoặc CPU cao trên production. Bạn điều tra thế nào?C# & .NET · Senior
Gợi ý trả lời
Ôn thêm câu hỏi C# & .NET →Thu thập số liệu trước, đoán sau: xem metrics, chụp dump hoặc trace, rồi phân tích.
- Theo dõi bằng
dotnet-counters: heap size, số lần GC từng gen, thread pool queue length, exception rate. - Leak bộ nhớ: chụp hai lần
dotnet-gcdumphoặcdotnet-dumpcách nhau một khoảng, so sánh loại object tăng và tìm ai đang giữ tham chiếu. - CPU cao hoặc treo:
dotnet-traceđể xem hot path; thread pool queue tăng thường do sync-over-async.
Nguyên nhân hay gặp: event handler không gỡ đăng ký, cache static không giới hạn kích thước, giữ
DbContextquá lâu, regex hoặc serialize lặp lại trong vòng lặp nóng.Người phỏng vấn muốn nghe: một ca thực tế bạn từng xử lý, công cụ đã dùng và kết quả trước/sau.
- Theo dõi bằng
08Xử lý concurrency khi nhiều request cùng cập nhật một bản ghi trong EF Core thế nào?C# & .NET · Senior
Gợi ý trả lời
Ôn thêm câu hỏi C# & .NET →Hai hướng chính: optimistic concurrency (phát hiện xung đột khi lưu) và pessimistic (khoá trước khi sửa).
Optimistic với EF Core: đánh dấu một cột làm concurrency token, EF thêm điều kiện so sánh vào
UPDATEvà némDbUpdateConcurrencyExceptionnếu không có dòng nào bị cập nhật.public class Product { public int Stock { get; set; } [Timestamp] public byte[] RowVersion { get; set; } = []; }- Bắt exception, tải lại dữ liệu, rồi retry hoặc báo người dùng.
- PostgreSQL thường dùng cột hệ thống
xminlàm token. - Trường hợp đơn giản như trừ tồn kho có thể dùng một câu
ExecuteUpdateAsyncatomic kèm điều kiệnStock >= qty.
Người phỏng vấn muốn nghe: bạn cân nhắc mức độ tranh chấp: thấp thì optimistic, cao và nghiệp vụ quan trọng thì khoá hoặc đưa vào hàng đợi.
09Chuẩn hoá (normalization) là gì? Khi nào nên denormalize?SQL & Database
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →Chuẩn hoá là tách dữ liệu để mỗi thông tin chỉ lưu ở một chỗ, tránh dư thừa và sai lệch khi cập nhật.
- 1NF: mỗi ô một giá trị nguyên tử, không lưu danh sách trong một cột.
- 2NF: cột không khoá phụ thuộc vào toàn bộ khoá chính, không chỉ một phần.
- 3NF: cột không khoá không phụ thuộc bắc cầu qua cột không khoá khác.
Denormalize khi đọc nhiều hơn ghi rất nhiều và JOIN trở thành điểm nghẽn: lưu sẵn
comment_counttrong bảng bài viết, chépcustomer_namevào đơn hàng để giữ đúng tên tại thời điểm đặt, hoặc dựng bảng báo cáo riêng.Hay sai: denormalize mà không có cơ chế đồng bộ (trigger, job, event) nên số liệu lệch dần. Hãy nói rõ cái giá phải trả là logic ghi phức tạp hơn.
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
Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →Đâ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.
Bạn đã phỏng vấn ở Nam Thanh Bình?
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