Joya 是对
Spring Data JPA
扩展,JPA本身功能已经很强大了,但是复杂查询语句HQL
通常都是大量字符串拼接,不利于维护和阅读,提供优雅、易读和强大的链式查询语句的Joya
应运而生
- 基于
Hibernate NativeQuery
进行扩展,支持全字段查询和指定字段查询,支持多种风格灵活易用 - 兼容JPA,可插拔式集成,无需修改任何代码,不影响
JPA和Hibernate
原有功能和特性 - 作为 JPA 的扩展和增强,兼容 Spring Data JPA 原有功能和各种特性
- 拥有使用原生SQL语句的极致体验
- SQL结果可返回指定对象实体,同样支持单个字段返回包装类和
String
类 - 可扩展性强,兼容其他ORM框架底层工作量小
适用于 使用Java Spring Data JPA
和JDK 1.8
及以上的项目,完美兼容Spring Boot 2.x
Maven Project
<dependency>
<groupId>com.sondertara</groupId>
<artifactId>joya</artifactId>
<version>0.2.0</version>
</dependency>
Gradle Project
implementation 'com.sondertara:joya:0.2.0'
以Spring boot
项目为例,注入Bean.
@Bean
public JoyaRepositoryFactoryBean joyaRepositoryFactoryBean(){
return new JoyaRepositoryFactoryBean();
}
通过 JoyaRepositoryFactoryBean 会注入 JoyaRepository
和JoyaSpringContext
(一个Spring全局类)
joya:
# 是否打印sql日志
sql-view: true
Joya 主要提供NativeSqlQuery 来处理查询语句,关于使用有如下特殊说明:
select,from和where语句中都可以使用原生sql字符串方式来拼接查询
Joya默认会为表生成别名,按照表在select和where部分第一次出现的顺序(select),别名依次为 t0,t1... 如果要添加自定义的sql,请使用表别名
对于联表查询到实体,避免字段冲突。如果有相同的column字段,默认会使用第一个表中的值映射到目标实体,也可以为字段指定别名来都映射到目标实体
针对where语句中的subQuery,如果where是AND查询则subQuery联接条件为OR,反之where联接为OR,subQuery则为AND
// SQL编写风格
NativeSqlQuery query = NativeSqlQuery.builder()
.select()
.from()
.where()
.groupBy()
.having()
.orderBy()
.build();
JoyaRepository中方法摘要
/**
* 查询list
* @param sql 原生sql
* @param clazz 目标实体
* @param params 参数
* @param <T> 泛型
* @return list
*/
@SuppressWarnings("unchecked")
public<T> List<T> findListBySql(String sql,Class<T> clazz,Object...params);
/**
* find to list
* @param nativeSql native query
* @param resultClass result class
* @param <T> generic
* @return list
*/
@SuppressWarnings("unchecked")
public<T> List<T> findListBySql(NativeSqlQuery nativeSql,Class<T> resultClass);
/**
* 分页查询
*
* @param resultClass 查询结果接收class
* @param queryParam 查询数据
* @param targetClass 查询数据库表
* @param <T> 泛型
* @return 分页数据
*/
public<T> PageResult<T> queryPage(PageQueryParam queryParam,Class<T> resultClass,Class<?>...targetClass)
/**
* 分页查询
*
* @param resultClass 查询结果接收class
* @param queryParam 查询数据
* @param <T> 泛型
* @param joinPart join语句
* @return 分页数据
*/
public<T> PageResult<T> queryPage(PageQueryParam queryParam,Class<T> resultClass,UnaryOperator<JoinCriterion> joinPart)
/**
* 通过sql 分页查询
*
* @param nativeSql 查询语句
* @param resultClass 结果映射class
* @param pageNo page
* @param pageSize pageSize
* @param <T> result
* @return result
*/
@SuppressWarnings("unchecked")
public<T> PageResult<T> queryPage(NativeSqlQuery nativeSql,Class<T> resultClass,Integer pageNo,Integer pageSize)
- 查询全部字段
public class Test {
/**
* 等同于select * from xxx , 默认表中的字段全部列出
*/
@Test
public void testSelectAll() {
// SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age FROM user AS t0 WHERE t0.user_name = ?1
//使用function函数和 entity对于的class类
NativeSqlQuery query = NativeSqlQuery.builder()
.select()
.from(UserPo.class)
.where(w -> w.eq(UserPo::getUserName, "张三"))
.build();
//使用字符串格式
NativeSqlQuery query = NativeSqlQuery.builder()
.select()
.from("user AS t0")
.where(w -> w
//.eq("t0.user_name","张三")) 下划线格式
.eq("t0.userName", "张三")) //驼峰格式
.build();
// 映射到UserDTO
List<UserDTO> list = joyaRepository.findListBySql(query, UserDTO.class);
}
}
- 指定字段
public class Test {
@Test
public void testSelectSome() {
// SELECT t0.id, t0.user_name FROM user AS t0 WHERE t0.user_name = ?1
// 使用function函数接口 支持选择1-12个字段
NativeSqlQuery query = NativeSqlQuery.builder()
.select(UserPo::getId, UserPo::getUserName)
.from(UserPo.class)
.where(w -> w.eq(UserPo::getUserName, "张三"))
.build();
//使用UnaryOperator 函数接口
NativeSqlQuery query1 = NativeSqlQuery.builder()
.select((UnaryOperator<SelectCriterion>) s -> {
s.add(UserPo::getUserName).add(UserPo::getId);
return s;
})
.from(UserPo.class)
.where(w -> w.eq(UserPo::getUserName, "张三"))
.build();
//字符串格式指定字段
NativeSqlQuery query3 = NativeSqlQuery.builder()
.select("t0.id", "t0.userName")
//.select("t0.id","t0.user_name")
.from(UserPo.class)
.where(w -> w.eq(UserPo::getUserName, "张三"))
.build();
List<UserDTO> list = joyaRepository.findListBySql(query, UserDTO.class);
// 查询单个字段映射到包装类或String
//SELECT t0.user_name FROM user AS t0 WHERE t0.user_name = ?1
NativeSqlQuery query3 = NativeSqlQuery.builder()
.select(UserPo::getUserName)
.from(UserPo.class)
.where(w -> w.eq(UserPo::getUserName, "张三"))
.build();
List<String> list1 = joyaRepository.findListBySql(query3, String.class);
}
}
public class Test {
@Test
public void testJoin() {
// 联接字段在where 语句中
//SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age,t1.user_id,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0, user_extend AS t1 WHERE t0.id = t1.user_id AND t0.user_name = ?1
NativeSqlQuery query = NativeSqlQuery.builder()
.select()
.from(UserPo.class, UserExtendPo.class)
.where(w -> w
.eq(UserPo::getId, UserExtendPo::getUserId)
.eq(UserPo::getUserName, "张三"))
.build();
// 联接字段在from语句中 支持inner join,left join和 right join三种方式,目前为了提升效率,限制最大支持三张表联表查询
//SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age,t1.user_id,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0 JOIN user_extend AS t1 ON t0.id = t1.user_id WHERE t0.user_name = ?1
NativeSqlQuery query1 = NativeSqlQuery.builder()
.select()
.from(j -> j.join(UserPo::getId, UserExtendPo::getUserId))
.where(w -> w
.eq(UserPo::getUserName, "张三"))
.build();
//对于冲突字段可以指定别名,如user表和user_extend表同时有 updateTime字段,可以通过指定别名来避免字段值覆盖
// SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.update_time,t1.update_time AS modifyTime,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0 JOIN user_extend AS t1 ON t0.id = t1.user_id WHERE t0.user_name = ?1
NativeSqlQuery query3 = NativeSqlQuery.builder()
.select()//查询全部字段
.specificS("t1.updateTime AS modifyTime") //将user_extend中重名的updateTime 指定为modifyTime
.from(j -> j.join(UserPo::getId, UserExtendPo::getUserId))
.where(w -> w
.eq(UserPo::getUserName, "张三"))
.build();
}
}
在Joya中为分页查询封装了PageQueryParam
提供给restFul接口使用
/**
* 分页查询参数支持常用封装
*/
public class PageQueryParam extends JoyaQuery implements Serializable {
/**
* 分页大小
*/
private Integer pageSize = 10;
/**
* 页数 默认从0开始
*/
private Integer page = 0;
/**
* 连接类型 默认and
*/
private LinkType linkType = LinkType.AND;
/**
* 排序字段
*/
private List<OrderParam> orderList = Lists.newArrayList();
/**
* 搜索参数
*/
private List<SearchParam> params = Lists.newArrayList();
public enum LinkType {
/**
*
*/
AND,
OR;
}
}
如有如下查询场景
分页关联查询user表和user_extend表,查询条件为userName like '张三%'并且 age>18,按照user表中的id降序
那么接口请求的PageQueryParam
则为
{
"orderList": [
{
"fieldName": "t0.id",
"orderType": "DESC"
}
],
"page": 0,
"pageSize": 10,
"params": [
{
"fieldName": "t0.userName",
"fieldValue": "张三",
"operator": "LIKE_R"
},
{
"fieldName": "t0.age",
"fieldValue": 18,
"operator": "GT"
}
]
}
使用Joya查询方法有如下两种:
- 分页查询(指定join字段)
PageQueryParam pageQueryParam=JSON.parseObject(jsonString,PageQueryParam.class);
PageResult<UserDTO> pageResult=joyaRepository.queryPage(pageQueryParam,UserDTO.class,j->j.join(UserPo::getId,UserExtendPo::getUserId));
- 分页查询(指定where语句中的联接字段)
PageQueryParam pageQueryParam1=JSON.parseObject("",PageQueryParam.class);
//附加where
pageQueryParam1.setSpecificW("t0.id=t1.userId");
//指定要查询的表,顺序要注意,因为别名按照先后顺序来生成
PageResult<UserDTO> pageResult=joyaRepository.queryPage(pageQueryParam,UserDTO.class,UserPo.class,UserExtendPo.class);
在Joya中,where 查询语句支持常用查询,也可以通过specificW
方法来添加特殊查询语句
.where(w -> w
.eq() // =
.gt() // >
.lt() // <
.gte() // >=
.lte() // <=
.isNull() // is null
.isNotNull() // is not null
.in() // in
.notIn() // not in
.endsWith() // like '%a'
.contains() // like '%a%'
.startsWith() // like 'a%'
.specificS()) //指定特殊的查询语句
where 查询语句默认是AND
条件联接,可以选择OR
条件联接
//SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age,t1.user_id,t1.salt,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0, user_extend AS t1 WHERE t0.user_name = ?1 OR t0.user_name = ?2 OR ( t0.age >= ?2 AND t0.user_phone LIKE ?2 )
NativeSqlQuery query=NativeSqlQuery.builder()
.select()
.from(UserPo.class,UserExtendPo.class)
.where(w->w
.eq(UserPo::getUserName,"张三")
.eq(UserPo::getUserName,"李四")
.subQuery(q->q.gte(UserPo::getAge,18).startsWith(UserPo::getUserPhone,"1385")),true)
.build();
fork本项目,添加features或bugfix,提交Pull Requests
Joya 遵守 Apache License 2.0 许可证。