JDBC交互框架:
Spring的JDBC操作工具:
依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
JDBC的模版類:JdbcTemplate
引入Mysql的依賴
<dependency>
<groupId>com.mysql</groupId>
?<artifactId>mysql-connector-j</artifactId>
</dependency>
application的配置信息:
spring:
??datasource:
????url: jdbc:mysql://localhost:3306/test
????username: 你的用戶名
????password: 你的密碼
????driver-class-name: com.mysql.cj.jdbc.Driver
使用JdbcTemplate來操作
Yml配置
spring:
??datasource:
????url: jdbc:mysql://localhost:3306/test
????username: root
????password: 123456
????driver-class-name: com.mysql.cj.jdbc.Driver
我們要操作數據庫,最簡單直接的方法就是使用JdbcTemplate來完成:
@Resource
JdbcTemplate template;
實例:
@Test
void contextLoads() {
Map<String, Object>?map = template.queryForMap(
"select * from user where id = ?", 1
);
????System.out.println(map);
}
亦可以查詢類:
@Data@AllArgsConstructorpublic?class?User?{
????int?id;
????String?name;
????String?email;
String?password;
}
@Testvoid?contextLoads()?{
????User?user =?template.queryForObject("select * from user where id = ?",
????????(r,?i)?->?new?User(r.getInt(1),?r.getString(2),?r.getString(3),?r.getString(4)),?1);
System.out.println(user);
}
第一個參數:SQL 查詢語句,使用?作為占位符。
第二個參數:RowMapper 接口的實現,用于將查詢結果映射到 User 對象。這里使用了 Lambda 表達式:
r.getInt(1):獲取結果集中第一列(id)。
r.getString(2):獲取結果集中第二列(name)。
r.getString(3):獲取結果集中第三列(email)。
r.getString(4):獲取結果集中第四列(password)。
第三個參數:SQL 查詢參數,用于替換?占位符。
這個測試方法的功能是從數據庫中查詢 id 為 1 的用戶,并將結果打印輸出。
亦可以進行查詢,更新,刪除,使用update
@Repositorypublic class UserDao {
????private final JdbcTemplate template;
????public UserDao(JdbcTemplate template) {
????????this.template = template;
????}
????// 插入用戶
????public int insertUser(User user) {
????????String sql = "INSERT INTO user (id, name, email, password) VALUES (?, ?, ?, ?)";
????????return template.update(sql,
????????????????user.getId(),
????????????????user.getName(),
????????????????user.getEmail(),
????????????????user.getPassword());
????}
????// 更新用戶
????public int updateUser(User user) {
????????String sql = "UPDATE user SET name = ?, email = ?, password = ? WHERE id = ?";
????????return template.update(sql,
????????????????user.getName(),
????????????????user.getEmail(),
????????????????user.getPassword(),
????????????????user.getId());
????}
????// 刪除用戶
????public int deleteUser(int id) {
????????String sql = "DELETE FROM user WHERE id = ?";
????????return template.update(sql, id);
????}
????// 查詢用戶(保留原示例)
????public User getUserById(int id) {
????????String sql = "SELECT * FROM user WHERE id = ?";
????????return template.queryForObject(sql, userRowMapper(), id);
????}
????// RowMapper 提取為獨立方法提高復用性
????private RowMapper<User> userRowMapper() {
????????return (rs, rowNum) -> new User(
????????????????rs.getInt("id"),
????????????????rs.getString("name"),
????????????????rs.getString("email"),
????????????????rs.getString("password")
????????);
}
}
如果是小項目or測試方法,JdbcTemplate可以很快的輔助我們完成操作
Jdbc的簡單封裝:
SimpleJdbcInsert來處理一些高級的插入:SimpleJdbcInsert?是 Spring 框架提供的一個便捷工具類,用于簡化 JDBC 插入操作,尤其適合處理動態插入場景。與直接使用?JdbcTemplate?相比,它提供了更高級的特性,如自動生成主鍵、基于數據庫元數據的表結構感知等。
核心特性
1,自動表結構感知:通過數據庫元數據自動獲取表結構信息
2,主鍵生成支持:支持自增主鍵和序列(如 Oracle)
3,參數類型自動匹配:基于列類型自動轉換參數
4,批處理支持:高效處理批量插入操作
5,簡化的 API:鏈式調用風格,代碼更簡潔
看一看這個的基本使用方法:
@Repositorypublic class AdvancedUserDao {
????private final SimpleJdbcInsert jdbcInsert;
????public AdvancedUserDao(DataSource dataSource) {
????????// 初始化 SimpleJdbcInsert,指定數據源和表名
????????this.jdbcInsert = new SimpleJdbcInsert(dataSource)
????????????????.withTableName("user")
????????????????.usingGeneratedKeyColumns("id"); // 指定自增主鍵列
????}
????// 插入用戶并返回生成的主鍵
????public Number insertUser(User user) {
????????Map<String, Object> parameters = new HashMap<>();
????????parameters.put("name", user.getName());
????????parameters.put("email", user.getEmail());
????????parameters.put("password", user.getPassword());
????????
????????// 執行插入并返回自動生成的主鍵
????????return jdbcInsert.executeAndReturnKey(parameters);
????}
????public void batchInsertUsers(List<User> users) {
??? ?// 1. 創建一個用于存儲批量插入參數的列表
???? List<Map<String, Object>> batch = new ArrayList<>();
????
???? // 2. 遍歷用戶列表,為每個用戶創建參數映射
???? for (User user : users) {
???? ????// 3. 為當前用戶創建一個鍵值對映射,鍵為列名,值為列值
???? ????Map<String, Object> parameters = new HashMap<>();
???? ????// 4. 添加用戶名列
???? ????parameters.put("name", user.getName());
???? ????// 5. 添加郵箱列
???? ????parameters.put("email", user.getEmail());
???? ????// 6. 添加密碼列
???? ????parameters.put("password", user.getPassword());
???? ????// 7. 將當前用戶的參數映射添加到批量參數列表中
???? ????batch.add(parameters);
???? }
????
???? // 8. 執行批量插入操作
???? // ???batch.toArray(new Map[0]) 將列表轉換為 Map 數組
???? // ???executeBatch 方法會將數組中的每個 Map 作為一組參數執行插入
jdbcInsert.executeBatch(batch.toArray(new Map[0]));
}
}
還可以自定義列映射:
public AdvancedUserDao(DataSource dataSource) {
????this.jdbcInsert = new SimpleJdbcInsert(dataSource)
????????????.withTableName("user")
????????????.usingColumns("name", "email", "password") // 顯式指定要插入的列
????????????.withoutTableColumnMetaDataAccess(); // 禁用元數據訪問(提高性能)
}
處理復合主鍵:
public Number[] insertUserWithCompositeKey(User user) {
????Map<String, Object> params = new HashMap<>();
????params.put("org_id", user.getOrgId()); // 復合主鍵字段1
????params.put("user_id", user.getUserId()); // 復合主鍵字段2
????params.put("name", user.getName());
????
????// 返回包含所有主鍵值的 Map
return jdbcInsert.executeAndReturnKeyHolder(params).getKeys();
}
上面的都是一些小型的工具,幫助我們實現一個小項目or測試方法的時候可以用,更復雜的就不建議了
JPA框架:
Spring Data JPA 是 Spring 框架的一部分,旨在簡化基于 JPA(Java Persistence API)的數據訪問層開發。它通過提供統一的接口和自動實現機制,大幅減少了數據訪問層的樣板代碼,讓開發者可以更專注于業務邏輯。
核心思想,將實體類對應一個數據庫表
first,引入依賴:
同樣的,我們只需要導入stater依賴即可:
<dependency>
????<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
second,創建對應的類:
@Data
public class Account {
????int id;
????String username;
????String password;
}
third添加實體類和數據庫表的映射關系:
@Data
@Entity //表示這個類是一個實體類
@Table(name = "account") //對應的數據庫中表名稱
public class Account {
@GeneratedValue(strategy = GenerationType.IDENTITY) //生成策略,這里配置為自增 @Column(name = "id") //對應表中id這一列
@Id //此屬性為主鍵
int id;
@Column(name = "username") //對應表中
username這一列 String username;
@Column(name = "password") //對應表中password這一列
String password;
}
Fourth:配置yml文件
spring:
??jpa:
????#開啟SQL語句執行日志信息
????show-sql: true
????hibernate:
??????#配置為檢查數據庫表結構,沒有時會自動創建
??????ddl-auto: update
ddl-auto屬性用于設置自動表定義,可以實現自動在數據庫中為我們創建一個表,表的結構會根據我們定義的實體類決定,它有以下幾種:
none: 不執行任何操作,數據庫表結構需要手動創建。
create: 框架在每次運行時都會刪除所有表,并重新創建。
create-drop: 框架在每次運行時都會刪除所有表,然后再創建,但在程序結束時會再次刪除所有表。
update: 框架會檢查數據庫表結構,如果與實體類定義不匹配,則會做相應的修改,以保持它們的一致性。
validate:?框架會檢查數據庫表結構與實體類定義是否匹配,如果不匹配,則會拋出異常。
這個配置項的作用是為了避免手動管理數據庫表結構,使開發者可以更方便地進行開發和測試,但在生產環境中,更推薦使用數據庫遷移工具來管理表結構的變更。
fifth:訪問表
一個repository類,繼承接口JpaRepository<>:
@Repository?
public interface AccountRepository extends JpaRepository<Account, Integer> { }
JpaRepository<實體類, ID類型>
注入這個Repository類進行查詢就好啦
@Resource
AccountRepository repository;
@Test
void contextLoads() {
Account account = new Account();
account.setUsername("小紅");
account.setPassword("1234567");
System.out.println(repository.save(account).getId()); //使用save來快速插入數據,并且會返回插入的對象,如果存在自增ID,對象的自增id屬性會自動被賦值,這就很方便了
}
查詢就可以使用 findxx():
@Test
?void contextLoads() {
//默認通過通過ID查找的方法,并且返回的結果是Optional包裝的對象,非常人性化
?repository.findById(1).ifPresent(System.out::println);
}
方法名拼接自定義SQL
屬性 | 拼接方法名稱示例 | 執行的語句 |
Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull,Null | findByAge(Is)Null | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1(參數與附加%綁定) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1(參數與前綴%綁定) |
Containing | findByFirstnameContaining | … where x.firstname like ?1(參數綁定以%包裝) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> ages) | … where x.age not in ?1 |
True | findByActiveTrue | … where x.active = true |
False | findByActiveFalse | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |
關聯查詢:
一對一關聯:
因為我們JPA的核心思想史對象對應一個表,所以關聯就可以看做一個對象和對象關聯
比如:用戶信息和用戶詳細信息的一對一關聯
的依賴關系,比如用戶表中包含了用戶詳細信息的ID字段作為外鍵,那么實際上就是用戶表實體中包括了用戶詳細信息實體對象:
@Data
@Entity
@Table(name = "users_detail")
public class AccountDetail {
????@Column(name = "id")
????@GeneratedValue(strategy = GenerationType.IDENTITY)
????@Id
????int id;
????@Column(name = "address")
????String address;
????@Column(name = "email")
????String email;
????@Column(name = "phone")
????String phone;
????@Column(name = "real_name")
????String realName;
}
@Data
@Entity
@Table(name = "users")
public class Account {
????@GeneratedValue(strategy = GenerationType.IDENTITY)
????@Column(name = "id")
????@Id
????int id;
????@Column(name = "username")
????String username;
????@Column(name = "password")
????String password;
????@JoinColumn(name = "detail_id") ??//指定存儲外鍵的字段名稱
????@OneToOne ???//聲明為一對一關系
????AccountDetail detail;
}
還有其他的一對多,多對一,多對多的關系
如果只需要查詢用戶信息,不需要詳細信息就可以設置一個懶加載,這樣就不會每次查詢都去找詳細信息了,只會在需要的時候才會去查
@OneToOne(fetch = FetchType.LAZY)?//將獲取類型改為LAZY
當然了,如果你想再加入一個表的數據的時候對關聯的表也去操作,就可以使用cascade
ALL:所有操作都進行關聯操作
PERSIST:插入操作時才進行關聯操作
REMOVE:刪除操作時才進行關聯操作
MERGE:修改操作時才進行關聯操作
就變這樣了:
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)?//設置關聯操作為ALL AccountDetail detail;
一對多:
@oneTomany:
@manyToone:
比如一個成績排名對應了很多的學生,學生們都對應的同一個成績榜單,多對一,這里的學生是多:
@Entitypublic class Student {
????@Id
????@GeneratedValue(strategy = GenerationType.IDENTITY)
????private Long id;
????private String name;
????private int age;
????// 多對一:多個學生關聯同一個成績單
????@ManyToOne(fetch = FetchType.LAZY)
????@JoinColumn(name = "transcript_id") // 外鍵列,指向成績單ID
????private Transcript transcript;
????// 構造方法、Getter和Setter
????public Student() {}
????
????public Student(String name, int age) {
????????this.name = name;
????????this.age = age;
????}
????
????// Getters and Setters
????public Long getId() { return id; }
????public void setId(Long id) { this.id = id; }
????public String getName() { return name; }
????public void setName(String name) { this.name = name; }
????public int getAge() { return age; }
????public void setAge(int age) { this.age = age; }
????public Transcript getTranscript() { return transcript; }
public void setTranscript(Transcript transcript) { this.transcript = transcript; }
}
@Entitypublic class Transcript {
????@Id
????@GeneratedValue(strategy = GenerationType.IDENTITY)
????private Long id;
????private String course; ?// 課程名稱
????private double score; ??// 分數(共享的統一分數)
????// 一對多:一個成績單對應多個學生
????@OneToMany(mappedBy = "transcript", cascade = CascadeType.ALL, orphanRemoval = true)
????private List<Student> students = new ArrayList<>();
????// 構造方法、Getter和Setter
????public Transcript() {}
????
????public Transcript(String course, double score) {
????????this.course = course;
????????this.score = score;
????}
????
????// 添加學生的便捷方法
????public void addStudent(Student student) {
????????students.add(student);
????????student.setTranscript(this);
????}
????
????// 移除學生的便捷方法
????public void removeStudent(Student student) {
????????students.remove(student);
????????student.setTranscript(null);
????}
????
????// Getters and Setters
????public Long getId() { return id; }
????public void setId(Long id) { this.id = id; }
????public String getCourse() { return course; }
????public void setCourse(String course) { this.course = course; }
????public double getScore() { return score; }
????public void setScore(double score) { this.score = score; }
????public List<Student> getStudents() { return students; }
public void setStudents(List<Student> students) { this.students = students; }
}
多對多:
@ManyToMany:
學生(Student)與課程(Course)?的關系。一個學生可以選修多門課程,一門課程也可以被多個學生選修。
一、實體類設計
1.?學生實體(Student)
@Entity
@Table(name = "students")
public class Student {
????@Id
????@GeneratedValue(strategy = GenerationType.IDENTITY)
????private Long id;
????
????private String name;
????private int age;
????
????// 多對多關系:學生選修多門課程
????@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
????@JoinTable(
????????name = "student_course", ??????????????// 中間表名
????????joinColumns = @JoinColumn(name = "student_id"), ?// 指向當前實體(學生)的外鍵
????????inverseJoinColumns = @JoinColumn(name = "course_id") ?// 指向關聯實體(課程)的外鍵
????)
????private List<Course> courses = new ArrayList<>();
????
????// 構造方法、Getter和Setter
????public Student() {}
????
????public Student(String name, int age) {
????????this.name = name;
????????this.age = age;
????}
????
????// 添加課程的便捷方法
????public void addCourse(Course course) {
????????courses.add(course);
????????course.getStudents().add(this);
????}
????
????// 移除課程的便捷方法
????public void removeCourse(Course course) {
????????courses.remove(course);
????????course.getStudents().remove(this);
????}
????
????// Getters and Setters
????public Long getId() { return id; }
????public void setId(Long id) { this.id = id; }
????public String getName() { return name; }
????public void setName(String name) { this.name = name; }
????public int getAge() { return age; }
????public void setAge(int age) { this.age = age; }
????public List<Course> getCourses() { return courses; }
public void setCourses(List<Course> courses) { this.courses = courses; }
}
2.?課程實體(Course)
@Entity
@Table(name = "courses")
public class Course {
????@Id
????@GeneratedValue(strategy = GenerationType.IDENTITY)
????private Long id;
????
????private String courseName;
????private int credits;
????
????// 多對多關系:課程被多個學生選修
????@ManyToMany(mappedBy = "courses") ?// 映射到 Student 實體的 courses 字段
????private List<Student> students = new ArrayList<>();
????
????// 構造方法、Getter和Setter
????public Course() {}
????
????public Course(String courseName, int credits) {
????????this.courseName = courseName;
????????this.credits = credits;
????}
????
????// 添加學生的便捷方法
????public void addStudent(Student student) {
????????students.add(student);
????????student.getCourses().add(this);
????}
????
????// 移除學生的便捷方法
????public void removeStudent(Student student) {
????????students.remove(student);
????????student.getCourses().remove(this);
????}
????
????// Getters and Setters
????public Long getId() { return id; }
????public void setId(Long id) { this.id = id; }
????public String getCourseName() { return courseName; }
????public void setCourseName(String courseName) { this.courseName = courseName; }
????public int getCredits() { return credits; }
????public void setCredits(int credits) { this.credits = credits; }
????public List<Student> getStudents() { return students; }
public void setStudents(List<Student> students) { this.students = students; }
}
二、數據庫表結構
多對多關系通過?中間表(Join Table)?實現:
1.?students 表
字段名 | 類型 | 描述 |
id | BIGINT | 主鍵 |
name | VARCHAR | 學生姓名 |
age | INT | 學生年齡 |
2.?courses 表
字段名 | 類型 | 描述 |
id | BIGINT | 主鍵 |
course_name | VARCHAR | 課程名稱 |
credits | INT | 學分 |
3.?student_course 中間表
字段名 | 類型 | 描述 |
student_id | BIGINT | 外鍵,關聯 students 表 |
course_id | BIGINT | 外鍵,關聯 courses 表 |
PRIMARY KEY | (student_id, course_id) | 復合主鍵 |
三.Repository 接口
public interface StudentRepository extends JpaRepository<Student, Long> {}
public interface CourseRepository extends JpaRepository<Course, Long> {}
四、業務邏輯示例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class StudentCourseService {
????
????@Autowired
????private StudentRepository studentRepository;
????
????@Autowired
????private CourseRepository courseRepository;
????
????// 創建學生并分配課程
????@Transactional
????public Student createStudentWithCourses(String name, int age, List<Course> courses) {
????????Student student = new Student(name, age);
????????courses.forEach(course -> student.addCourse(course));
????????return studentRepository.save(student);
????}
????
????// 創建課程并分配學生
????@Transactional
????public Course createCourseWithStudents(String courseName, int credits, List<Student> students) {
????????Course course = new Course(courseName, credits);
????????students.forEach(student -> course.addStudent(student));
????????return courseRepository.save(course);
????}
????
????// 為學生添加課程
????@Transactional
????public void addCourseToStudent(Long studentId, Long courseId) {
????????Student student = studentRepository.findById(studentId)
????????????????.orElseThrow(() -> new IllegalArgumentException("Student not found"));
????????Course course = courseRepository.findById(courseId)
????????????????.orElseThrow(() -> new IllegalArgumentException("Course not found"));
????????student.addCourse(course);
????}
????
????// 獲取學生及其選修的課程
????@Transactional(readOnly = true)
????public Student getStudentWithCourses(Long studentId) {
????????return studentRepository.findById(studentId)
????????????????.orElseThrow(() -> new IllegalArgumentException("Student not found"));
????}
????
????// 刪除學生及其選課記錄
????@Transactional
????public void deleteStudent(Long studentId) {
????????studentRepository.deleteById(studentId);
}
}
有時候過于復雜的語句還是只有使用SQl語句,為了不讓我們再次去使用Mybatis框架,可以使用@Query(原生sql語句進行查詢)
@Query("update xxx set ?xxx?= ?2 where xxx?= ?1")
int updatexxxbyxxx(第一個參數,第二個參數)
這里的?后面的數字表示填入第幾個參數
MybatisPlus框架:
一、MyBatis-Plus 框架全解析
1. 基本信息
MyBatis-Plus (簡稱 MP) 是一個 MyBatis 的增強工具,旨在簡化開發過程,提供零配置、CRUD 自動化和強大的條件構造器,使開發者能夠更高效地使用 MyBatis。
核心優勢:
無需編寫 XML 或大量 SQL 語句
提供豐富的條件構造器,替代復雜 SQL
支持自動填充、邏輯刪除、樂觀鎖等高級特性
內置分頁插件,簡化分頁操作
代碼生成器快速生成基礎代碼
二、引入依賴
Maven 依賴:
<dependency>
????<groupId>com.baomidou</groupId>
????<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- MySQL 驅動 -->
<dependency>
????<groupId>mysql</groupId>
????<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
三、配置 application.yml
spring:
??datasource:
????driver-class-name: com.mysql.cj.jdbc.Driver
????url: jdbc:mysql://localhost:3306
????username: root
????password: yourpassword
mybatis-plus:
??mapper-locations: classpath:mapper/*.xml ?# mapper XML 文件位置
??global-config:
????db-config:
??????id-type: auto ????????????????????????# 主鍵類型
??????logic-delete-field: deleted ??????????# 邏輯刪除字段名
??????logic-not-delete-value: 0 ????????????# 未刪除值
??????logic-delete-value: 1 ????????????????# 已刪除值
??configuration:
????log-impl: org.apache.ibatis.logging.stdout.StdOutImpl ?# SQL 日志打印
????map-underscore-to-camel-case: true ?????????????????????# 下劃線轉駝峰
四、示例實體類定義
@Data
@TableName("user") ?// 對應數據庫表名
public class User {
????@TableId(type = IdType.AUTO) ?// 主鍵自增
????private Long id;
????@TableFeild(“對應的字段”)
????private String username;
????@TableFeild(“對應的字段”)
????private String email;
????@TableFeild(“對應的字段”)
????private Integer age;
????@TableField(對應的字段,fill = FieldFill.INSERT) ?// 插入時自動填充
????private LocalDateTime createTime;
????
????@TableField(對應的字段,fill = FieldFill.INSERT_UPDATE) ?// 插入和更新時自動填充
????private LocalDateTime updateTime;
????
????@TableLogic ?// 邏輯刪除字段
????private Integer deleted;
????
????@Version ?// 樂觀鎖版本號
private Integer version;
}
五、Mapper 接口定義
@Mapper
public interface UserMapper extends BaseMapper<User> {
????// 繼承 BaseMapper 后,自動擁有 CRUD 方法
// 可添加自定義方法
}
六、簡單測試方法
@SpringBootTest
public class UserMapperTest {
????@Autowired
????private UserMapper userMapper;
????
????@Test
????public void testSelectById() {
????????User user = userMapper.selectById(1L);
????????System.out.println(user);
????}
}
七、條件構造器處理復雜查詢
@SpringBootTest
public class QueryWrapperTest {
????@Autowired
????private UserMapper userMapper;
????
????@Test
????public void testComplexQuery() {
????????QueryWrapper<User> wrapper = new QueryWrapper<>();
????????wrapper
????????????.like("username", "張") ?????// 用戶名包含"張"
????????????.ge("age", 20) ?????????????// 年齡大于等于20
????????????.le("age", 30) ?????????????// 年齡小于等于30
????????????.orderByDesc("create_time") // 按創建時間降序
????????????.last("LIMIT 10"); ?????????// 追加SQL片段
????????
????????List<User> users = userMapper.selectList(wrapper);
????????users.forEach(System.out::println);
}
}
八、批處理操作
@SpringBootTest
public class BatchOperationTest {
????@Autowired
????private UserMapper userMapper;
????
????@Test
????@Transactional ?// 批量操作建議在事務中執行
????public void testBatchInsert() {
????????List<User> userList = new ArrayList<>();
????????for (int i = 0; i < 100; i++) {
????????????User user = new User();
????????????user.setUsername("test" + i);
????????????user.setEmail("test" + i + "@example.com");
????????????user.setAge(20 + i % 10);
????????????userList.add(user);
????????}
????????
????????// 批量插入
????????userList.forEach(userMapper::insert);
}
}
九、分頁查詢
先配置:
@Configuration
public class MybatisConfiguration {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //添加分頁攔截器到MybatisPlusInterceptor中
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor; }
?}
@SpringBootTest
public class PaginationTest {
????@Autowired
????private UserMapper userMapper;
????
????@Test
????public void testPagination() {
????????// 創建分頁對象,查詢第1頁,每頁10條
????????Page<User> page = new Page<>(1, 10);
????????
????????QueryWrapper<User> wrapper = new QueryWrapper<>();
????????wrapper.gt("age", 18);
????????
????????// 執行分頁查詢
????????Page<User> result = userMapper.selectPage(page, wrapper);
????????
????????System.out.println("總記錄數: " + result.getTotal());
????????System.out.println("總頁數: " + result.getPages());
????????System.out.println("當前頁數據: " + result.getRecords());
}
}
Page.of(1,2)
一共2頁,查看第一頁
十、增刪改操作
1. 新增數據
User user = new User();
user.setUsername("doubao");
user.setEmail("doubao@example.com");
user.setAge(25);
int rows = userMapper.insert(user); // 返回影響行數
System.out.println("新增用戶ID: " + user.getId());
2. 刪除數據
// 物理刪除
int rows = userMapper.deleteById(1L);
// 邏輯刪除(更新deleted字段)
int logicRows = userMapper.deleteById(2L);
3. 更新數據
User user = new User();
user.setId(1L);
user.setAge(26); // 只更新age字段
int rows = userMapper.updateById(user);
也可以使用UpdateWrapper<>來處理
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set(xxx,xxx).eq(xxx,xx)
mapper.update(null,wrapper)
十一、IService 接口的繼承與實現
1. 定義 Service 接口
public interface UserService extends IService<User> {
????// 繼承 IService 后,自動擁有基礎 CRUD 方法
????
????// 自定義方法
????List<User> findByAgeGreaterThan(Integer age);}
2. 實現 Service 接口
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
????@Override
????public List<User> findByAgeGreaterThan(Integer age) {
????????return baseMapper.selectList(new QueryWrapper<User>().gt("age", age));
}
}
3. 使用示例
@Autowired
private UserService userService;
@Test
public void testCustomServiceMethod() {
????List<User> users = userService.findByAgeGreaterThan(20);
users.forEach(System.out::println);
}
MyBatis-Plus 通過?BaseMapper?和?IService?接口提供了強大的 CRUD 能力,同時通過?條件構造器?簡化了復雜查詢。開發者可以在繼承基礎接口的同時,添加自定義方法,實現靈活擴展。
關鍵組件:
BaseMapper:提供基礎 CRUD 方法
IService:提供更高級的業務層方法(如批量操作)
ServiceImpl:默認實現類,集成 BaseMapper
Wrapper:強大的條件構造器,替代復雜 SQL
通過這種方式,MyBatis-Plus 大幅減少了樣板代碼,提高了開發效率,同時保留了 MyBatis 的靈活性。