Mapper Interfaces¶
Mapper trong LarkBatis là một Java interface thông thường. Không cần kế thừa interface cha, không cần bọc dynamic proxy lúc runtime.
Khi biên dịch, processor sinh ra class final class UserMapper$$Impl implements UserMapper với constructor công khai nhận LarkBatisSession.
Annotations Statement¶
| Annotation | Loại Statement |
|---|---|
@Select |
SELECT |
@Insert |
INSERT |
@Update |
UPDATE |
@Delete |
DELETE |
Nhận mảng String[], các dòng được tự động ghép nối bằng một dấu cách đơn:
@Select({
"SELECT id, name, email, created_at",
"FROM users",
"WHERE email = #{email}"
})
User findByEmail(String email);
Mapper interface chứa ít nhất một statement annotation sẽ được processor tự động nhận diện. Bạn chỉ cần thêm @Mapper khi toàn bộ statement nằm trong file XML.
Liên kết tham số qua #{}¶
Cú pháp #{name} được chuyển đổi thành ký tự giữ chỗ ? trong JDBC PreparedStatement và sinh lệnh ps.setXxx tương ứng:
Tham số là kiểu nguyên thủy, wrapper hoặc một Java Bean chứa getter:
Mỗi tham số cần có tên đối chiếu (tên biến trong code hoặc đặt qua @Param):
Lưu ý về cờ -parameters
Gradle incremental build có thể chạy processor trên file .class. Hãy bật cờ -parameters trong cấu hình biên dịch hoặc khai báo @Param để tránh việc tên tham số bị đổi thành arg0.
Tên tham số không tồn tại sẽ báo lỗi biên dịch ngay lập tức. Không hỗ trợ kiểu Map hoặc Object không định kiểu.
Các kiểu trả về hỗ trợ¶
| Chữ ký phương thức | Mã nguồn sinh ra |
|---|---|
User findById(long) |
rs.next() ? UserRow.read(rs) : null |
List<User> findAll() |
Đọc tuần tự toàn bộ ResultSet vào danh sách List |
Stream<User> streamAll() |
Trả về con trỏ mở Stream<User> (caller chịu trách nhiệm đóng stream). Xem Streaming |
long countByName(String) |
Đọc trực tiếp giá trị kiểu long từ cột 1 |
int insert(User) |
ps.executeUpdate() trả về số dòng bị ảnh hưởng |
void delete(long) |
ps.executeUpdate() bỏ qua kết quả |
Định nghĩa POJO Result Class¶
POJO kết quả chỉ cần constructor không tham số và các hàm getter/setter tương ứng:
public class User {
private long id;
private String name;
private Instant createdAt;
// Getters and Setters
}
Tên cột được tự động ánh xạ sang setter theo quy tắc snake_case → camelCase lúc biên dịch (ví dụ cột created_at tự động gọi setCreatedAt()).
Nếu tên cột không thể tự khớp, bạn có thể:
1. Đặt alias trong câu SQL: SELECT user_name AS name ...
2. Gắn @Column("user_name") trên field hoặc getter/setter.
3. Khai báo <resultMap>.
Đọc dữ liệu: Vị trí cột vs. Tên cột¶
- Đọc theo vị trí cột (Positional read): Khi câu
SELECTliệt kê danh sách cột rõ ràng, processor sinh các lệnh đọc trực tiếp theo index tĩnh (rs.getLong(1),rs.getString(2)). - Fallback đọc theo tên cột (Name-based fallback): Khi câu lệnh là
SELECT *hoặc chứa chuỗi${}trong select list, processor giải quyết index cột từResultSetMetaDatamột lần duy nhất ở dòng đầu tiên, các dòng tiếp theo vẫn đọc theo vị trí.
Phương thức default trong Mapper¶
Bạn có thể viết các phương thức default trực tiếp trong mapper interface để thực hiện truy vấn tùy biến hoặc nghiệp vụ bổ sung:
default List<User> recent(LarkBatisSession s, int limit) {
return s.query(
SqlFragment.unsafeRawSql(
"SELECT id, name, email, created_at FROM users"
+ " ORDER BY created_at DESC LIMIT " + limit),
ps -> { },
UserRow.READER); // Tái sử dụng UserRow.READER sinh sẵn không cần reflection
}
Factory Registry LarkBatisMappers¶
Tất cả các mapper được tổng hợp trong class factory tĩnh LarkBatisMappers:
Khi tích hợp Spring Boot, class @Configuration sinh ra sẽ tự động inject các mapper bean mà bạn không cần gọi factory này thủ công.