序言
由于项目可能部署到不同的数据库类型,使用mybatis操作简单,做不到一套SQL全部类型数据库可用(不求100%完美可用,但求尽可能少的修改)。目前部署的数据库类型有:
- MySQL5.7
- MySQL8.0.x
- Oracle9x
- Oracle10
- Oracle11g
- Oracle12c
- Oracle19c
- DB2-11.1.4
- DB2-11.1.5
- Postgres9
- Postgres12
如果只是遇到MySQL和Oracle还好点,一下涉及到这么多数据库类型,然后不同版本数据库可能还有点语法不太一样,使用MyBatis无疑会增加测试,开发的工作量,效率底下,本身不要求高并发,所以采用JPA的方式确实能减少很多工作,并且效率很高,QueryDSL更是可以为JPA插上翅膀,方便很多工作。
QueryDSL
官网地址
www.querydsl.com/static/quer… 最新的官方文档
搭建
1.引入依赖
<!--下面这些配置要配置到 @Entity注解所在的模块中的pom.xml里面,配置到其他的项目不行-->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
<project>
<build>
<plugins>
...
<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>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
</project>
复制代码
2.生成Qxxx类
引入QueryDSL依赖包之后,需要点击下maven构建,生成以Q开头的查询class
Maven这两个箭头,随便点击一个就行,结果如下图:
好奇心查看下生成的代码例子:
@Generated("com.querydsl.codegen.EntitySerializer")
public class QPermission extends EntityPathBase<Permission> {
private static final long serialVersionUID = 1115934067L;
public static final QPermission permission = new QPermission("permission");
public final StringPath dataScopes = createString("dataScopes");
public final StringPath depends = createString("depends");
public final BooleanPath display = createBoolean("display");
public final NumberPath<Integer> formMethod = createNumber("formMethod", Integer.class);
public final StringPath icon = createString("icon");
public final NumberPath<Integer> id = createNumber("id", Integer.class);
public final NumberPath<Integer> level = createNumber("level", Integer.class);
public final NumberPath<Integer> order = createNumber("order", Integer.class);
public final NumberPath<Integer> parentId = createNumber("parentId", Integer.class);
public final StringPath path = createString("path");
public final StringPath permissionCode = createString("permissionCode");
public final StringPath permissionName = createString("permissionName");
public final EnumPath<com.xuanwu.fgmp.common.enumeration.base.PermissionType> permissionType = createEnum("permissionType", com.xuanwu.fgmp.common.enumeration.base.PermissionType.class);
public final EnumPath<com.xuanwu.fgmp.common.enumeration.base.PlatformType> platformFlag = createEnum("platformFlag", com.xuanwu.fgmp.common.enumeration.base.PlatformType.class);
public final StringPath relevance = createString("relevance");
public final StringPath remark = createString("remark");
public QPermission(String variable) {
super(Permission.class, forVariable(variable));
}
public QPermission(Path<? extends Permission> path) {
super(path.getType(), path.getMetadata());
}
public QPermission(PathMetadata metadata) {
super(Permission.class, metadata);
}
}
复制代码
可以看到生成的都是些xxxxPath的对象,这个是为了后面组件JPAQuery做准备的!
使用
QueryDSL目前只支持:Update,Delete,Select操作,不支持Save操作,但是看官方文档有insert操作,这个目前没去试验!
准备两个表
/**
* 我们使用了lombok,只给出主键注解,其他省略了,代码太多了
* 这个是角色表
*/
@Entity
@Table(name = "role")
@Data
@Accessors(chain = true)
public class Role {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String remark;
private Boolean isDefault;
private Integer userId;
private Date createTime;
private Date updateTime;
}
复制代码
/**
* 用户信息表 无关的属性全给删除了
*/
@Entity
@Table(name = "user")
@Data
@Accessors(chain = true)
public class BaseUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
@Comment(comment = "主键,自增id")
private Integer id;
private Integer enterpriseId;
private String name;
private String account;
@Convert(converter = UserStateConverter.class)
private UserState state;
private Integer departmentId;
private Date createTime;
private Date updateTime;
}
复制代码
//角色和用户关联表,用户---多对多---角色 的关系
@Entity
@Table(name = "fgmp_user_role")
public class UserRole {
private Integer userId;
private Integer roleId;
}
复制代码
构造JPAQueryFactory
@Configuration
public class JPAQueryFactoryConfig {
@Autowired
@PersistenceContext
private EntityManager entityManager;
@Bean("jpaQueryFactory")
public JPAQueryFactory jpaQueryFactory(){
return new JPAQueryFactory(entityManager);
}
}
复制代码
单表操作
update
@Transactional
@Override
public boolean modifyUserById(Integer userId) {
QBaseUser user = QBaseUser.baseUser;//这个是配置QueryDSL之后自动生成的
return jpaQueryFactory.update(user)
.set(user.isRemove, true)
.set(user.name,"xxxx修改的名字信息")
.set(user.updateTime, new Date())
.where(user.id.eq(userId))//条件
.execute() == 1;
}
翻译成SQL:
update user
set name = xxx,is_remove=true,update_time='xxxxx日期'
where id = xxxx;
复制代码
delete
@Transactional
@Override
public boolean deleteUserById(Integer userId) {
QBaseUser user = QBaseUser.baseUser;//这个是配置QueryDSL之后自动生成的
return jpaQueryFactory.delete(user)
.where(user.id.eq(userId))//条件
.execute() == 1;
}
翻译成SQL
delete from user
where id = xxx;
复制代码
select
public void pageData(){
QBaseUser user = QBaseUser.baseUser;
List<BaseUser> pageDate = jpaQueryFactory.selectFrom(user)
.where(user.updateTime.between(new Date(), new Date()))
.where(user.isRemove.eq(false).or(user.id.gt(3)))
.orderBy(user.createTime.desc())
.offset(3)
.limit(10)
.fetch();
}
翻译成SQL(这个而是按照MySQL写的,其他数据库可能不一样):
select *
from user
where update_time between 日期1 and 日期2
and (is_remove = false or id >3)
order by create_time desc
limint 3,10;
注意,连着写.where(xxxx).where(xxxx)默认是and的关系,当然你可以这么写
.where(user.updateTime.between(new Date(), new Date()).and(user.isRemove.eq(false).or(user.id.gt(3))))
==
.where(user.updateTime.between(new Date(), new Date()))
.where(user.isRemove.eq(false).or(user.id.gt(3)))
复制代码
处理部分字段返回结果
public void pageData(){
QBaseUser user = QBaseUser.baseUser;
List<Tuple> tuples = jpaQueryFactory.select(user.account, user.name)
.from(user)
.where(user.id.gt(13))
.fetch();
List<SimpleUser> result = tuples.stream()
.map(tuple -> new SimpleUser()
.setAccount(tuple.get(user.account))//注意这个地方只能从上面select的字段才有数据
.setName(tuple.get(user.name)))
.collect(Collectors.toList());
}
@Data
@Accessors(chain = true)
class SimpleUser{
private String account;
private String name;
}
复制代码
连表操作
这个才是业务当中的重中之重
List<Tuple> result = jpaQueryFactory.select(user.id,
user.account,
user.name,
user.email,
department.name,
user.state)
.from(user)
.leftJoin(department)
.on(user.departmentId.eq(department.id))
.where(user.isRemove.eq(false))
.where(department.path.startsWith('xxx').or(department.id.eq(xid)))
.fetch();
翻译成SQL:
select user.id,user.account,user.name,user.email,department.name,user.state
from user left join department on user.department_id = department.id
where user.is_remove = fasle
and (department.path like '%xxx%' or department.id=xid);
这个返回结果也是List<Tuple> 自己像上面转化下就行!
复制代码
子查询
List<LoginToken> result = queryFactory.select(loginToken)
.where(loginToken.id.eq(JPAExpressions.select(app.id.max()).from(app)))
.fetch();
翻译成SQL:
select *
from loginToken
where loginToken.id = (select max(app.id)
from app);
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END