{"id":37024754,"url":"https://github.com/dunmengjun/sqldsl","last_synced_at":"2026-01-14T03:00:09.125Z","repository":{"id":46969466,"uuid":"404774240","full_name":"dunmengjun/sqldsl","owner":"dunmengjun","description":"基于jdbc实现的sql dsl，类似Querydsl,  但不需要插件就可提供类型安全的查询(基于SerializedLambda)。可以很方便的和各种类型的库(比如mybatis, hibernate等)集成。","archived":false,"fork":false,"pushed_at":"2023-12-23T08:26:57.000Z","size":471,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-16T03:39:49.704Z","etag":null,"topics":["dsl","gradle","hibernate","java","jdbc","lambda","maven","mybatis","mysql","oracle","postgresql","querydsl","sql","sql-server"],"latest_commit_sha":null,"homepage":"https://dunmengjun.github.io/sqldsl/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dunmengjun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-09-09T15:26:28.000Z","updated_at":"2021-10-04T08:01:32.000Z","dependencies_parsed_at":"2023-11-24T17:26:46.877Z","dependency_job_id":"2812fff2-5ffe-46f7-a3a4-c59efee0686d","html_url":"https://github.com/dunmengjun/sqldsl","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/dunmengjun/sqldsl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunmengjun%2Fsqldsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunmengjun%2Fsqldsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunmengjun%2Fsqldsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunmengjun%2Fsqldsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dunmengjun","download_url":"https://codeload.github.com/dunmengjun/sqldsl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunmengjun%2Fsqldsl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408799,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dsl","gradle","hibernate","java","jdbc","lambda","maven","mybatis","mysql","oracle","postgresql","querydsl","sql","sql-server"],"created_at":"2026-01-14T03:00:07.529Z","updated_at":"2026-01-14T03:00:08.998Z","avatar_url":"https://github.com/dunmengjun.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sqldsl\n[![Sonarqube-check](https://github.com/dunmengjun/sqldsl/actions/workflows/sonarqube-check.yml/badge.svg)](https://github.com/dunmengjun/sqldsl/actions/workflows/sonarqube-check.yml)\u0026nbsp;\u0026nbsp;\u0026nbsp;[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dunmengjun_sqldsl\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=dunmengjun_sqldsl)\u0026nbsp;\u0026nbsp;\u0026nbsp;[![Publish Package](https://github.com/dunmengjun/sqldsl/actions/workflows/gradle-publish.yml/badge.svg)](https://github.com/dunmengjun/sqldsl/actions/workflows/gradle-publish.yml)\n\n基于jdbc实现的sql dsl，类似Querydsl, 但不需要插件就可提供类型安全的查询(基于SerializedLambda)。可以很方便的和各种类型的库(比如mybatis,\nhibernate等)集成。(项目还处于早期阶段，测试可以，请不要用于生产环境)\n\n### 特点\n\n1. 用java代码写sql语句，不管是简单还是复杂的sql\n\n\u003e 类似querydsl, 和它一样简单明了，但不用生成代码\n\n2. 无代码生成的类型安全保证, 保姆级的sql规则校验\n\n\u003e 不会有processor配置,只会有简单的一个jar包, 类型安全的原理是充分的利用SerializedLambda和java类型机制\n\u003e\n\u003e 为什么需要类型安全? 因为非类型安全写sql很容易出错(老手也一样), 一旦出错导致的bug要花巨大的代价去修复\n\u003e\n\u003e 大部分的类型安全会在编译时保证，少部分在运行时保证。什么？你问类型安全为什么不都在编译时保证？\n\u003e 原因是一是sql很复杂，并且还要支持子查询，不可能都在编译时保证类型安全，二是,java的泛型，你懂的。\n\n3. 灵活充分的元数据配置\n\n\u003e 比如可以配置基于哪些注解完成表名和列名的扫描，默认是基于javax.persistence, 不过可配置\n\u003e\n\u003e 能很容易的集成到spring环境，也可以很容易的在非spring去用(项目就是在非spring环境写的)\n\u003e\n\u003e 由于注解可配置，所以也很容易和其他框架结合，比如mybatis, hibernate等, 集成可用于提供类型安全且灵活的查询\n\u003e 而不用去手写sql语句，即容易错误，也不好分析\n\n4. 不提供复杂的包装，只用java就可以实现很复杂的sql\n\n\u003e 比如hibernate的session管理，hql，又比如mybatis的mapper和xml的映射，在作者看来很是眼花缭乱，不知道该用啥写啥\n\u003e\n\u003e 本项目保证全程用java代码就可以实现很复杂的sql。\n\n5. 翻译到h2,mysql,postgres,oracle,sqlserver2012以上\n\n\u003e 保证一旦你写完一个查询, 能符合常用规则和预期并且正确的翻译到主流数据库\n\n6. 最少的依赖\n\n\u003e 本项目基于jdk8编写只依赖于java标准库,javax.persistence, java.sql和一个日志门面slf4j-api, 再就没有任何依赖了\n\n### 开始\n\n#### Maven\n\n```xml\n\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.dunmengjun\u003c/groupId\u003e\n  \u003cartifactId\u003esqldsl\u003c/artifactId\u003e\n  \u003cversion\u003e{latest version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n#### Gradle\n\n```groovy\nimplementation 'io.github.dunmengjun:sqldsl:{latest version}'\n```\n\n#### Spring环境下bean的配置(默认需要依赖javax.persistence,java.sql)\n\n```java\n\n@Configuration\npublic class SqlDslConfiguration {\n\n  @Bean\n  public SqlDslService sqlDslService(DataSource dataSource) {\n    GlobalConfig.setGlobalColumnNameTranslator(new CamelToUnderlineTranslator());\n    GlobalConfig.setGlobalTableNameTranslator(new FirstCharToLowerTranslator());\n    return new SqlDslService(new SqlDslExecutor(SqlDialect.mysql, dataSource::getConnection));\n  }\n}\n```\n\nSpring环境和非Spring环境都是用的同一种api，区别只是在spring环境下，sqldslservice被spring所管理，而非spring环境需要手动new出来。\n\n#### 使用案例\n\n#### 1. 简单单表查询\n\n实体类\n\n```java\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\n@Table(name = \"user\")\npublic class User {\n\n  @Id\n  private Integer id;\n\n  @Column\n  private String name;\n\n  @Column\n  private Integer age;\n\n  @Column\n  private Integer type;\n}\n```\n\n如果项目没有依赖javax.persistence, 而是依赖的orm框架自己的注解，也是可以配置的，sqldsl提供了一个全局配置去替换注解扫描\n\n```java\npublic class GlobalConfig {\n\n  private static EntityConfig entityConfig = EntityConfig.builder()\n      .tableConfig(TableConfig.builder()\n          .annotationClass(Table.class)\n          .tableNameAttribute(\"name\")\n          .build())\n      .columnConfig(ColumnConfig.builder()\n          .idAnnotationClass(Id.class)\n          .columnAnnotationClass(Column.class)\n          .columnNameAttribute(\"name\")\n          .build())\n      .lambdaMethodTranslator(new PojoLikedStyleTranslator())\n      .build();\n  \n  ...\n\n  public static void setEntityConfig(EntityConfig entityConfig) {\n    GlobalConfig.entityConfig = entityConfig;\n  }\n  ...\n}\n```\n\n这是全局配置的源码，在工程中可以直接调用GlobalConfig.setEntityConfig方法去设置自己项目依赖的注解信息， sqldsl所有关于注解的处理都是在EntityConfig中进行。\n\n普通查询\n\n```java\nList\u003cUser\u003e actual=sqlDslService.select(User.class);\n```\n\n分页查询\n\n```java    \nPageRequest request = PageRequest.of(1, 1);\nPage\u003cUser\u003e actual = sqlDslService.select(request, User.class);\n```\n\n条件查询\n\n```java\nList\u003cUser\u003e actual=sqlDslService.select(\n    new Wrapper\u003c\u003e(User.class)\n    .eq(User::getType,1)\n);\n```\n\nlimit查询\n\n```java\nList\u003cUser\u003e actual=sqlDslService.select(\n    new Wrapper\u003c\u003e(User.class)\n    .eq(User::getType,1)\n    .limit(1)\n);\n```\n\n分组查询\n\n```java\nList\u003cUser\u003e actual=sqlDslService.select(\n    new Wrapper\u003c\u003e(User.class)\n    .selectAs(max(User::getAge),User::getAge)\n    .groupBy(User::getType)\n    .having(w-\u003ew.gt(max(User::getAge),17))\n);\n```\n\n排序查询\n\n```java\nList\u003cUser\u003e actual=sqlDslService.select(\n    new Wrapper\u003c\u003e(User.class)\n    .selectAs(max(User::getAge),User::getAge)\n    .groupBy(User::getType)\n    .orderBy(User::getType,false)\n    .limit(2)\n);\n```\n\n#### 2. 多表复杂查询\n\n实体类就不列出来了\n\n普通join查询\n\n```java\nDslQueryBuilder queryBuilder=new SelectBuilder()\n    .selectAll(User.class,User::getId,User::getAge)\n    .selectAll(Comment.class,Comment::getUserId)\n    .from(User.class)\n    .leftJoin(Comment.class,eq(User::getId,Comment::getUserId))\n    .where(eq(User::getAge,17));\n\nList\u003cUserComment\u003e actual=sqlDslService.select(queryBuilder,UserComment.class);\n```\n\n多join查询\n\n```java\nDslQueryBuilder queryBuilder=new SelectBuilder()\n    .select(User::getName)\n    .select(Comment::getId,Comment::getMessage)\n    .select(Satisfaction::getRating)\n    .from(User.class)\n    .leftJoin(Comment.class,eq(User::getId,Comment::getUserId))\n    .leftJoin(Satisfaction.class,eq(Comment::getId,Satisfaction::getCommentId))\n    .where(eq(Comment::getStatus,1));\n\nList\u003cCommentRating\u003e actual=sqlDslService.select(queryBuilder,CommentRating.class);\n```\n\n自连接查询\n\n```java\nEntityBuilder selfDept=EntityBuilder.alias(Dept.class);\nDslQueryBuilder queryBuilder=new SelectBuilder()\n    .selectAll(selfDept)\n    .from(Dept.class)\n    .leftJoin(selfDept,eq(Dept::getParent,selfDept.col(Dept::getId)))\n    .where(eq(Dept::getName,\"Development Department\"));\n\nList\u003cDept\u003e actual=sqlDslService.select(queryBuilder,Dept.class);\n```\n\nform子查询\n\n```java\nDslQueryBuilder queryBuilder=new SelectBuilder()\n    .selectAll(User.class)\n    .from(User.class)\n    .where(lt(User::getAge,17));\n\nSubQueryBuilder subQuery=SubQueryBuilder.alias(queryBuilder);\nDslQueryBuilder query=new SelectBuilder()\n    .selectAll(subQuery)\n    .from(subQuery)\n    .where(eq(subQuery.col(User::getAge),16));\n\nList\u003cUser\u003e actual=sqlDslService.select(query,User.class);\n```\n\njoin子查询\n\n```java\nDslQueryBuilder queryBuilder=new SelectBuilder()\n    .selectAll(User.class)\n    .from(User.class)\n    .where(lt(User::getAge,17));\n\nSubQueryBuilder subQuery=SubQueryBuilder.alias(queryBuilder);\nDslQueryBuilder query=new SelectBuilder()\n    .selectAll(subQuery)\n    .from(User.class)\n    .leftJoin(subQuery,eq(subQuery.col(User::getId),User::getId))\n    .where(eq(subQuery.col(User::getAge),16));\n\nList\u003cUser\u003e actual=sqlDslService.select(query,User.class);\n```\n\n#### 插入和更新\n\n默认: null字段不更新和插入,有ID是更新,无ID是插入。\n可以定制化对每一个对象设置是更新还是插入, 还有强制更新插入的字段\n详情请看 单元测试SaveDataTest\n\n插入\n\n```java\nTypeUser entity=new TypeUser(\"alice\",16,1);\n\nsqlDslService.save(entity);\n```\n\n更新\n\n```java\nTypeUser entity=new TypeUser(1,\"b bb\",16,1);\n\nsqlDslService.save(entity);\n```\n\n插入和更新的区别只在于有没有ID\n\n批量更新或者插入\n\n```java\nList\u003cTypeUser\u003e typeUsers=Arrays.asList(\n    new TypeUser(1,null,16,1),\n    new TypeUser(\"bob\",16,1),\n    new TypeUser(\"tom\",18,2)\n);\n\nsqlDslService.save(typeUsers);\n```\n\n批量操作会自动判断是更新还是插入(底层会把它们分开并生成更新或者插入的jdbc批量操作)\n\n新增 事务管理 详情请看 单元测试TransactionTest\n\n还有很多的案例就不写在这儿了，需要详细的使用介绍，可以直接浏览单元测试，里面分得很细也很全，代码也很好阅读。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunmengjun%2Fsqldsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdunmengjun%2Fsqldsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunmengjun%2Fsqldsl/lists"}