【SpringBoot框架篇】11.Spring Data Jpa实战

1.简介

首先了解一下 JPA,Spring Data Jpa,之间的关系

1.1.JPA

JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
JPA包括以下3方面的技术:

  • ORM映射元数据: 支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系
  • API: 操作实体对象来执行CRUD操作
  • 查询语言: 通过面向对象而非面向数据库的查询语言(JPQL)查询数据,避免程序的SQL语句紧密耦合

1.2.Spring Data Jpa

下面引入官网的介绍
在这里插入图片描述

1.3.Hibernate

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任

1.4.Jpa、Spring Data Jpa、Hibernate三者之间的关系

Hibernate是Spring Data Jpa的默认实现方式
在这里插入图片描述

2.引入依赖

        <!--spring data jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--mysql依赖-->    
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

3.配置文件

server:
  port: 8011

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/jpa_db?createDatabaseIfNotExist=true&useSSL=false&serverTimezone=GMT%2b8&characterEncoding=utf8&connectTimeout=10000&socketTimeout=3000&autoReconnect=true&rewriteBatchedStatements=true
    username: root
    password: 123456
  jpa:
    database: mysql
    show-sql: true
    hibernate:
      #自动创建或修改表结构
      ddl-auto: update
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    properties:
      hibernate:
        #设置hibernate方言使用mysql的InnoDBD引擎,InnoDBD支持事务
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        #启用懒加载
        enable_lazy_load_no_trans: true

4.实体类常用注解

4.1.@Entity和@Table

@Entity
@Table(name = "sys_user")
public class User{}  
  • @Entity 表明该类 (User) 为一个实体类,它默认对应数据库中的表名是user。这里也可以写成
    @Entity(name = “sys_user”)
    或者
    @Entity
    @Table(name = “user”)
  • @Table 当实体类与其映射的数据库表名不同名时需要使用 @Table注解说明,该标注与 @Entity 注解并列使用

4.2.@Index

@Index注解用来添加表的索引,可以指定单个字段和多个字段,多个字段之间用 ’ , ’ 隔开

@Entity
@Table(name = "sys_user",indexes = {
        @Index(name = "username",  columnList = "username"),
        @Index(name = "address_age",  columnList = "address,age")
}
public class User{
	  private String username;
	  private String address;
	  private Integer age;
}

4.3.@Id和@GeneratedValue

  • @Id 标识此字段是主键
  • @GeneratedValue 设置主键的自增策略,默认是AUTO
    • TABLE 使用一个特定的数据库表格来保存主键。
    • SEQUENCE 根据底层数据库的序列来生成主键,条件是数据库支持序列。
    • IDENTITY 主键由数据库自动生成(主要是自动增长型)
    • AUTO 主键由程序控制。
  @Id
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  private Integer id;

4.4.@Column

@Column 注释定义了将成员属性映射到关系表中的哪一列和该列的结构信息,属性如下:

属性名描述
name映射的列名。如:映射tbl_user表的name列,可以在name属性的上面或getName方法上面加入;
unique是否唯一;
nullable是否允许为空;
length对于字符型列,length属性指定列的最大字符长度;
insertable是否允许插入;
updatable是否允许更新;
    @Column(name = "username", unique = true, nullable = false,updatable = false,length = 36)
    private String username;

4.5.@Transient

@Transien就是在给某个javabean上需要添加个属性,但是这个属性你又不希望给存到数据库中去,仅仅是做个临时变量,用一下。不修改已经存在数据库的数据的数据结构。

    @Transient
    private String ignoreColumn;

4.6.@Where

@Where可以在级联加载数据的时候根据条件筛选数据

public class OcrFileInfo{
    private Integer page;
}
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name="fileId",insertable = false, updatable = false)
//只查询page字段1~5页的数据
@Where(clause="page  between 1 and 5")
List<OcrFileInfo> ocrFileInfos;

4.7.@OrderBy

根据字段排序

public class OcrFileInfo{
    private Integer filed1;
    private Integer filed2;
}
//根据filed1字段升序排序,然后根据filed2字段降序排序
@OrderBy("filed1,filed2 desc")
List<OcrFileInfo> ocrFileInfos;

5.继承超类的通用字段属性

@Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)//选择继承策略
@MappedSuperclass
public class BaseModel implements Serializable {
	
	@Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
	private Date createdDate;
}
@Entity
@Table(name = "sys_user")
public class User extends  BaseModel{
	//这里就不用再写通用的字段了。
}  

5.1.@MappedSuperclass

  • 标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
  • .标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。
    我们可以把一些通用的表字段放到超类中定义

5.2.@Inheritance

Hibernate继承映射在 Annotation 中使用 @Inheritance 注解,并且需要使用 strategy 属性指定继承策略,继承策略有 SINGLE_TABLE、TABLE_PER_CLASS 和 JOINED 三种。

  • SINGLE_TABLE 是将父类和其所有的子类集合在一块,存在一张表中,并创建一个新的字段来判断对象的类型。
  • TABLE_PER_CLASS 是为每一个类创建一个表,这些表是相互独立的。
  • JOINED 是将父类、子类分别存放在不同的表中,并且建立相应的外键,以确定相互之间的关系

6.审计功能

我们一般对记录的创建和修改需要手动set操作时间
user.setCreateDate(new Date());
但是通过使用Jpa的审计功能,就可以交给Jpa去实现了.

6.1.启用审计功能

在启动类里添加注解

@EnableJpaAuditing
public class SpringDatajpaApplication {}

在需要使用的类上面添加审计监听器
在需要使用审计功能的类上面加@EntityListeners注解指定监听类为AuditingEntityListener
一般我们会这些审计的通用字段放到超类里面

@EntityListeners(AuditingEntityListener.class)
public class BaseModel {}

6.2.审计功能注解

  • @CreatedDate 在记录创建的时候自动插入创建时间
  • @CreatedBy 在记录创建的时候自动插入创建者名称
  • @LastModifiedDate 在记录修改的时候自动修改操作 时间
  • @LastModifiedBy 在记录修改的时候自动修改修改者名称

6.3.添加审计人

我这里写死了是admin,实际使用场景应该获取当前登录人的用户名

@Component
public class AuditorAwareImpl implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("admin");
    }
}
@Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)//选择继承策略
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseModel implements Serializable {
    @CreatedDate
    @Column(name = "created_date", updatable = false)
    private Date createdDate;

    @CreatedBy
    @Column(name = "created_by", updatable = false, length = 64)
    private String createdBy;

    @LastModifiedDate
    @Column(name = "updated_date")
    private Date updatedDate;

    @LastModifiedBy
    @Column(name = "updated_by", length = 64)
    private String updatedBy;
}
@Entity
@Table(name = "sys_user")
@Data
public class User  extends  BaseMode{
}

下面我插入一条数据,能看到审计字段也都自动插入了.
在这里插入图片描述
在这里插入图片描述

6.4.复合主键

在我们的日常开发中,有时候会用到数据库进行设计的时候,采用了复合主键来来保证唯一性,
hibernate的 @EmbeddedId 嵌入式主键应用于实体类或映射超类的持久字段或属性,以表示可嵌入类的组合主键。 可嵌入的类必须标注为 @Embeddable 下面介绍一下采用
下面以用户角色关联表介绍.

@Entity
@Table(name = "user_role")
@Data
public class UserRole {

    public UserRole(){ }

    public UserRole(Integer userId, Integer roleId){
    this.id=new PK(userId,roleId);
    }
    
    @EmbeddedId
    private PK id;
    
    /**
     * 联合主键
     */
    @Embeddable
    @Data
    public static class PK implements Serializable {

        public PK() { }

        public PK(int userId, Integer roleId) {
            this.userId = userId;
            this.roleId = roleId;
        }
        /**
         * 用户id
         */
        private Integer userId;

        /**
         * 角色id
         */
        private Integer roleId;
  }
}

7.Spring Data Jpa 接口使用详解

创建一个接口,然后继承JpaRepository<T,ID>,T是表对应的实体类,ID是主键的类型

public interface UserRepository extends JpaRepository<User,Integer> {}

7.1.JpaRepository默认提供的方法

我这边列出了一些常用的方法
@Autowired
UserRepository userRepository;
userRepository.findAll();
下面的方法可以直接通过userRepository直接调用

	//查询所有信息
 	List<T> findAll();
 	//保存并且刷新
    <S extends T> S saveAndFlush(S var1);
  	//根据主键删除
    void deleteById(ID var1);
    //根据实体对象删除
    void delete(T var1);
    //根据主键获取对象信息
    T getOne(ID var1);
    //添加或则修改
	<S extends T> S save(S var1);

7.2.查询创建Query Creation

Spring Data Jpa通过解析方法名创建查询,框架在进行方法名解析时,会先把方法名多余的前缀find…By, read…By, query…By, count…By以及get…By截取掉,然后对剩下部分进行解析,第一个By会被用作分隔符来指示实际查询条件的开始。 我们可以在实体属性上定义条件,并将它们与And和Or连接起来,从而创建大量查询:

关键字示例JPQL
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ? (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ? (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection age)… where x.age not in ?1
TRUEfindByActiveTrue()… where x.active = true
FALSEfindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

7.3.自定义查询@Query

7.3.1.位置参数绑定

下标重1开始

		@Query("select u from User u where u.username = ?1 and u.password = ?2")
		User getByUsernameAndPassword(String username, String password);

7.3.2.命名参数绑定

		@Query("select u from User u where u.username = :username and u.password = :password")
		User getByUsernameAndPassword(@Param("username")String username,@Param("password") String password);

7.3.3.原生查询Native Queries

需要在@Query注解中加nativeQuery = true
注意,from后面对应的是表名称,而不是实体类的名称

	    @Query(value = "select u.* from sys_user u where u.username = :username and u.password = :password",nativeQuery = true)
	    User getByUsernameAndPasswordSQl(@Param("username")String username,@Param("password") String password);

7.3.4.删除修改操作

单独使用@Query注解只是查询,如涉及到修改、删除则需要再加上@Modifying和@Transactional注解

	    @Transactional
	    @Modifying
	    @Query("delete from User  where id=?1")
	    void deleteByUserId(Integer id);

7.3.5 and(:查询条件 is null or 字段=:查询条件)

下面的hql查询是根据用户名或者手机号查询,当传入的查询条件字段值为null的时候对应的and 里的条件则不生效。

 @Query("select u from User u where 1=1 " +
            " and(:username is null or u.username=:username)" +
            " and(:mobile is null or u.mobile=:mobile)")
    User findByUserNameOrMobile(@Param("username")String username, @Param("mobile") String mobile);

测试数据

    /**
     * hql参数非空判断查询
     * 条件都为null的时候则查询所有,反之根据手机号和用户名两个条件查询
     * 用户名为null手机号不为null则根据手机号查询,反之同理
     */
    public void findByUserNameOrMobile() {
        String userName = "dominick_li";
        //String userName = null;
        //String mobile = "17600251493";
        String mobile = null;
        User user = userRepository.findByUserNameOrMobile(userName, mobile);
        System.out.println(user==null);
    }

7.4.分页查询

		Page<User> findAllByUsernameLike(String username, Pageable pageable);

构建Pageable 对象的方法

参数描述
page页码,重0开始
size每页显示的数量
direction排序类型, Sort.Direction.DESC是降序,Sort.Direction.ASC是升序
properties排序的字段,可变参数。
		//2.0版本之前
		new PageRequest(int page, int size);
		new PageRequest(int page, int size, Direction direction,String... properties);
		//2.0版本之后        
		PageRequest.of(int page, int size);
		PageRequest.of(int page, int size, Direction direction, String... properties);

完整代码

        Pageable pageable = PageRequest.of(0, 10, Sort.Direction.ASC, "id");
        Page<User> userPage = userRepository.findAllByUsernameLike("user%", pageable);
        System.out.println("总记录数"+userPage.getTotalElements()+",总页数"+userPage.getTotalPages());
        for (User user : userPage.getContent()) {
            System.out.println(user.getUsername());
        }

7.5.使用Specification进行动态参数查询

对于查询条件不固定的情况下,JPQL实现不了这种情况,这个时候要继承JpaSpecificationExecutor
接口来实现动态参数查询了.
JpaSpecificationExecutor接口主要的2个方法

	    List<T> findAll(@Nullable Specification<T> var1);
	    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

首先继承JpaSpecificationExecutor接口

public interface UserRepository extends JpaRepository<User,Integer>, JpaSpecificationExecutor {}

然后组装Specification对象

 		String startDate = "2020-05-22";
        String endDate = "2020-05-25";
        String username = "dominick";
        Specification<User> querySpecifi = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if (!StringUtils.isEmpty(startDate)) {
                    //大于或等于传入时间
                    predicates.add(cb.greaterThanOrEqualTo(root.get("createDate").as(String.class), startDate));
                }
                if (!StringUtils.isEmpty(endDate)) {
                    //小于或等于传入时间
                    predicates.add(cb.lessThanOrEqualTo(root.get("endDate").as(String.class), endDate)));
                }
                if (!StringUtils.isEmpty(username)) {
                    //模糊查询,需要自己手动拼接%%字符
                    predicates.add(cb.like(root.get("username").as(String.class), "%" + username + "%"));
                }
                // and到一起的话所有条件就是且关系,or就是或关系
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        List<User> userList = userRepository.findAll(querySpecifi);

7.6.复杂的原生sql查询

通过EntityManagerFactory构建原生sql查询
下面只是简单的示范了怎么用,然后可以根据需求写对应的sql,能用sql解决的都不是难事。。

public interface UserCustomRepository {
    List<Object[]> findBynativeQuery(User user);
}

@Component
public class UserCustomImplRepsotory implements UserCustomRepository {

    private EntityManagerFactory emf;

    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }

    @Override
    public List<Object[]> findBynativeQuery(User user) {
        EntityManager em = emf.createEntityManager();
        try {
            Query query = null;
            StringBuilder sql = new StringBuilder("select * from sys_user  where 1=1 ");
            List<Object> condition = new ArrayList<>();
            int index = 0;
            if (!StringUtils.isEmpty(user.getUsername())) {
                index++;
                condition.add(user.getUsername());
                sql.append(" and username=?" + index);
            }
            if (!StringUtils.isEmpty(user.getChannelId())) {
                index++;
                condition.add(user.getChannelId());
                sql.append(" and channelId=?" + index);
            }
            //创建query对象
            query = em.createNativeQuery(sql.toString());
            //注入参数
            if (index != 0) {
                for (int i = 1; i <= index; i++) {
                    //query的parameter 下标起始位置重1开始的
                    query.setParameter(i, condition.get(i - 1));
                }
            }
            List<Object[]> success = query.getResultList();
            em.close();
            return success;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }
}

调用代码

		@Autowired
	    UserCustomImplRepsotory userCustomImplRepsotory;
   
  		User user=new User();
        user.setUsername("dominick_li");
        user.setChannelId(1);
        List<Object[]>  list=userCustomImplRepsotory.findBynativeQuery(user);
        for(Object[] objs:list){
            System.out.println(objs[0]+","+objs[1]);
        }

7.7. 多表字段映射查询

当需要查询多表的数据的时候,可以通过自定义字段然后去映射注入,例如下面查询用户表的用户名称和角色Id关联的角色名称。

public class UserVO {
    private String username;
    private String roleName;
    public UserVO(String username, String roleName) {
        this.username = username;
        this.roleName = roleName;
    }
}    
    @Query(value="select new com.ljm.boot.springdatajpa.model.UserVO(u.username,r.roleName) from User u left join Role  r on u.roleId=r.id")
    List<UserVO> findAllUserVO();

8.级联加载信息

下面级联查询我都用了懒加载
fetch = FetchType.LAZY
需要在配置文件把懒加载的开关打开

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true #开启懒加载

8.1.一对一

使用@OneToOne注解实现一对一的关系映射
@JoinColumn中的name标识当前实体的外键字段,referencedColumnName标识用户表roleId和Role表的关联字段。
我这里用 用户表和角色表介绍,省略了其它字段和注解,只描述重点

public class User {
	private Integer roleId;
	@OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="roleId",referencedColumnName="id",insertable = false, updatable = false)
    private Role role;
}
public class Role(
	private Integer id;
	private String roleName;
)

用户表数据
在这里插入图片描述
角色表数据
在这里插入图片描述
测试结果

       User user=userRepository.getOne(id);;
       System.out.println("角色名称是:"+user.getRole().getRoleName());

在这里插入图片描述

8.2.一对多

一对多使用 @OneToMany 注解实现一对一关系映射
@JoinColumn name属性指的是多的一方外键,也就是用户表的channelId属性,referencedColumnName表示当前类和用户类关联的列,默认是主键
我这里使用渠道表和用户表介绍

public class User {
	private Integer channelId;
}
public class Channel {
	
    private Integer id;
    private String channelName;

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name="channelId")
    private List<User> users;
}

渠道表数据
在这里插入图片描述
用户表数据
在这里插入图片描述
测试级联查询

        Channel channel = channelRepository.getOne(id);
        System.out.println(channel.getChannelName() + "有" + channel.getUsers().size() + "个用户");

在这里插入图片描述

8.3.多对一

多对一使用 @ManyToOne 注解进行关系映射
@JoinColumn name属性指的是多的一方外键,也就是user表的channelId属性,referencedColumnName表示渠道表和用户关联的列,默认是主键
我这里使用用户表和渠道表作介绍

public class User{
	 private Integer id;
	 private Integer channelId;
	  @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="channelId",referencedColumnName="id",insertable = false, updatable = false)
    private Channel channel;
}

private class Channel{
	private Intger id;
	private String channelName;
}

用户表数据
在这里插入图片描述
渠道表数据
在这里插入图片描述
测试级联加载结果

        User user=userRepository.getOne();
        System.out.println("渠道名称是:"+user.getChannel().getChannelName());

在这里插入图片描述

8.4.多对多

多对多关系用 @ManyToMany 注解进行关系映射
还需要依赖@JoinTable注解关联 关系表

public  class User{
	private int id;
	@ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "user_role", joinColumns = {@JoinColumn(name = "userId")},
            inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<Role> roles;
}
public class Role{
	private int id;
}

public class UserRole{
	private Intger userId;
	private Intger roleId;
}

用户表
在这里插入图片描述
角色表
在这里插入图片描述
用户角色关系表
在这里插入图片描述
测试级联加载结果

       User user=userRepository.getOne();
       System.out.println("用户拥有:"+user.getRoles().size()+"个角色");

在这里插入图片描述

8.5.不生成外键

可以根据需求决定是否取消外键的生成,在@JoinColumn注解中添加foreignKey = @ForeignKey(name = “null”, value = ConstraintMode.NO_CONSTRAINT)

public class Menu{
private Integer id;
private Integer parentId;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name="parentId",referencedColumnName="id",foreignKey =  @ForeignKey(name = "null", value = ConstraintMode.NO_CONSTRAINT) )
private List<Menu> children;
}

9.开启jpa SaveAll批量新增或修改操作

jpa默认的saveAll是在里面通过while不停的调用 save方法,假设要添加500条数据,则需要
执行500条insert语句才能完成操作,sql执行时间会长,jpa提供了批量执行sql的功能,下面
我来带大家开启批处理功能
在这里插入图片描述

9.1.配置文件

注意: @Transactional注解会导致批处理失败

spring:
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 50
        #检测批处理开关是否打开
        generate_statistics: true
属性描述
batch_size设置批处理一次处理多少条数据,如果大小设置为50,假设执行saveAll的数据300条,则需要执行6次sql才能处理完请求。
generate_statistics是否检测批处理开关是否打开

9.2.测试代码

注意: 如果设置主键为自增类型,则批处理还是会失效。如果想使用批处理,尽量用雪花算法生成ID或者UUID

Model

@Entity
@Table(name = "orders")
@Data
public class Orders  {
    @Id
    private String id;
    private String orderName;
}

Dao层

public interface OrdersRepository extends JpaRepository<Orders,String> {
}

web层

@RestController
public class OrdersController {
    @Autowired
    OrdersRepository ordersRepository;
    @RequestMapping("/saveAll")
    public String saveAll(){
        Orders orders=null;
        List<Orders> ordersList=new ArrayList<>(100);
        for(int i=0;i<300;i++){
            orders=new Orders();
            //订单表的主键应该使用雪花算法之类生成,雪花算法生成的id是有序的,这样索引查询起来会快很多,uuid是无序的,查询效率极低。。。。
            orders.setId(UUID.randomUUID().toString());
            orders.setOrderName("订单_"+1);
            ordersList.add(orders);
        }
        ordersRepository.saveAll(ordersList);
        return "success";
    }

}

9.3.开启批处理前

SQL Stat View JSON API 是druid连接池的一个监控工具,我会在下一章博客教大家使用
可以看到下面执行数是300
在这里插入图片描述

9.4.开启批处理后

可以看到sql执行数是6,和我们预期的一致。
在这里插入图片描述
下面是控制打印的
在这里插入图片描述

10.项目配套代码

gitee代码地址

创作不易,要是觉得我写的对你有点帮助的话,麻烦在gitee上帮我点下 Star

【SpringBoot框架篇】其它文章如下,后续会继续更新。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皓亮君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值