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; }

}

  1. 课程实体(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 | 学生年龄 |

  1. courses 表

|-------------|---------|------|
| 字段名 | 类型 | 描述 |
| id | BIGINT | 主键 |
| course_name | VARCHAR | 课程名称 |
| credits | INT | 学分 |

  1. 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("[email protected]");

user.setAge(25);

int rows = userMapper.insert(user); // 返回影响行数

System.out.println("新增用户ID: " + user.getId());

  1. 删除数据

// 物理删除

int rows = userMapper.deleteById(1L);

// 逻辑删除(更新deleted字段)

int logicRows = userMapper.deleteById(2L);

  1. 更新数据

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);}

  1. 实现 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));

}

}

  1. 使用示例

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

相关推荐
老华带你飞12 分钟前
实习记录小程序|基于SSM+Vue的实习记录小程序设计与实现(源码+数据库+文档)
java·数据库·spring boot·小程序·论文·毕设·实习记录小程序
my_styles1 小时前
docker-compose部署项目(springboot服务)以及基础环境(mysql、redis等)ruoyi-ry
spring boot·redis·后端·mysql·spring cloud·docker·容器
编程、小哥哥1 小时前
互联网大厂Java面试:从Spring Boot到微服务架构的技术深挖
java·spring boot·redis·微服务·prometheus·面试技巧
免檒2 小时前
go语言协程调度器 GPM 模型
开发语言·后端·golang
不知道写什么的作者3 小时前
Flask快速入门和问答项目源码
后端·python·flask
caihuayuan53 小时前
生产模式下react项目报错minified react error #130的问题
java·大数据·spring boot·后端·课程设计
编程、小哥哥3 小时前
Java大厂面试:从Web框架到微服务技术的场景化提问与解析
java·spring boot·微服务·面试·技术栈·数据库设计·分布式系统
苹果酱05676 小时前
React方向:react脚手架的使用
java·vue.js·spring boot·mysql·课程设计
不再幻想,脚踏实地7 小时前
Spring AOP从0到1
java·后端·spring