当前位置: 首页 > news >正文

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

相关文章:

  • shell脚本之条件判断,循环控制,exit详解
  • NestJS——日志、NestJS-logger、pino、winston、全局异常过滤器
  • JDBC 的编写步骤及原理详解
  • 多指标组合策略
  • 什么情况下使用ActiveMQ
  • 【读代码】端到端多模态语言模型Ultravox深度解析
  • Flask项目实践:构建功能完善的博客系统(含评论与标签功能)
  • C++ 蓝桥 STEMA 真题模拟测试卷一(选择题)
  • FastMCP:为大语言模型构建强大的上下文和工具服务
  • 系统架构设计(九):分布式架构与微服务
  • 系统架构-大数据架构设计
  • 【2025 技术指南】如何创建和配置国际版 Apple ID
  • 一个可拖拉实现列表排序的WPF开源控件
  • nt!MiInitializePfn函数分析之nt!MiPfPutPagesInTransition函数的关键一步
  • 区块链基本理解
  • 淘宝商品主图标题api接口(附API接口文档)
  • 实验6分类汇总
  • uniapp-商城-61-后台 新增商品(添加商品到数据库)
  • C# DataGrid功能总览
  • 04_决策树
  • 英国警方再逮捕一名涉嫌参与首相住宅纵火案嫌疑人
  • 广西隆林突发山洪,致3人遇难1人失联
  • 用贝多芬八首钢琴三重奏纪念风雨并肩20年
  • 病重老人取钱在银行门口去世,家属:已协商一致
  • 泽连斯基与埃尔多安会面,称已决定派遣代表团前往伊斯坦布尔
  • 阿里上季度营收增7%:淘天营收创新高,AI产品营收连续七个季度三位数增长