https://github.com/dunmengjun/sqldsl
基于jdbc实现的sql dsl,类似Querydsl, 但不需要插件就可提供类型安全的查询(基于SerializedLambda)。可以很方便的和各种类型的库(比如mybatis, hibernate等)集成。
https://github.com/dunmengjun/sqldsl
dsl gradle hibernate java jdbc lambda maven mybatis mysql oracle postgresql querydsl sql sql-server
Last synced: 9 days ago
JSON representation
基于jdbc实现的sql dsl,类似Querydsl, 但不需要插件就可提供类型安全的查询(基于SerializedLambda)。可以很方便的和各种类型的库(比如mybatis, hibernate等)集成。
- Host: GitHub
- URL: https://github.com/dunmengjun/sqldsl
- Owner: dunmengjun
- License: mit
- Created: 2021-09-09T15:26:28.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2023-12-23T08:26:57.000Z (about 2 years ago)
- Last Synced: 2024-11-16T03:39:49.704Z (about 1 year ago)
- Topics: dsl, gradle, hibernate, java, jdbc, lambda, maven, mybatis, mysql, oracle, postgresql, querydsl, sql, sql-server
- Language: Java
- Homepage: https://dunmengjun.github.io/sqldsl/
- Size: 460 KB
- Stars: 1
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Sqldsl
[](https://github.com/dunmengjun/sqldsl/actions/workflows/sonarqube-check.yml) [](https://sonarcloud.io/dashboard?id=dunmengjun_sqldsl) [](https://github.com/dunmengjun/sqldsl/actions/workflows/gradle-publish.yml)
基于jdbc实现的sql dsl,类似Querydsl, 但不需要插件就可提供类型安全的查询(基于SerializedLambda)。可以很方便的和各种类型的库(比如mybatis,
hibernate等)集成。(项目还处于早期阶段,测试可以,请不要用于生产环境)
### 特点
1. 用java代码写sql语句,不管是简单还是复杂的sql
> 类似querydsl, 和它一样简单明了,但不用生成代码
2. 无代码生成的类型安全保证, 保姆级的sql规则校验
> 不会有processor配置,只会有简单的一个jar包, 类型安全的原理是充分的利用SerializedLambda和java类型机制
>
> 为什么需要类型安全? 因为非类型安全写sql很容易出错(老手也一样), 一旦出错导致的bug要花巨大的代价去修复
>
> 大部分的类型安全会在编译时保证,少部分在运行时保证。什么?你问类型安全为什么不都在编译时保证?
> 原因是一是sql很复杂,并且还要支持子查询,不可能都在编译时保证类型安全,二是,java的泛型,你懂的。
3. 灵活充分的元数据配置
> 比如可以配置基于哪些注解完成表名和列名的扫描,默认是基于javax.persistence, 不过可配置
>
> 能很容易的集成到spring环境,也可以很容易的在非spring去用(项目就是在非spring环境写的)
>
> 由于注解可配置,所以也很容易和其他框架结合,比如mybatis, hibernate等, 集成可用于提供类型安全且灵活的查询
> 而不用去手写sql语句,即容易错误,也不好分析
4. 不提供复杂的包装,只用java就可以实现很复杂的sql
> 比如hibernate的session管理,hql,又比如mybatis的mapper和xml的映射,在作者看来很是眼花缭乱,不知道该用啥写啥
>
> 本项目保证全程用java代码就可以实现很复杂的sql。
5. 翻译到h2,mysql,postgres,oracle,sqlserver2012以上
> 保证一旦你写完一个查询, 能符合常用规则和预期并且正确的翻译到主流数据库
6. 最少的依赖
> 本项目基于jdk8编写只依赖于java标准库,javax.persistence, java.sql和一个日志门面slf4j-api, 再就没有任何依赖了
### 开始
#### Maven
```xml
io.github.dunmengjun
sqldsl
{latest version}
```
#### Gradle
```groovy
implementation 'io.github.dunmengjun:sqldsl:{latest version}'
```
#### Spring环境下bean的配置(默认需要依赖javax.persistence,java.sql)
```java
@Configuration
public class SqlDslConfiguration {
@Bean
public SqlDslService sqlDslService(DataSource dataSource) {
GlobalConfig.setGlobalColumnNameTranslator(new CamelToUnderlineTranslator());
GlobalConfig.setGlobalTableNameTranslator(new FirstCharToLowerTranslator());
return new SqlDslService(new SqlDslExecutor(SqlDialect.mysql, dataSource::getConnection));
}
}
```
Spring环境和非Spring环境都是用的同一种api,区别只是在spring环境下,sqldslservice被spring所管理,而非spring环境需要手动new出来。
#### 使用案例
#### 1. 简单单表查询
实体类
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "user")
public class User {
@Id
private Integer id;
@Column
private String name;
@Column
private Integer age;
@Column
private Integer type;
}
```
如果项目没有依赖javax.persistence, 而是依赖的orm框架自己的注解,也是可以配置的,sqldsl提供了一个全局配置去替换注解扫描
```java
public class GlobalConfig {
private static EntityConfig entityConfig = EntityConfig.builder()
.tableConfig(TableConfig.builder()
.annotationClass(Table.class)
.tableNameAttribute("name")
.build())
.columnConfig(ColumnConfig.builder()
.idAnnotationClass(Id.class)
.columnAnnotationClass(Column.class)
.columnNameAttribute("name")
.build())
.lambdaMethodTranslator(new PojoLikedStyleTranslator())
.build();
...
public static void setEntityConfig(EntityConfig entityConfig) {
GlobalConfig.entityConfig = entityConfig;
}
...
}
```
这是全局配置的源码,在工程中可以直接调用GlobalConfig.setEntityConfig方法去设置自己项目依赖的注解信息, sqldsl所有关于注解的处理都是在EntityConfig中进行。
普通查询
```java
List actual=sqlDslService.select(User.class);
```
分页查询
```java
PageRequest request = PageRequest.of(1, 1);
Page actual = sqlDslService.select(request, User.class);
```
条件查询
```java
List actual=sqlDslService.select(
new Wrapper<>(User.class)
.eq(User::getType,1)
);
```
limit查询
```java
List actual=sqlDslService.select(
new Wrapper<>(User.class)
.eq(User::getType,1)
.limit(1)
);
```
分组查询
```java
List actual=sqlDslService.select(
new Wrapper<>(User.class)
.selectAs(max(User::getAge),User::getAge)
.groupBy(User::getType)
.having(w->w.gt(max(User::getAge),17))
);
```
排序查询
```java
List actual=sqlDslService.select(
new Wrapper<>(User.class)
.selectAs(max(User::getAge),User::getAge)
.groupBy(User::getType)
.orderBy(User::getType,false)
.limit(2)
);
```
#### 2. 多表复杂查询
实体类就不列出来了
普通join查询
```java
DslQueryBuilder queryBuilder=new SelectBuilder()
.selectAll(User.class,User::getId,User::getAge)
.selectAll(Comment.class,Comment::getUserId)
.from(User.class)
.leftJoin(Comment.class,eq(User::getId,Comment::getUserId))
.where(eq(User::getAge,17));
List actual=sqlDslService.select(queryBuilder,UserComment.class);
```
多join查询
```java
DslQueryBuilder queryBuilder=new SelectBuilder()
.select(User::getName)
.select(Comment::getId,Comment::getMessage)
.select(Satisfaction::getRating)
.from(User.class)
.leftJoin(Comment.class,eq(User::getId,Comment::getUserId))
.leftJoin(Satisfaction.class,eq(Comment::getId,Satisfaction::getCommentId))
.where(eq(Comment::getStatus,1));
List actual=sqlDslService.select(queryBuilder,CommentRating.class);
```
自连接查询
```java
EntityBuilder selfDept=EntityBuilder.alias(Dept.class);
DslQueryBuilder queryBuilder=new SelectBuilder()
.selectAll(selfDept)
.from(Dept.class)
.leftJoin(selfDept,eq(Dept::getParent,selfDept.col(Dept::getId)))
.where(eq(Dept::getName,"Development Department"));
List actual=sqlDslService.select(queryBuilder,Dept.class);
```
form子查询
```java
DslQueryBuilder queryBuilder=new SelectBuilder()
.selectAll(User.class)
.from(User.class)
.where(lt(User::getAge,17));
SubQueryBuilder subQuery=SubQueryBuilder.alias(queryBuilder);
DslQueryBuilder query=new SelectBuilder()
.selectAll(subQuery)
.from(subQuery)
.where(eq(subQuery.col(User::getAge),16));
List actual=sqlDslService.select(query,User.class);
```
join子查询
```java
DslQueryBuilder queryBuilder=new SelectBuilder()
.selectAll(User.class)
.from(User.class)
.where(lt(User::getAge,17));
SubQueryBuilder subQuery=SubQueryBuilder.alias(queryBuilder);
DslQueryBuilder query=new SelectBuilder()
.selectAll(subQuery)
.from(User.class)
.leftJoin(subQuery,eq(subQuery.col(User::getId),User::getId))
.where(eq(subQuery.col(User::getAge),16));
List actual=sqlDslService.select(query,User.class);
```
#### 插入和更新
默认: null字段不更新和插入,有ID是更新,无ID是插入。
可以定制化对每一个对象设置是更新还是插入, 还有强制更新插入的字段
详情请看 单元测试SaveDataTest
插入
```java
TypeUser entity=new TypeUser("alice",16,1);
sqlDslService.save(entity);
```
更新
```java
TypeUser entity=new TypeUser(1,"b bb",16,1);
sqlDslService.save(entity);
```
插入和更新的区别只在于有没有ID
批量更新或者插入
```java
List typeUsers=Arrays.asList(
new TypeUser(1,null,16,1),
new TypeUser("bob",16,1),
new TypeUser("tom",18,2)
);
sqlDslService.save(typeUsers);
```
批量操作会自动判断是更新还是插入(底层会把它们分开并生成更新或者插入的jdbc批量操作)
新增 事务管理 详情请看 单元测试TransactionTest
还有很多的案例就不写在这儿了,需要详细的使用介绍,可以直接浏览单元测试,里面分得很细也很全,代码也很好阅读。