文章目录
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 |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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 | findByAgeIsNull | … 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 ? (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ? (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … 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上帮我点下 Star
【SpringBoot框架篇】其它文章如下,后续会继续更新。
- 1.搭建第一个springboot项目
- 2.Thymeleaf模板引擎实战
- 3.优化代码,让代码更简洁高效
- 4.集成jta-atomikos实现分布式事务
- 5.分布式锁的实现方式
- 6.docker部署,并挂载配置文件到宿主机上面
- 7.项目发布到生产环境
- 8.搭建自己的spring-boot-starter
- 9.dubbo入门实战
- 10.API接口限流实战
- 11.Spring Data Jpa实战
- 12.使用druid的monitor工具查看sql执行性能
- 13.使用springboot admin对springboot应用进行监控
- 14.mybatis-plus实战
- 15.使用shiro对web应用进行权限认证
- 16.security整合jwt实现对前后端分离的项目进行权限认证
- 17.使用swagger2生成RESTful风格的接口文档
- 18.使用Netty加websocket实现在线聊天功能
- 19.使用spring-session加redis来实现session共享
- 20.自定义@Configuration配置类启用开关
- 21.对springboot框架编译后的jar文件瘦身
- 22.集成RocketMQ实现消息发布和订阅
- 23.集成smart-doc插件零侵入自动生成RESTful格式API文档
- 24.集成FastDFS实现文件的分布式存储
- 25.集成Minio实现文件的私有化对象存储
- 26.集成spring-boot-starter-validation对接口参数校验
- 27.集成mail实现邮件推送带网页样式的消息
- 28.使用JdbcTemplate操作数据库
- 29.Jpa+vue实现单模型的低代码平台
- 30.使用sharding-jdbc实现读写分离和分库分表
- 31.基于分布式锁或xxx-job实现分布式任务调度
- 32.基于注解+redis实现表单防重复提交
- 33.优雅集成i18n实现国际化信息返回
- 34.使用Spring Retry完成任务的重试