Spring Boot- 2 (數萬字入門教程 ):數據交互篇

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 的靈活性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81729.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81729.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81729.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在 Kotlin 中,什么是內聯函數?有什么作用?

在 Kotlin 中&#xff0c;內聯函數是一種通過 inline 關鍵字聲明的函數&#xff0c;其主要目的是優化高階函數&#xff08;即以函數作為參數或返回值的函數&#xff09;的性能。 內聯函數的函數體會在編譯時直接插入到調用處&#xff0c;從而避免函數調用的開銷&#xff0c;并…

LLM筆記(五)概率論

1. 隨機變量與概率分布&#xff1a;模型輸出的基礎 在LLM中&#xff0c;隨機變量最直觀的體現就是模型預測的下一個token。每個時刻&#xff0c;模型都會輸出一個概率分布&#xff0c;表示詞匯表中每個token可能是"下一個詞"的概率。 直觀理解 想象模型在處理句子…

LeetCode-滑動窗口-找到字符串中所有字母異位詞

LeetCode-滑動窗口-找到字符串中所有字母異位詞 ?? 關于專欄&#xff1a;專欄用于記錄 prepare for the coding test。 文章目錄 LeetCode-滑動窗口-找到字符串中所有字母異位詞&#x1f4dd; 找到字符串中所有字母異位詞&#x1f3af;題目描述&#x1f50d; 輸入輸出示例&am…

PostgreSQL 初體驗

目錄 一、PostgreSQL 1. 簡介 2. 特點 &#xff08;1&#xff09; 開源免費&#xff08;Open Source&#xff09; &#xff08;2&#xff09;標準兼容&#xff08;SQL Compliance&#xff09; &#xff08;3&#xff09; 豐富的數據類型&#xff08;Data Types&#xff09…

05_核支持向量機

描述 核支持向量機&#xff08;通常簡稱為SVM&#xff09;可以推廣到更復雜模型的擴展&#xff0c;這些模型無法被輸入空間的超平面定義。 SVM 的核心思想是找到一個最優的超平面&#xff0c;將不同類別的數據分開。這個超平面不僅要能夠正確分類數據&#xff0c;還要使得兩個…

Java + 鴻蒙雙引擎:ZKmall開源商城如何定義下一代B2C商城技術標準?

在 B2C 電商領域持續革新的當下&#xff0c;技術架構的優劣成為決定商城競爭力的核心要素。ZKmall開源商城以其創新融合的 Java 與鴻蒙雙引擎&#xff0c;為下一代 B2C 商城技術標準勾勒出全新藍圖&#xff0c;在性能、兼容性、拓展性等關鍵維度實現了重大突破。 一、Java 技術…

關于 Web 漏洞原理與利用:3. CSRF(跨站請求偽造)

一、原理&#xff1a; 利用用戶登錄態偽造操作 CSRF&#xff08;Cross-Site Request Forgery&#xff0c;跨站請求偽造&#xff09;是攻擊者“借刀殺人”&#xff0c;借用用戶瀏覽器中已有的登錄狀態&#xff0c;誘導用戶完成攻擊者指定的操作。 1. 基本機制分解 1&#xf…

【HTML5】【AJAX的幾種封裝方法詳解】

【HTML5】【AJAX的幾種封裝方法詳解】 AJAX (Asynchronous JavaScript and XML) 封裝是為了簡化重復的異步請求代碼&#xff0c;提高開發效率和代碼復用性。下面我將介紹幾種常見的 AJAX 封裝方式。 方法1. 基于原生 XMLHttpRequest 的封裝 XMLHttpRequest。其主要特點如下…

C++ - 網絡編程之初始連接(Winsock2 概述、初始連接案例、初始連接案例解讀)

一、Winsock2 概述 Winsock2&#xff08;Windows Sockets 2&#xff09;是微軟提供的 Windows 平臺網絡編程庫 二、初始連接案例 1、Server #include <winsock2.h> #include <ws2tcpip.h> #include <iostream>#pragma comment(lib, "ws2_32.lib&quo…

Spring Cloud Gateway深度解析:原理、架構與生產實踐

文章目錄 前言一、概述二、核心架構設計及設計原理2.1 分層架構模型網絡層&#xff08;I/O模型&#xff09;核心處理層 2.2 核心組件協作流程路由定位階段過濾器執行階段 2.3 響應式編程模型實現Reactor上下文傳遞背壓處理機制 2.4 動態路由設計原理2.5 異常處理體系2.6 關鍵路…

游戲開發實戰(一):Python復刻「崩壞星穹鐵道」嗷嗚嗷嗚事務所---源碼級解析該小游戲背后的算法與設計模式【純原創】

文章目錄 奇美拉項目游戲規則奇美拉(Chimeras)檔案領隊成員 結果展示&#xff1a; 奇美拉項目 由于項目工程較大&#xff0c;并且我打算把我的思考過程和實現過程中踩過的坑都分享一下&#xff0c;因此會分3-4篇博文詳細講解本項目。本文首先介紹下游戲規則并給出奇美拉檔案。…

說一下響應狀態碼有哪些?

HTTP響應狀態碼分類(RFC 7231標準) 1. 1xx(信息類) 臨時響應,表示請求已被接收,需要繼續處理 100 Continue:客戶端應繼續發送請求體 101 Switching Protocols:服務器同意升級協議(如WebSocket) 102 Processing(WebDAV):服務器正在處理但未完成 2. 2xx(成功類)…

Linux多進程 寫時拷貝 物理地址和邏輯地址

如果不采用寫時拷貝技術 直接fork子進程 會發生什么&#xff1f; 如上圖所示 橙色為父進程所占內存空間 綠色為子進程所占內存空間。 如果子進程只是需要做出一點點和父進程不一樣的 其余和父進程均為相同 第一 就會出現復制開銷比較大&#xff1b;第二占用內存空間 所以 …

【TTS回顧】Bert-VITS2深度解析:融合BERT的多語言語音合成模型

一、基本介紹 Bert-VITS2是基于VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的改進版本,通過整合BERT語義編碼能力,顯著提升了語音合成的自然度和表現力。項目地址:https://github.com/fishaudio/Bert-VITS2 語種自然度相似度流…

win11下docker 的使用方案

Windows 11 Docker 使用方式對比 特性Docker Desktop (使用 WSL 2 后端)直接在 WSL 2 中安裝 Docker Engine安裝與易用性極簡&#xff0c;一鍵安裝&#xff0c;提供直觀的 GUI 界面 管理容器、鏡像、卷等相對復雜&#xff0c;需手動在 Linux 環境中安裝 Docker Daemon 并配置G…

配合本專欄前端文章對應的后端文章——從模擬到展示:一步步搭建傳感器數據交互系統

對應文章&#xff1a;進一步完善前端框架搭建及vue-konva依賴的使用&#xff08;Vscode&#xff09;-CSDN博客 目錄 一、后端開發 1.模擬傳感器數據 2.前端頁面呈現數據后端互通 2.1更新模擬傳感器數據程序&#xff08;多次請求&#xff09; 2.2&#x1f9e9; 功能目標 …

牛客網NC209794:使徒襲來

牛客網NC209794:使徒襲來 題目背景 問題分析 數學建模 設三位駕駛員的戰斗力分別為 a, b, c已知條件&#xff1a;a b c n (n為輸入的正整數)目標&#xff1a;求 a b c 的最小值 解題思路 根據算術-幾何平均值不等式(AM-GM不等式)&#xff0c;對于任意正實數a, b, c&a…

動態規劃之爬樓梯模型

文章目錄 爬樓梯模型LeetCode 746. 使用最小花費爬樓梯思路Golang 代碼 LeetCode 377. 組合總和 Ⅳ思路Golang 代碼 LeetCode 2466. 統計構造好字符串的方案數思路Golang 代碼 LeetCode 2266. 統計打字方案數思路Golang 代碼 爬樓梯模型 爬樓梯模型是動態規劃當中的一個經典模型…

【每天一個知識點】湖倉一體(Data Lakehouse)

“湖倉一體”&#xff08;Data Lakehouse&#xff09;是一種融合了數據湖&#xff08;Data Lake&#xff09;與數據倉庫&#xff08;Data Warehouse&#xff09;優勢的新型數據架構。它既繼承了數據湖對多類型數據的靈活存儲能力&#xff0c;也具備數據倉庫對結構化數據的高效查…

Linux | mdadm 創建軟 RAID

注&#xff1a;本文為 “Linux mdadm RAID” 相關文章合輯。 略作重排&#xff0c;未整理去重。 如有內容異常&#xff0c;請看原文。 Linux 下用 mdadm 創建軟 RAID 以及避坑 喵??&#xfecc;?? Oct 31, 2023 前言 linux 下組軟 raid 用 mdadm 命令&#xff0c;multi…