springboot + querydsl 入门到会用
自从邂逅了spring-data-jpa
+ querydsl
这个组合后,我再也没用过mybatis
。
QueryDsl简单了解
QueryDSL可以在任何支持的ORM
框架或者SQL
平台上以一种通用的API方式来构建查询。目前QueryDSL支持的平台包括JPA
,JDO
,SQL
,Mongodb
等等。
官网
Gitthub
https://github.com/querydsl/querydsl
入门到会用
这个教程是演示querydsl
+ spring-data-jpa
整合使用(其他的我也不会)。对于spring-data-jpa
,如果你不熟悉也没太大的关系,不影响使用querydsl
。
开始之前,这里要做一些说明。
这里不会涉及太多JPA相关的东西
QueryDsl和jpa
整合其实很简单(就几行代码)。但是jap
和springboot
的整合会涉及很多的配置属性,代码。这里不会过多的去解释它们。
实体类建模不采用面向对象的思想建模
JPA
让人讨厌的很大一个原因是因为那一堆 @OnToOne
, @OneToMany
。。。等关系描述。并且由此带来诸多的概念:延迟加载,级联删除,级联保存,孤儿删除。。。更是头疼不已。代码是死的,人是活的,不一定非要墨守成规。不用面向对象思想建模,就彻底解决了这些关联问题。
演示工程的创建
在编辑器初始化工程的过程,省略。
Maven完整的核心依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.springboot.querydsl</groupId>
<artifactId>springboot-querydsl</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<skipTests>true</skipTests>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- 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>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- QueryDsl -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<!-- QueryDsl代码生成插件 -->
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<!-- 查询对象的生成路径 -->
<outputDirectory>target/generated-sources/java</outputDirectory>
<!-- 生成查询对象的处理器, 使用JPA-->
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
除了jpa
和必须的依赖(驱动,连接池)以外,querydsl
只有3个组件。俩依赖,一个插件。插件的功能在于,在maven打包的时候,根据实体类生成查询对象。
配置文件
server:
port: 80
logging:
level:
root: DEBUG
# 在日志中输SQL参数的绑定信息
'org.hibernate.type.descriptor.sql.BasicBinder': TRACE
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/querydsl?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=true
username: root
password: root
data:
jpa:
repositories:
enabled: true
bootstrap-mode: default
jpa:
# 指定关系型数据库的方言
database-platform: org.hibernate.dialect.MySQL57Dialect
# 不在视图层维护连接
open-in-view: false
# 日志中输出SQL
show-sql: false
properties:
# 格式化日志中输出的SQL
hibernate.format_sql: false
hibernate:
# SQL建表策略: UPDATE
ddl-auto: update
这基本都是spring-data-jpa
相关的一些配置,特别的地方,都写上了注释。很好理解。
JPAQueryFactoryConfiguration
JPA整合QueryDsl,其实就这点代码
package io.springboot.querydsl.configuration;
import javax.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.querydsl.jpa.impl.JPAQueryFactory;
@Configuration
public class JPAQueryFactoryConfiguration {
@Bean
public JPAQueryFactory jpaQueryFactory(@Autowired EntityManager entityManager) {
return new JPAQueryFactory(entityManager);
}
}
实体类
建模,这里定义了4
个实体类,描述了常见的一对多
,多对多
关系。
-
BaseEntity
抽象出公共的字段 -
User
用户 -
Email
用户邮箱一对多关联 -
Role
角色 -
UserRole
用户角色多对多关联
这里省略了Getter/Setter 方法
BaseEntity
package io.springboot.querydsl.entity;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 7054150882445633369L;
// 创建时间
@Column(columnDefinition = "timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'", nullable = false)
private LocalDateTime createdDate;
// 最后修改时间
@Column(columnDefinition = "timestamp NULL DEFAULT NULL COMMENT '最后一次修改时间'")
private LocalDateTime lastModifiedDate;
}
User
package io.springboot.querydsl.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
@Entity
@Table(name = "user", indexes = {
@Index(name = "name", columnList = "name", unique = true),
})
@org.hibernate.annotations.Table(appliesTo = "user", comment = "用户")
public class User extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = -5342379801159855228L;
@Id
@Column(columnDefinition = "INT(11) UNSIGNED COMMENT 'id'")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// 昵称
@Column(columnDefinition = "VARCHAR(20) COMMENT '昵称'", nullable = false)
private String name;
// 性别
@Column(columnDefinition = "TINYINT(1) unsigned COMMENT '性别。0:女,1:男,2:未知'", nullable = false)
private Gender gender;
// 账户是否已经验证
@Column(columnDefinition = "TINYINT(1) unsigned COMMENT '账户是否已经验证'", nullable = false)
private Boolean validated;
// 性别枚举
public static enum Gender {
GIRL, BOY, UNKNOWN
}
}
package io.springboot.querydsl.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
@Entity
@Table(name = "email", indexes = {
@Index(name = "userEmailAccount", columnList = "user_id,account", unique = true),
@Index(name = "account", columnList = "account")
})
@org.hibernate.annotations.Table(appliesTo = "email", comment = "用户邮箱")
public class Email extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = -730436482990380359L;
@Id
@Column(columnDefinition = "INT(11) UNSIGNED COMMENT 'id'")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// 用户id
@Column(name = "user_id", columnDefinition = "INT(11) UNSIGNED COMMENT '用户id'")
private Integer userId;
// 邮箱账户
@Column(name = "account", columnDefinition = "VARCHAR(20) COMMENT '昵称'", nullable = false)
private String account;
}
Role
package io.springboot.querydsl.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
@Entity
@Table(name = "role", indexes = {
@Index(name = "name", columnList = "name", unique = true),
})
@org.hibernate.annotations.Table(appliesTo = "role", comment = "角色")
public class Role extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = 1749885146919803064L;
@Id
@Column(columnDefinition = "INT(11) UNSIGNED COMMENT 'id'")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// 名称
@Column(columnDefinition = "VARCHAR(20) COMMENT '名称'", nullable = false)
private String name;
}
UserRole
package io.springboot.querydsl.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.IdClass;
import javax.persistence.Index;
import javax.persistence.Table;
@Entity
@Table(name = "user_role", indexes = {
@Index(name = "roleId", columnList = "role_id"),
})
@org.hibernate.annotations.Table(appliesTo = "user_role", comment = "用户角色关联")
@IdClass(UserRole.Id.class)
public class UserRole extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = 1782979029236838525L;
@Column(name = "user_id", columnDefinition = "INT(11) UNSIGNED COMMENT '用户ID'", nullable = false)
@javax.persistence.Id
private Integer userId;
@javax.persistence.Id
@Column(name = "role_id", columnDefinition = "INT(11) UNSIGNED COMMENT '角色ID'", nullable = false)
private Integer roleId;
public static class Id implements Serializable {
private static final long serialVersionUID = 2751217704686895162L;
private Integer userId;
private Integer roleId;
public Id() {
}
public Id(Integer userId, Integer roleId) {
super();
this.userId = userId;
this.roleId = roleId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((roleId == null) ? 0 : roleId.hashCode());
result = prime * result + ((userId == null) ? 0 : userId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Id other = (Id) obj;
if (roleId == null) {
if (other.roleId != null)
return false;
} else if (!roleId.equals(other.roleId))
return false;
if (userId == null) {
if (other.userId != null)
return false;
} else if (!userId.equals(other.userId))
return false;
return true;
}
}
}
Repository
BaseRepository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface BaseRepository<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T>, QuerydslPredicateExecutor<T> {
}
其他的几个Repository
package io.springboot.querydsl.repository;
import io.springboot.querydsl.entity.User;
public interface UserRepository extends BaseRepository<User, Integer>{
}
package io.springboot.querydsl.repository;
import io.springboot.querydsl.entity.Email;
public interface EmailRepository extends BaseRepository<Email, Integer> {
}
package io.springboot.querydsl.repository;
import io.springboot.querydsl.entity.Role;
public interface RoleRepository extends BaseRepository<Role, Integer> {
}
package io.springboot.querydsl.repository;
import io.springboot.querydsl.entity.UserRole;
public interface UserRoleRepository extends BaseRepository<UserRole, UserRole.Id> {
}
Service
BaseService
package io.springboot.querydsl.service;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
public interface BaseService <T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor <T>, QuerydslPredicateExecutor<T> {
}
AbstractService
package io.springboot.querydsl.service;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.springboot.querydsl.repository.BaseRepository;
public class AbstractService<T, ID> implements BaseService <T, ID>{
@Autowired
protected BaseRepository<T,ID> baseRepository;
@Autowired
protected JPAQueryFactory jpaQueryFactory;
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public List<T> findAll() {
return this.baseRepository.findAll();
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public List<T> findAll(Sort sort) {
return this.baseRepository.findAll(sort);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public List<T> findAllById(Iterable<ID> ids) {
return this.baseRepository.findAllById(ids);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public <S extends T> List<S> saveAll(Iterable<S> entities) {
return this.baseRepository.saveAll(entities);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void flush() {
this.baseRepository.flush();
}
@Transactional(rollbackFor = Throwable.class)
public <S extends T> S saveAndFlush(S entity) {
return this.baseRepository.saveAndFlush(entity);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void deleteInBatch(Iterable<T> entities) {
this.baseRepository.deleteInBatch(entities);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void deleteAllInBatch() {
this.baseRepository.deleteAllInBatch();
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public T getOne(ID id) {
return this.baseRepository.getOne(id);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <S extends T> List<S> findAll(Example<S> example) {
return this.baseRepository.findAll(example);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
return this.baseRepository.findAll(example, sort);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Page<T> findAll(Pageable pageable) {
return this.baseRepository.findAll(pageable);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public <S extends T> S save(S entity) {
return this.baseRepository.save(entity);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Optional<T> findById(ID id) {
return this.baseRepository.findById(id);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public boolean existsById(ID id) {
return this.baseRepository.existsById(id);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public long count() {
return this.baseRepository.count();
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void deleteById(ID id) {
this.baseRepository.deleteById(id);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void delete(T entity) {
this.baseRepository.delete(entity);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void deleteAll(Iterable<? extends T> entities) {
this.baseRepository.deleteAll(entities);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void deleteAll() {
this.baseRepository.deleteAll();
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <S extends T> Optional<S> findOne(Example<S> example) {
return this.baseRepository.findOne(example);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
return this.baseRepository.findAll(example, pageable);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <S extends T> long count(Example<S> example) {
return this.baseRepository.count(example);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <S extends T> boolean exists(Example<S> example) {
return this.baseRepository.exists(example);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Optional<T> findOne(Specification<T> spec) {
return this.baseRepository.findOne(spec);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public List<T> findAll(Specification<T> spec) {
return this.baseRepository.findAll(spec);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
return this.baseRepository.findAll(spec, pageable);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public List<T> findAll(Specification<T> spec, Sort sort) {
return this.baseRepository.findAll(spec, sort);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public long count(Specification<T> spec) {
return this.baseRepository.count(spec);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Optional<T> findOne(Predicate predicate) {
return this.baseRepository.findOne(predicate);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Iterable<T> findAll(Predicate predicate) {
return this.baseRepository.findAll(predicate);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Iterable<T> findAll(Predicate predicate, Sort sort) {
return this.baseRepository.findAll(predicate, sort);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
return this.baseRepository.findAll(predicate, orders);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Iterable<T> findAll(OrderSpecifier<?>... orders) {
return this.baseRepository.findAll(orders);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public Page<T> findAll(Predicate predicate, Pageable pageable) {
return this.baseRepository.findAll(predicate, pageable);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public long count(Predicate predicate) {
return this.baseRepository.count(predicate);
}
@Override
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public boolean exists(Predicate predicate) {
return this.baseRepository.exists(predicate);
}
// 自定义的2个方法,用于在事务中获取到JPAQueryFactory,执行自定义的查询逻辑
@Transactional(rollbackFor = Throwable.class)
public <R> R apply(Function<JPAQueryFactory, R> function) {
return function.apply(this.jpaQueryFactory);
}
@Transactional(readOnly = true, rollbackFor = Throwable.class)
public <R> R applyReadOnly(Function<JPAQueryFactory, R> function) {
return function.apply(this.jpaQueryFactory);
}
}
其他的几个Service
package io.springboot.querydsl.service;
import org.springframework.stereotype.Service;
import io.springboot.querydsl.entity.User;
@Service
public class UserService extends AbstractService<User, Integer> {
}
package io.springboot.querydsl.service;
import org.springframework.stereotype.Service;
import io.springboot.querydsl.entity.Email;
@Service
public class EmailService extends AbstractService<Email, Integer> {
}
package io.springboot.querydsl.service;
import org.springframework.stereotype.Service;
import io.springboot.querydsl.entity.Role;
@Service
public class RoleService extends AbstractService<Role, Integer>{
}
package io.springboot.querydsl.service;
import org.springframework.stereotype.Service;
import io.springboot.querydsl.entity.UserRole;
@Service
public class UserRoleService extends AbstractService<UserRole, UserRole.Id> {
}
Application启动类
package io.springboot.querydsl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EnableJpaRepositories(basePackages = { "io.springboot.querydsl.repository" })
@EntityScan(basePackages = { "io.springboot.querydsl.entity" })
public class QueryDslAppliccation {
public static void main(String[] args) {
SpringApplication.run(QueryDslAppliccation.class, args);
}
}
Maven打包
执行MAVEN打包,插件会在指定目录下生成查询对象,以Q开头。
启动工程自动创建数据表
如果启动过程没有异常的话,就会根据实体类在数据库自动的创建数据表(因为配置了自动建表策略)。
CREATE TABLE `email` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modified_date` timestamp NULL DEFAULT NULL COMMENT '最后一次修改时间',
`account` varchar(20) NOT NULL COMMENT '昵称',
`user_id` int(11) unsigned DEFAULT NULL COMMENT '用户id',
PRIMARY KEY (`id`),
UNIQUE KEY `userEmailAccount` (`user_id`,`account`),
KEY `account` (`account`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户邮箱';
CREATE TABLE `role` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modified_date` timestamp NULL DEFAULT NULL COMMENT '最后一次修改时间',
`name` varchar(20) NOT NULL COMMENT '名称',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色';
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modified_date` timestamp NULL DEFAULT NULL COMMENT '最后一次修改时间',
`gender` tinyint(1) unsigned NOT NULL COMMENT '性别。0:女,1:男,2:未知',
`name` varchar(20) NOT NULL COMMENT '昵称',
`validated` tinyint(1) unsigned NOT NULL COMMENT '账户是否已经验证',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户';
CREATE TABLE `user_role` (
`role_id` int(11) unsigned NOT NULL COMMENT '角色ID',
`user_id` int(11) unsigned NOT NULL COMMENT '用户ID',
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modified_date` timestamp NULL DEFAULT NULL COMMENT '最后一次修改时间',
PRIMARY KEY (`role_id`,`user_id`),
KEY `roleId` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联';
本篇总结
这里这里大篇幅的东西 都是 spring-data-jpa
相关的,QueryDsl的整合其实就几个东西
- 导入相关依赖
- 把
JPAQueryFactory
添加倒IOC(学QueryDsl,本质上就是学怎么用它)