{"id":29558805,"url":"https://github.com/llllllxy/tiny-jdbc","last_synced_at":"2025-07-18T13:02:17.035Z","repository":{"id":203644632,"uuid":"709863520","full_name":"llllllxy/tiny-jdbc","owner":"llllllxy","description":" 🌟 tiny-jdbc：一款专为 Java 开发者量身打造的极致轻量级数据库 ORM 神器✨！它深度依托 Spring JdbcTemplate 的强大内核，以精妙的架构设计和卓越的性能表现，无缝融合了 SQL 操作的灵活性与实体类映射操作的便捷性。无论是简单的数据查询，还是复杂的事务处理，tiny-jdbc 都能让数据库操作变得如同行云流水般简单，助你在开发之路上一路狂飙🚀！","archived":false,"fork":false,"pushed_at":"2025-07-14T10:49:38.000Z","size":545,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-14T13:52:17.331Z","etag":null,"topics":["database","java","jdbc-template","orm","springboot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/llllllxy.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-10-25T14:44:59.000Z","updated_at":"2025-07-14T10:32:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"d666f26f-f30c-403c-a7e7-0eed33f83f05","html_url":"https://github.com/llllllxy/tiny-jdbc","commit_stats":null,"previous_names":["llllllxy/tiny-jdbc-boot-starter","llllllxy/tiny-jdbc"],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/llllllxy/tiny-jdbc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-jdbc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-jdbc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-jdbc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-jdbc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/llllllxy","download_url":"https://codeload.github.com/llllllxy/tiny-jdbc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-jdbc/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265765526,"owners_count":23824604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["database","java","jdbc-template","orm","springboot"],"created_at":"2025-07-18T13:01:45.570Z","updated_at":"2025-07-18T13:02:16.633Z","avatar_url":"https://github.com/llllllxy.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eTinyJDBC\u003c/h1\u003e\r\n\u003ch1 align=\"center\"\u003e一个优雅的 ORM 框架，轻量、灵活、高性能\u003c/h1\u003e\r\n\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003ca href=\"https://github.com/llllllxy/tiny-jdbc/blob/master/LICENSE\"\u003e\r\n        \u003cimg src=\"https://img.shields.io/github/license/llllllxy/tiny-jdbc.svg?style=flat-square\"\u003e\r\n    \u003c/a\u003e\r\n\t\u003ca target=\"_blank\" href=\"https://www.oracle.com/technetwork/java/javase/downloads/index.html\"\u003e\r\n\t\t\u003cimg src=\"https://img.shields.io/badge/JDK-8+-blue.svg\" /\u003e\r\n\t\u003c/a\u003e\r\n    \u003ca href=\"https://github.com/llllllxy/tiny-jdbc/stargazers\"\u003e\r\n        \u003cimg src=\"https://img.shields.io/github/stars/llllllxy/tiny-jdbc?style=flat-square\u0026logo=GitHub\"\u003e\r\n    \u003c/a\u003e\r\n    \u003ca href=\"https://github.com/llllllxy/tiny-jdbc/network/members\"\u003e\r\n        \u003cimg src=\"https://img.shields.io/github/forks/llllllxy/tiny-jdbc?style=flat-square\u0026logo=GitHub\"\u003e\r\n    \u003c/a\u003e\r\n    \u003ca href=\"https://github.com/llllllxy/tiny-jdbc/watchers\"\u003e\r\n        \u003cimg src=\"https://img.shields.io/github/watchers/llllllxy/tiny-jdbc?style=flat-square\u0026logo=GitHub\"\u003e\r\n    \u003c/a\u003e\r\n    \u003ca href=\"https://github.com/llllllxy/tiny-jdbc/issues\"\u003e\r\n        \u003cimg src=\"https://img.shields.io/github/issues/llllllxy/tiny-jdbc.svg?style=flat-square\u0026logo=GitHub\"\u003e\r\n    \u003c/a\u003e\r\n    \u003ca href='https://github.com/llllllxy/tiny-jdbc/releases'\u003e\r\n        \u003cimg src='https://img.shields.io/github/release/llllllxy/tiny-jdbc.svg?style=flat-square\u0026logo=GitHub'\u003e\r\n    \u003c/a\u003e\r\n    \u003ca href='https://gitee.com/leisureLXY/tiny-jdbc'\u003e\r\n        \u003cimg src='https://gitee.com/leisureLXY/tiny-jdbc/badge/star.svg?theme=dark' alt='star' /\u003e\r\n    \u003c/a\u003e\r\n\r\n\u003cbr/\u003e\r\n\u003c/p\u003e\r\n\r\n## 1、简介\r\n\r\n`tiny-jdbc` 是一款基于 `Spring JDBC` 精心打造的轻量、灵活且高性能的数据库 `ORM` 框架。它在继承 `Spring JDBC`\r\n原有强大功能的基础上，进行了大量的增强和优化，为开发者提供了更加便捷、高效的数据库操作体验，让操作数据库这件事变得更加简单！\r\n\r\n### 优势\r\n\r\n- **轻量级**：除了 Spring JDBC 本身，再无任何第三方依赖，轻量可靠\r\n- **性能高**：依托高性能的 Spring JDBC，在执行数据库操作时性能基本无损耗，能够满足高并发场景下的应用需求\r\n- **功能强**：既支持原生 sql 操作，让开发者可以灵活编写复杂的 sql 语句；又支持实体类映射操作，通过简单的配置即可实现对象与数据库表的映射。BaseDao\r\n  里封装了大量的通用方法，配合强大灵活的条件构造器（Criteria）和SQL构造器（SQL），基本能满足各类使用需求。\r\n- **支持 Lambda 形式调用**：条件构造器（Criteria）和SQL构造器（SQL）支持Lambda形式调用，编译期语法增强，无需再担心字段写错，提高代码的安全性和可维护性\r\n- **支持主键自动生成**：内含多种主键生成策略，包括自增主键、UUID、雪花ID 等，同时也支持自定义 ID 生成策略，满足不同业务场景下的主键生成需求。\r\n- **支持多种数据库分页方言**：包括 MySQL、ORACLE、DB2、PostgreSql 等多种常用数据库，无需额外配置，框架会自动识别数据库类型并采用相应的分页方言，大大简化了分页查询的开发工作。\r\n- **同时支持 SpringBoot2 和 SpringBoot3 **\r\n\r\n### 支持数据库\r\n\r\n- 分页插件目前支持MySQL、MARIADB、ORACLE、DB2、PostgreSql、SQLite、H2、OceanBase、openGauss、informix、达梦数据库、人大金仓数据库、瀚高数据库等常见数据库\r\n- 其他操作支持任何使用标准 SQL 的数据库\r\n\r\n## 2、快速开始\r\n\r\n### 引入Maven依赖\r\n\r\n```xml\r\n\u003cdependency\u003e\r\n    \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\r\n    \u003cartifactId\u003espring-boot-starter-jdbc\u003c/artifactId\u003e\r\n\u003c/dependency\u003e\r\n\u003cdependency\u003e\r\n\u003cgroupId\u003etop.lxyccc\u003c/groupId\u003e\r\n\u003cartifactId\u003etiny-jdbc-boot-starter\u003c/artifactId\u003e\r\n\u003cversion\u003e1.8.8\u003c/version\u003e\r\n\u003c/dependency\u003e\r\n```\r\n\r\n### application.yml参数配置\r\n\r\n- **或application.properties**\r\n\r\n```yaml\r\ntiny-jdbc:\r\n  # 打印banner，默认false\r\n  banner: true\r\n  # 分页器适配类型，可不配置，不配置的话会自动获取\r\n  db-type: mysql\r\n```\r\n\r\n### 定义Entity实体类\r\n\r\n- **实体类对应数据库的一张表**\r\n- **实体类属性名必须使用`驼峰命名规则`，与数据库表字段一一映射**\r\n\r\n```java\r\n\r\n@Table(\"b_upload_file\")\r\npublic class UploadFile implements Serializable {\r\n    private static final long serialVersionUID = -1L;\r\n\r\n    /**\r\n     * @Id 注解用于标记表的主键，目前只支持单主键，请不要在多个属性上设置此注解，会导致程序出错\r\n     *\r\n     * idType: 主键ID策略，目前支持以下7种 AUTO_INCREMENT、INPUT、OBJECT_ID、ASSIGN_ID、UUID、SEQUENCE、CUSTOM\r\n     * value: 则代表的是sequence 序列的 sql 内容，idType=SEQUENCE时，必须设置此内容\r\n     * \u003cbr/\u003e\r\n     * 注意！\r\n     * 如果设置为 AUTO_INCREMENT 自增主键 的话，则此字段必须为Long\r\n     * 如果设置为 UUID 的话，则此属性类型必须为String\r\n     * 如果设置为 OBJECT_ID 的话，则此属性类型必须为String\r\n     * 如果设置为 ASSIGN_ID 的话，则此属性类型必须为String或者Long\r\n     * 如果设置为 SEQUENCE 的话，则此属性类型必须为Integer或者Long，且必须设置value属性为查询序列值的SQL\r\n     * 如果设置为 CUSTOM 的话，则需要自己实现 IdGeneratorInterface 接口并注册为bean\r\n     *\r\n     *\r\n     * @Column 注解用于标记属性和表字段的对应关系\r\n     */\r\n    @Id(idType = IdType.AUTO_INCREMENT)\r\n    @Column(value = \"id\")\r\n    private Long id;\r\n\r\n    /**\r\n     * 文件id\r\n     */\r\n    @Column(\"file_id\")\r\n    private String fileId;\r\n\r\n    /**\r\n     * 文件原名称\r\n     */\r\n    @Column(\"file_name_old\")\r\n    private String fileNameOld;\r\n\r\n    /**\r\n     * 文件新名称\r\n     */\r\n    @Column(\"file_name_new\")\r\n    private String fileNameNew;\r\n\r\n    /**\r\n     * 文件路径\r\n     */\r\n    @Column(\"file_path\")\r\n    private String filePath;\r\n\r\n    /**\r\n     * 文件md5\r\n     */\r\n    @Column(\"file_md5\")\r\n    private String fileMd5;\r\n\r\n    /**\r\n     * 上传时间\r\n     */\r\n    @Column(\"created_at\")\r\n    private Date createdAt;\r\n\r\n    public Long getId() {\r\n        return id;\r\n    }\r\n\r\n    public void setId(Long id) {\r\n        this.id = id;\r\n    }\r\n\r\n    // 其他 getter 和 setter 方法...\r\n}\r\n```\r\n\r\n### 定义Dao类，继承自BaseDao\r\n\r\n- **泛型一为对应实体类，泛型二实体类主键类型**\r\n\r\n```java\r\nimport org.springframework.stereotype.Repository;\r\nimport org.tinycloud.jdbc.BaseDao;\r\nimport org.tinycloud.entity.UploadFile;\r\n\r\n@Repository\r\npublic class UploadFileDao extends BaseDao\u003cUploadFile, Long\u003e {\r\n\r\n    // 可添加自定义方法...\r\n}\r\n```\r\n\r\n### Service层注入使用\r\n\r\n```java\r\nimport org.springframework.stereotype.Service;\r\nimport org.tinycloud.dao.UploadFileDao;\r\n\r\n@Service\r\npublic class UploadFileService {\r\n\r\n    @Autowired\r\n    private UploadFileDao uploadFileDao;\r\n}\r\n```\r\n\r\n## 3、注解说明\r\n\r\n#### @Table\r\n\r\n- 描述：表名注解，标识实体类对应的表\r\n- 使用位置：实体类\r\n\r\n```java\r\n\r\n@Table(\"b_upload_file\")\r\npublic class UploadFile implements Serializable {\r\n    private static final long serialVersionUID = -1L;\r\n\r\n}\r\n```\r\n\r\n| 属性    | 类型     | 必须指定 | 默认值 | 描述      |\r\n|-------|--------|------|-----|---------|\r\n| value | String | 是    | \"\"  | 对应数据库表名 |\r\n\r\n#### @Id\r\n\r\n- 描述：主键注解，标识实体类主键属性\r\n- 使用位置：实体类属性\r\n\r\n```java\r\n\r\n@Table(\"b_upload_file\")\r\npublic class UploadFile implements Serializable {\r\n    private static final long serialVersionUID = -1L;\r\n\r\n    @Id(idType = IdType.AUTO_INCREMENT)\r\n    @Column(value = \"id\")\r\n    private Long id;\r\n}\r\n```\r\n\r\n| 属性     | 类型     | 必须指定 | 默认值          | 描述                                                         |\r\n|--------|--------|------|--------------|------------------------------------------------------------|\r\n| idType | String | 是    | IdType.INPUT | 主键策略                                                       |\r\n| value  | String | 否    | \"\"           | 若 idType 类型是 sequence， value 则代表的是sequence 序列的 sql 内容，此时必填 |\r\n\r\n##### IdType主键策略说明\r\n\r\n| 值              | 描述                                                            |\r\n|----------------|---------------------------------------------------------------|\r\n| INPUT          | 自行 set 主键值                                                    |  \r\n| AUTO_INCREMENT | 数据库 ID 自增                                                     |  \r\n| OBJECT_ID      | 自动设置 MongoDb objectId 作为主键值                                   |  \r\n| ASSIGN_ID      | 自动设置 雪花ID 作为主键值                                               |  \r\n| UUID           | 自动设置 UUID 作为主键值                                               |  \r\n| SEQUENCE       | 自动设置 调用序列SQL结果 作为主键值                                          |  \r\n| CUSTOM         | 自定义主键ID生成器，需自行实现 IdGeneratorInterface 接口，详见[自定义ID生成器](#idGen) | \r\n\r\n#### @Column\r\n\r\n- 描述：字段注解，标识实体类属性和字段的对应关系\r\n- 使用位置：实体类属性\r\n\r\n```java\r\n\r\n@Table(\"b_upload_file\")\r\npublic class UploadFile implements Serializable {\r\n    private static final long serialVersionUID = -1L;\r\n\r\n    @Id(idType = IdType.AUTO_INCREMENT)\r\n    @Column(value = \"id\")\r\n    private Long id;\r\n\r\n    @Column(\"file_id\")\r\n    private String fileId;\r\n}\r\n```\r\n\r\n| 属性    | 类型     | 必须指定 | 默认值 | 描述       |\r\n|-------|--------|------|-----|----------|\r\n| value | String | 是    | \"\"  | 对应数据库字段名 |\r\n\r\n## 4、BaseDao CRUD接口说明\r\n\r\n### 查询操作\r\n\r\n| 方法                                                                              | 说明                                                       |\r\n|---------------------------------------------------------------------------------|----------------------------------------------------------|\r\n| `List\u003cT\u003e selectAll();`                                                          | 查询所有数据并返回实体类对象列表，类型使用的是xxxDao\u003cT\u003e的类型                      |\r\n| `\u003cF\u003e List\u003cF\u003e select(String sql, Class\u003cF\u003e classz, Object... params);`            | 根据给定的sql语句和实体类型和参数，查询数据并返回实体类对象列表                        |\r\n| `List\u003cT\u003e select(String sql, Object... params);`                                 | 根据给定的sq语句l和参数，查询数据并返回实体类对象列表，类型使用的是xxxDao\u003cT\u003e的类型          |\r\n| `\u003cF\u003e F selectOne(String sql, Class\u003cF\u003e classz, Object... params);`               | 根据给定的sql语句和实体类型和参数，查询数据并返回一个实体类对象                        |\r\n| `T selectOne(String sql, Object... params);`                                    | 根据给定的sql语句和参数，查询数据并返回一个实体类对象，类型使用的是xxxDao\u003cT\u003e的类型          |\r\n| `List\u003cMap\u003cString, Object\u003e\u003e selectMap(String sql, Object... params);`            | 根据给定的sql语句和参数，查询数据并返回Map\u003cString, Object\u003e列表               |\r\n| `Map\u003cString, Object\u003e selectOneMap(String sql, Object... params);`               | 根据给定的sql语句和参数，查询数据并返回一个Map\u003cString, Object\u003e对象             |\r\n| `\u003cT\u003e T selectForObject(String sql, Class\u003cT\u003e clazz, Object... params);`          | 根据给定的sql语句和实体类型和参数，查询数据并返回一个值（常用于查count）                 |\r\n| `Page\u003cF\u003e paginate(String sql, Class\u003cF\u003e clazz, Page\u003cF\u003e page, Object... params);` | 根据给定的sql语句和参数，执行分页查询，返回Page对象，类型使用的Class\u003cF\u003e传入的自定义类型      |\r\n| `Page\u003cT\u003e paginate(String sql, Page\u003cT\u003e page, Object... params);`                 | 根据给定的sql语句和参数，执行分页查询，返回Page对象，类型使用的是xxxDao\u003cT\u003e的类型         |\r\n| `T selectById(ID id);`                                                          | 根据主键ID值，查询数据并返回一个实体类对象，类型使用的是xxxDao\u003cT\u003e的类型                |\r\n| `T selectByIds(List\u003cID\u003e ids);`                                                  | 根据主键ID值列表，查询数据并返回实体类对象列表，类型使用的是xxxDao\u003cT\u003e的类型              |\r\n| `T selectByIds(ID... id);`                                                      | 根据主键ID值可变参数列表，查询数据并返回实体类对象列表，类型使用的是xxxDao\u003cT\u003e的类型          |\r\n| `List\u003cT\u003e select(T entity);`                                                     | 实体类里面非null的属性作为查询条件，查询数据库并返回实体类对象列表，类型使用的是xxxDao\u003cT\u003e的类型   |\r\n| `List\u003cT\u003e select(QueryCriteria\u003cT\u003e criteria);`                                    | 根据查询构造器查询，返回多条，类型使用的是xxxDao\u003cT\u003e的类型                        |\r\n| `List\u003cT\u003e select(LambdaQueryCriteria\u003cT\u003e lambdaCriteria);`                        | 根据查询构造器(lambda)查询，返回多条，查询数据并返回一个实体类对象，类型使用的是xxxDao\u003cT\u003e的类型 |\r\n| `T selectOne(T entity);`                                                        | 实体类里面非null的属性作为查询条件，查询数据并返回一个实体类对象，类型使用的是xxxDao\u003cT\u003e的类型    |\r\n| `T selectOne(QueryCriteria\u003cT\u003e criteria);`                                       | 根据查询构造器执行查询，返回一条，类型使用的是xxxDao\u003cT\u003e的类型                      |\r\n| `T selectOne(LambdaQueryCriteria\u003cT\u003e lambdaCriteria);`                           | 根据查询构造器(lambda)执行查询，返回一条，类型使用的是xxxDao\u003cT\u003e的类型              |\r\n| `Page\u003cT\u003e paginate(T entity, Page\u003cT\u003e page);`                                     | 根据实体类里面非null的属性作为查询条件，执行分页查询，返回Page对象，类型使用的是xxxDao\u003cT\u003e的类型 |\r\n| `Page\u003cT\u003e paginate(QueryCriteria\u003cT\u003e criteria, Page\u003cT\u003e page);`                    | 根据查询构造器执行分页查询，返回Page对象，类型使用的是xxxDao\u003cT\u003e的类型                |\r\n| `Page\u003cT\u003e paginate(LambdaQueryCriteria\u003cT\u003e lambdaCriteria, Page\u003cT\u003e page);`        | 根据查询构造器(lambda)执行分页查询，返回Page对象，类型使用的是xxxDao\u003cT\u003e的类型        |\r\n| `Long selectCount(QueryCriteria\u003cT\u003e criteria);`                                  | 根据查询构造器执行总记录数查询，返回符合条件的总记录数量                             |\r\n| `Long selectCount(LambdaQueryCriteria\u003cT\u003e lambdaCriteria);`                      | 根据查询构造器(lambda)执行总记录数查询，返回符合条件的总记录数量                     |\r\n| `boolean exists(QueryCriteria\u003cT\u003e criteria);`                                    | 根据查询构造器执行查询记录是否存在，返回true或者false                          |\r\n| `boolean exists(LambdaQueryCriteria\u003cT\u003e lambdaCriteria);`                        | 根据查询构造器(lambda)执行查询记录是否存在，返回true或者false                  |\r\n\r\n### 插入操作\r\n\r\n| 方法                                                               | 说明                                                                                             |\r\n|------------------------------------------------------------------|------------------------------------------------------------------------------------------------|\r\n| `int insert(String sql, Object... params);`                      | 根据提供的sql语句和提供的参数，执行插入                                                                          |\r\n| `int insert(T entity);`                                          | 插入entity里的数据，忽略entity里值为null的属性，如果主键策略为assignId、uuid、objectId或custom，那将在entity里返回自动生成的主键值      |\r\n| `int insert(T entity, boolean ignoreNulls);`                     | 插入entity里的数据，可选择是否忽略entity里值为null的属性，如果主键策略为assignId、uuid、objectId或custom，那将在entity里返回自动生成的主键值 |\r\n| `Long insertReturnAutoIncrement(T entity);`                      | 插入entity里的数据，将忽略entity里属性值为null的属性，并且返回自增的主键                                                   |\r\n| `Long insertReturnAutoIncrement(T entity, boolean ignoreNulls);` | 插入entity里的数据，可选择是否忽略entity里值为null的属性，并且返回自增的主键                                                 |\r\n\r\n### 更新操作\r\n\r\n| 方法                                                                             | 说明                                                                  |\r\n|--------------------------------------------------------------------------------|---------------------------------------------------------------------|\r\n| `int update(String sql, Object... params);`                                    | 根据提供的SQL语句和提供的参数，执行修改                                               |\r\n| `int updateById(T entity);`                                                    | 根据entity提供SET子句，主键值提供WHERE条件，执行修改，默认忽略entity里值为null的属性              |\r\n| `int updateById(T entity, boolean ignoreNulls);`                               | 根据entity提供SET子句，主键值提供WHERE条件，执行修改，可选择是否忽略entity里值为null的属性           |\r\n| `int update(T entity, UpdateCriteria\u003cT\u003e criteria);`                            | 根据entity提供SET子句，条件构造器提供WHERE条件，执行修改，默认忽略entity里值为null的属性            |\r\n| `int update(T entity, LambdaUpdateCriteria\u003cT\u003e criteria);`                      | 根据entity提供SET子句，条件构造器（lambda）提供WHERE条件，执行修改，默认忽略entity里值为null的属性    |\r\n| `int update(T entity, boolean ignoreNulls, UpdateCriteria\u003cT\u003e criteria);`       | 根据entity提供SET子句，条件构造器，执行修改提供WHERE条件，执行修改，可选择是否忽略entity里值为null的属性    |\r\n| `int update(T entity, boolean ignoreNulls, LambdaUpdateCriteria\u003cT\u003e criteria);` | 根据entity提供SET子句，条件构造器（lambda）提供WHERE条件，执行修改，可选择是否忽略entity里值为null的属性 |\r\n| `int update(UpdateCriteria\u003cT\u003e criteria);`                                      | 只根据条件构造器来构建，需配合.set方法来使用                                            |\r\n| `int update(LambdaUpdateCriteria\u003cT\u003e criteria);`                                | 只根据条件构造器（lambda）来构建，需配合.set方法来使用                                  |\r\n\r\n### 删除操作\r\n\r\n| 方法                                              | 说明                                            |\r\n|-------------------------------------------------|-----------------------------------------------|\r\n| `int delete(String sql, Object... params);`     | 根据提供的SQL语句和提供的参数，执行删除                         |\r\n| `int deleteById(ID id);`                        | 根据主键ID进行删除，类型使用的是xxxDao\u003cT, ID\u003e的类型             |\r\n| `int deleteByIds(List\u003cID\u003e ids);`                | 根据主键ID列表进行删除，类型使用的是xxxDao\u003cT, ID\u003e的类型           |\r\n| `int deleteByIds(ID... ids);`                   | 根据主键ID可变参数列表进行删除，类型使用的是xxxDao\u003cT, ID\u003e的类型       |\r\n| `int delete(T entity);`                         | 根据entity里的属性值进行删除，entity里不为null的属性，将作为where参数 |\r\n| `int delete(UpdateCriteria\u003cT\u003e criteria);`       | 根据条件构造器，将作为where参数                            |\r\n| `int delete(LambdaUpdateCriteria\u003cT\u003e criteria);` | 根据条件构造器（lambda），将作为where参数                    |\r\n\r\n### 使用SQL构造器进行操作（`1.8.2`版本新增）\r\n\r\n| 方法                                                         | 说明                                                |\r\n|------------------------------------------------------------|---------------------------------------------------|\r\n| `int execute(SQL sql);`                                    | 根据提供的SQL构造器，执行删除、新增、或更新操作                         |\r\n| `int delete(SQL sql);`                                     | 根据提供的SQL构造器，执行删除操作                                |\r\n| `int update(SQL sql);`                                     | 根据提供的SQL构造器，执行更新操作                                |\r\n| `int insert(SQL sql);`                                     | 根据提供的SQL构造器，执行新增操作                                |\r\n| `\u003cF\u003e List\u003cF\u003e select(String SQL, Class\u003cF\u003e classz);`         | 根据给定的SQL构造器和实体类型数，查询数据库并返回实体类对象列表                 |\r\n| `List\u003cT\u003e select(SQL sql)`                                  | 根据给定的SQL构造器，查询数据库并返回实体类对象列表，类型使用的是xxxDao\u003cT\u003e的类型    |\r\n| `Page\u003cT\u003e paginate(SQL sql, Page\u003cT\u003e page);`                 | 根据给定的SQL构造器，执行分页查询，返回Page对象，类型使用的是xxxDao\u003cT\u003e的类型    |\r\n| `Page\u003cF\u003e paginate(SQL sql, Class\u003cF\u003e clazz, Page\u003cF\u003e page);` | 根据给定的SQL构造器，执行分页查询，返回Page对象，类型使用的Class\u003cF\u003e传入的自定义类型 |\r\n| `T selectOne(SQL sql);`                                    | 根据给定的SQL构造器，查询数据并返回一个实体类对象，类型使用的是xxxDao\u003cT\u003e的类型     |\r\n| `\u003cF\u003e F selectOne(SQL sql, Class\u003cF\u003e clazz);`                | 根据给定的SQL构造器，查询数据并返回一个实体类对象，类型使用的Class\u003cF\u003e传入的自定义类型  |\r\n\r\n## 5、条件构造器（Criteria）\r\n\r\n### 功能使用说明\r\n\r\n#### 条件构造器(AbstractCriteria \u0026 AbstractLambdaCriteria)\r\n\r\n\u003e QueryCriteria(LambdaQueryCriteria) 和 UpdateCriteria(LambdaUpdateCriteria) 的父类\r\n\u003e 用于生成 sql 的 where 条件\r\n\u003e\r\n\u003e 其中带Lambda字样的构造器 是基于 Lambda 表达式的条件构造器，它允许你使用 Lambda 表达式来指定字段，避免了硬编码字段名的问题。\r\n\u003e\r\n以下方法均有重载whether参数（第一个参数）后的方法，当whether=false时，不执行后面的条件，例如：`eq(boolean whether, String field, R value)`\r\n\r\n| 方法             | 说明                    | 普通示例                                       | lambda示例                                                 | 等价SQL                            |\r\n|----------------|-----------------------|--------------------------------------------|----------------------------------------------------------|----------------------------------|\r\n| eq             | 等于 =                  | eq(\"name\", \"张三\")                           | eq(User::getName, \"张三\")                                  | AND name = '张三'                  |\r\n| orEq           | 等于 =                  | orEq(\"name\", \"张三\")                         | orEq(User::getName, \"张三\")                                | OR name = '张三'                   |\r\n| notEq          | 不等于 \u003c\u003e                | notEq(\"name\", \"张三\")                        | notEq(User::getName, \"张三\")                               | AND name \u003c\u003e '张三'                 |\r\n| orNotEq        | 不等于 \u003c\u003e                | orNotEq(\"name\", \"张三\")                      | orNotEq(User::getName, \"张三\")                             | OR name \u003c\u003e '张三'                  |\r\n| isNull         | 等于null                | isNull(\"name\")                             | isNull(User::getName)                                    | AND name IS NULL                 |\r\n| orIsNull       | 等于null                | orIsNull(\"name\")                           | orIsNull(User::getName)                                  | OR name IS NULL                  |\r\n| isNotNull      | 不等于null               | isNotNull(\"name\")                          | isNotNull(User::getName)                                 | AND name IS NOT NULL             |\r\n| orIsNotNull    | 不等于null               | orIsNotNull(\"name\")                        | orIsNotNull(User::getName)                               | OR name IS NOT NULL              |\r\n| lt             | 小于 \u003c                  | lt(\"name\", \"张三\")                           | lt(User::getName, \"张三\")                                  | AND name \u003c '张三'                  |\r\n| orLt           | 小于 \u003c                  | orLt(\"name\", \"张三\")                         | orLt(User::getName, \"张三\")                                | OR name \u003c '张三'                   |\r\n| lte            | 小于等于 \u003c=               | lte(\"name\", \"张三\")                          | lte(User::getName, \"张三\")                                 | AND name \u003c= '张三'                 |\r\n| orLte          | 小于等于 \u003c=               | orLte(\"name\", \"张三\")                        | orLte(User::getName, \"张三\")                               | OR name \u003c= '张三'                  |\r\n| gt             | 大于 \u003e                  | gt(\"name\", \"张三\")                           | gt(User::getName, \"张三\")                                  | AND name \u003e '张三'                  | \r\n| orGt           | 大于 \u003e                  | orGt(\"name\", \"张三\")                         | orGt(User::getName, \"张三\")                                | OR name \u003e '张三'                   |\r\n| gte            | 大于等于 \u003e=               | gte(\"name\", \"张三\")                          | gte(User::getName, \"张三\")                                 | AND name \u003e= '张三'                 |\r\n| orGte          | 大于等于 \u003e=               | orGte(\"name\", \"张三\")                        | orGte(User::getName, \"张三\")                               | OR name \u003e= '张三'                  |\r\n| in             | SQL里的IN操作             | in(\"name\", {\"张三\",\"李四\"})                    | in(User::getName, \"张三\")                                  | AND name IN ('张三','李四')          |\r\n| orIn           | SQL里的IN操作             | orIn(\"name\", {\"张三\",\"李四\"})                  | orIn(User::getName, \"张三\")                                | OR name IN ('张三','李四')           |\r\n| notIn          | SQL里的IN操作             | notIn(\"name\", \"张三\")                        | notIn(User::getName, \"张三\")                               | AND name NOT IN ('张三','李四')      |\r\n| orNotIn        | SQL里的IN操作             | orNotIn(\"name\", {\"张三\",\"李四\"})               | orNotIn(User::getName, \"张三\")                             | OR name NOT IN ('张三','李四')       |\r\n| between        | NOT BETWEEN 值1 AND 值2 | between(\"age\", 10, 18)                     | between(User::getAge, 10, 18)                            | AND (age BETWEEN 10 AND 18 )     |\r\n| orBetween      | NOT BETWEEN 值1 AND 值2 | orBetween(\"age\", 10, 18)                   | orBetween(User::getAge, 10, 18)                          | OR (age BETWEEN 10 AND 18 )      |\r\n| notBetween     | NOT BETWEEN 值1 AND 值2 | notBetween(\"age\", 10, 18)                  | notBetween(User::getAge, 10, 18)                         | AND (age NOT BETWEEN 10 AND 18 ) |\r\n| orNotBetween   | NOT BETWEEN 值1 AND 值2 | orNotBetween(\"age\", 10, 18)                | orNotBetween(User::getAge, 10, 18)                       | OR (age NOT BETWEEN 10 AND 18 )  |\r\n| like           | LIKE '%值%'            | like(\"name\", \"张三\")                         | like(User::getName, \"张三\")                                | AND name LIKE '%张三%'             |\r\n| orLike         | LIKE '%值%'            | orLike(\"name\", \"张三\")                       | orLike(User::getName, \"张三\")                              | OR name LIKE '%张三%'              |\r\n| notLike        | NOT LIKE '%值%'        | notLike(\"name\", \"张三\")                      | notLike(User::getName, \"张三\")                             | AND name NOT LIKE '%张三%'         |\r\n| orNotLike      | NOT LIKE '%值%'        | orNotLike(\"name\", \"张三\")                    | orNotLike(User::getName, \"张三\")                           | OR name NOT LIKE '%张三%'          |\r\n| like           | LIKE '%值%'            | like(\"name\", \"张三\")                         | like(User::getName, \"张三\")                                | AND name LIKE '%张三%'             |\r\n| orLike         | LIKE '%值%'            | orLike(\"name\", \"张三\")                       | orLike(User::getName, \"张三\")                              | OR name LIKE '%张三%'              |\r\n| notLike        | NOT LIKE '%值%'        | notLike(\"name\", \"张三\")                      | notLike(User::getName, \"张三\")                             | AND name NOT LIKE '%张三%'         |\r\n| orNotLike      | NOT LIKE '%值%'        | orNotLike(\"name\", \"张三\")                    | orNotLike(User::getName, \"张三\")                           | OR name NOT LIKE '%张三%'          |\r\n| leftLike       | LIKE '%值'             | leftLike(\"name\", \"张三\")                     | leftLike(User::getName, \"张三\")                            | AND name LIKE '%张三'              |\r\n| orLeftLike     | LIKE '%值'             | orLeftLike(\"name\", \"张三\")                   | orLeftLike(User::getName, \"张三\")                          | OR name LIKE '%张三'               |\r\n| notLeftLike    | NOT LIKE '%值'         | notLeftLike(\"name\", \"张三\")                  | notLeftLike(User::getName, \"张三\")                         | AND name NOT LIKE '%张三'          |\r\n| orNotLeftLike  | NOT LIKE '%值'         | orNotLeftLike(\"name\", \"张三\")                | orNotLeftLike(User::getName, \"张三\")                       | OR name NOT LIKE '%张三'           |\r\n| rightLike      | LIKE '值%'             | rightLike(\"name\", \"张三\")                    | rightLike(User::getName, \"张三\")                           | AND name LIKE '张三%'              |\r\n| orRightLike    | LIKE '值%'             | orRightLike(\"name\", \"张三\")                  | orRightLike(User::getName, \"张三\")                         | OR name LIKE '张三%'               |\r\n| notRightLike   | NOT LIKE '值%'         | notRightLike(\"name\", \"张三\")                 | notRightLike(User::getName, \"张三\")                        | AND name NOT LIKE '张三%'          |\r\n| orNotRightLike | NOT LIKE '值%'         | orNotRightLike(\"name\", \"张三\")               | orNotRightLike(User::getName, \"张三\")                      | OR name NOT LIKE '张三%'           |\r\n| or             | OR 嵌套                 | or(i -\u003e i.eq(\"name\", \"张三\").lt(\"age\", 18))  | or(i -\u003e i.eq(User::getName, \"张三\").lt(User::getAge, 18))  | OR (name = '张三' AND age \u003c 18)    |\r\n| and            | AND 嵌套                | and(i -\u003e i.eq(\"name\", \"张三\").lt(\"age\", 18)) | and(i -\u003e i.eq(User::getName, \"张三\").lt(User::getAge, 18)) | AND (name = '张三' AND age \u003c 18)   |\r\n\r\n#### 查询构造器(QueryCriteria \u0026 LambdaQueryCriteria)\r\n\r\n\u003e 继承自条件构造器，可额外自定义查询的排序和字段内容，查询接口适用\r\n\r\n| 方法          | 说明                     | 普通示例                  | lambda示例                            | 等价SQL              |\r\n|-------------|------------------------|-----------------------|-------------------------------------|--------------------|\r\n| orderBy     | 排序，true=desc,false=asc | orderBy(\"name\", true) | orderBy(User::getName, true)        | ORDER BY name DESC |\r\n| orderBy     | 升序排序                   | orderBy(\"name\")       | orderBy(User::getName)              | ORDER BY name      |\r\n| orderByDesc | 降序排序                   | orderByDesc(\"name\")   | orderByDesc(User::getName)          | ORDER BY name DESC |\r\n| select      | 设置查询字段                 | select(\"name\", \"age\") | select(User::getName, User::getAge) | SELECT name,age    |\r\n| last        | 直接在查询的最后添加一个 SQL 片段    | last(\"LIMIT 1\")       | last(\"LIMIT 1\")                     | LIMIT 1            |\r\n\r\n##### QueryCriteria示例\r\n\r\n```java\r\nList\u003cInteger\u003e ids = new ArrayList\u003cInteger\u003e() {{\r\n    add(1);\r\n    add(2);\r\n    add(3);\r\n}};\r\n\r\nQueryCriteria\u003cPerson\u003e criteria = new QueryCriteria\u003c\u003e();\r\ncriteria.lt(\"age\", 28);\r\ncriteria.eq(\"created_at\", new Date());\r\ncriteria.in(\"id\", ids);\r\ncriteria.orderBy(\"age\", true);\r\n// 等价于 SELECT 所有字段 FROM person WHERE age \u003c 28 AND created_at = '2023-08-05 17:31:26' AND id IN (1,2,3) ORDER BY age DESC\r\n\r\nQueryCriteria\u003cPerson\u003e criteria = new QueryCriteria\u003c\u003e();\r\ncriteria.select(\"id\", \"name\");\r\ncriteria.lt(\"age\", 28);\r\n// 等价于 SELECT id,name FROM person WHERE age \u003c 28\r\n```\r\n\r\n##### LambdaQueryCriteria示例\r\n\r\n```java\r\nList\u003cLong\u003e ids = new ArrayList\u003cLong\u003e() {{\r\n    add(1L);\r\n    add(2L);\r\n    add(3L);\r\n}};\r\n\r\nLambdaQueryCriteria\u003cUploadFile\u003e criteria = new LambdaQueryCriteria\u003c\u003e();\r\ncriteria.lt(UploadFile::getFileId, \"1000\");\r\ncriteria.eq(UploadFile::getFileMd5, \"b8394b15e02c50b508b3e46cc120f0f5\");\r\ncriteria.in(UploadFile::getId, ids);\r\ncriteria.orderBy(UploadFile::getCreatedAt, true);\r\n// 等价于 SELECT 所有字段 FROM b_upload_file WHERE file_id \u003c '1000' AND file_md5 = 'b8394b15e02c50b508b3e46cc120f0f5' AND id IN (1,2,3) ORDER BY created_at DESC\r\n\r\nLambdaQueryCriteria\u003cUploadFile\u003e criteria = new LambdaQueryCriteria\u003c\u003e();\r\ncriteria.select(UploadFile::getFileId, UploadFile::getFileMd5);\r\ncriteria.lt(UploadFile::getFileId, \"1000\");\r\n// 等价于 SELECT file_id,file_md5 FROM b_upload_file WHERE file_id \u003c '1000'\r\n```\r\n\r\n#### 更新构造器(UpdateCriteria \u0026 LambdaUpdateCriteria)\r\n\r\n\u003e 继承自条件构造器，可额外自定义更新的字段内容和值，更新接口适用\r\n\r\n| 方法           | 说明     | 普通示例                   | lambda示例                      | 等价SQL             |\r\n|--------------|--------|------------------------|-------------------------------|-------------------|\r\n| set          | 设置更新字段 | set(\"name\", \"张三\")      | set(User::getName, \"张三\")      | set name = '张三'   |\r\n| setIncrement | 设置字段自增 | setIncrement(\"age\", 1) | setIncrement(User::getAge, 1) | set age = age + 1 |\r\n| setDecrement | 设置字段自减 | setDecrement(\"age\", 1) | setDecrement(User::getAge, 1) | set age = age - 1 |\r\n\r\n##### UpdateCriteria示例\r\n\r\n```java\r\nint num = projectInfoDao.update(new UpdateCriteria\u003cTProjectInfo\u003e()\r\n        .set(\"created_at\", new Date())\r\n        .set(\"updated_by\", \"admin3\")\r\n        .eq(\"project_name\", \"批量项目1\"));\r\n// 等价于 UPDATE t_project_info SET created_at = '2023-08-05 17:31:26', updated_by = 'admin3' WHERE project_name = '批量项目1'\r\n\r\nTProjectInfo project1 = new TProjectInfo();\r\nproject1.setCreatedAt(new Date());\r\nproject1.setUpdatedBy(\"admin3\");\r\n\r\nint num = projectInfoDao.update(project1, new UpdateCriteria\u003cTProjectInfo\u003e().eq(\"project_name\", \"批量项目1\"));\r\n// 等价于 UPDATE t_project_info SET created_at = '2023-08-05 17:31:26', updated_by = 'admin3' WHERE project_name = '批量项目1'\r\n```\r\n\r\n##### LambdaUpdateCriteria示例\r\n\r\n```java\r\nint num = projectInfoDao.update(new LambdaUpdateCriteria\u003cTProjectInfo\u003e()\r\n        .set(TProjectInfo::getEnableAt, new Date())\r\n        .set(TProjectInfo::getUpdatedBy, \"admin2\")\r\n        .eq(TProjectInfo::getProjectName, \"批量项目1\"));\r\n// 等价于 UPDATE t_project_info SET enable_at = '2023-08-05 17:31:26', updated_by = 'admin2' WHERE project_name = '批量项目1'\r\n\r\nTProjectInfo project1 = new TProjectInfo();\r\nproject1.setCreatedAt(new Date());\r\nproject1.setUpdatedBy(\"admin3\");\r\n\r\nint num = projectInfoDao.update(project1, new LambdaUpdateCriteria\u003cTProjectInfo\u003e().eq(TProjectInfo::getProjectName, \"批量项目1\"));\r\n// 等价于 UPDATE t_project_info SET created_at = '2023-08-05 17:31:26', updated_by = 'admin3' WHERE project_name = '批量项目1'\r\n```\r\n\r\n#### CriteriaBuilder的使用和示例\r\n\r\nTiny-Jdbc 提供了 CriteriaBuilder 类，它是一个静态工厂类，用于快速创建 QueryCriteria、LambdaQueryCriteria、UpdateCriteria 和\r\nLambdaUpdateCriteria 的实例。使用 CriteriaBuilder 可以减少代码量，提高开发效率。\r\n\r\n```java\r\n LambdaQueryCriteria queryCriteria = CriteriaBuilder.\u003cTProjectInfo\u003elambdaQuery()\r\n        .select(TProjectInfo::getId, TProjectInfo::getProjectName, TProjectInfo::getCreatedAt)\r\n        .eq(TProjectInfo::getProjectName, \"xxxx\")\r\n        .eq(TProjectInfo::getId, 1709630713614L);\r\n```\r\n\r\n## 6、SQL构造器（SQL）\r\n\r\nTiny-Jdbc 提供了 SQL 类，它是一个静态工厂类，用于快速创建 SQL 的实例。使用 SQL 可以减少代码量，提高开发效率。\r\n[使用文档](SQL.md)\r\n\r\n\u003ch2 id=\"idGen\"\u003e 7、自定义ID生成器\u003c/h2\u003e\r\n\r\n需要实现 IdGeneratorInterface 接口，并且声明为 Bean 供 Spring 扫描注入\r\n\r\n### 方式一：使用@Component注册成bean\r\n\r\n```java\r\n\r\n@Component\r\npublic class CustomIdGeneratorInterface implements IdGeneratorInterface {\r\n\r\n    @Override\r\n    public Object nextId(Object entity) {\r\n        // 可以将当前传入的class全类名来作为业务键,\r\n        // 或者通过反射获取表名进行业务Id调用生成\r\n        String bizKey = entity.getClass().getName();\r\n        // 自定义ID生成策略，推荐最终返回值使用包装类\r\n        Long id = ....;\r\n        // 返回生成的id值即可.\r\n        return id;\r\n    }\r\n}\r\n```\r\n\r\n### 方式二：在@Configuration配置类中注册\r\n\r\n```java\r\n\r\n@Bean\r\npublic IdGeneratorInterface idGenerator() {\r\n    return new IdGeneratorInterface() {\r\n        @Override\r\n        public Object nextId(Object entity) {\r\n            // 可以将当前传入的class全类名来作为业务键,\r\n            // 或者通过反射获取表名进行业务Id调用生成\r\n            String bizKey = entity.getClass().getName();\r\n            // 自定义ID生成策略，推荐最终返回值使用包装类\r\n            Long id = ....;\r\n            // 返回生成的id值即可.\r\n            return id;\r\n        }\r\n    };\r\n}\r\n```\r\n\r\n## 8、自定义雪花ID算法数据中心标识和机器标识\r\n\r\n需要实现 SnowflakeConfigInterface 接口，并且声明为 Bean 供 Spring 扫描注入\r\n\r\n### 方式一：使用@Component注册成bean\r\n\r\n```java\r\n\r\n@Component\r\npublic class CustomSnowflakeConfigInterface implements SnowflakeConfigInterface {\r\n\r\n    @Override\r\n    public DatacenterAndWorkerProvider getDatacenterIdAndWorkerId() {\r\n        DatacenterAndWorkerProvider provider = new DatacenterAndWorkerProvider();\r\n\r\n        // 自定义datacenterId和workerId生成逻辑\r\n        Long datacenterId = ....;\r\n        Long workerId = ....;\r\n\r\n        provider.setDatacenterId(datacenterId);\r\n        provider.setWorkerId(workerId);\r\n        return provider;\r\n    }\r\n}\r\n```\r\n\r\n### 方式二：在@Configuration配置类中注册\r\n\r\n```java\r\n\r\n@Bean\r\npublic SnowflakeConfigInterface snowflakeConfigInterface() {\r\n    return new SnowflakeConfigInterface() {\r\n        @Override\r\n        public DatacenterAndWorkerProvider getDatacenterIdAndWorkerId() {\r\n            DatacenterAndWorkerProvider provider = new DatacenterAndWorkerProvider();\r\n            // 自定义datacenterId和workerId生成逻辑\r\n            Long datacenterId = ....;\r\n            Long workerId = ....;\r\n            provider.setDatacenterId(datacenterId);\r\n            provider.setWorkerId(workerId);\r\n            return provider;\r\n        }\r\n    };\r\n}\r\n```\r\n\r\n## 9、无Entity实体类操作\r\n\r\nTiny-Jdbc 提供了 `JdbcTemplateHelper` 工具类，支持无实体类映射场景下的灵活数据操作。适用于：\r\n- 无明确业务实体的统计分析场景（如数据大屏、聚合报表）\r\n- 多表联合查询且无需实体映射的场景\r\n- 临时性或灵活性较高的数据操作需求\r\n\r\n### 核心优势\r\n- **无需继承 BaseDao**：直接通过工具类调用，解耦实体依赖\r\n- **支持复杂 SQL**：可执行任意自定义 SQL 语句\r\n- **全操作覆盖**：包含查询、分页、插入、更新、删除等完整能力\r\n\r\n#### 使用示例\r\n\r\n通过 Spring 依赖注入使用，示例如下：\r\n\r\n```java\r\n@Repository\r\npublic class OtherDao {\r\n\r\n    @Autowired\r\n    private JdbcTemplateHelper helper;\r\n\r\n  // 多表联合查询示例\r\n  public List\u003cDashboardVO\u003e queryDashboardData() {\r\n    String sql = \"SELECT \" +\r\n            \"p.id AS projectId, \" +\r\n            \"p.name AS projectName, \" +\r\n            \"COUNT(t.id) AS taskCount, \" +\r\n            \"SUM(CASE WHEN t.status = 'COMPLETED' THEN 1 ELSE 0 END) AS completedCount \" +\r\n            \"FROM t_project p \" +\r\n            \"LEFT JOIN t_task t ON p.id = t.project_id \" +\r\n            \"GROUP BY p.id\";\r\n\r\n    return helper.select(sql, DashboardVO.class);\r\n  }\r\n\r\n  // 分页查询示例\r\n  public Page\u003cProjectInfo\u003e paginateProjects(int pageNum, int pageSize) {\r\n    Page\u003cProjectInfo\u003e page = new Page\u003c\u003e(pageNum, pageSize);\r\n    String sql = \"SELECT id, name, create_time FROM t_project ORDER BY create_time DESC\";\r\n    return helper.paginate(sql, ProjectInfo.class, page);\r\n  }\r\n\r\n  // 插入操作示例\r\n  public int createProject(Map\u003cString, Object\u003e projectData) {\r\n    String sql = \"INSERT INTO t_project (name, owner_id, status) VALUES (?, ?, ?)\";\r\n    return helper.insert(\r\n            sql,\r\n            projectData.get(\"name\"),\r\n            projectData.get(\"ownerId\"),\r\n            projectData.get(\"status\")\r\n    );\r\n  }\r\n}\r\n```\r\n\r\n## 10、一些使用示例\r\n\r\n创建 ProjectInfoDao\r\n\r\n```java\r\n\r\nimport org.example.entity.TProjectInfo;\r\nimport org.springframework.stereotype.Repository;\r\nimport org.tinycloud.jdbc.BaseDao;\r\n\r\n@Repository\r\npublic class ProjectInfoDao extends BaseDao\u003cTProjectInfo, Long\u003e {\r\n\r\n}\r\n```\r\n\r\n1. 查询操作\r\n\r\n```java\r\n\r\n@Autowired\r\nprivate ProjectDao projectDao;\r\n\r\n// 查询所有的项目，返回列表\r\nList\u003cTProjectInfo\u003e projectList = projectDao.select(\"select * from t_project_info order by created_at desc\");\r\n\r\n// 自定义返回类型，返回列表\r\nList\u003cProjectInfoVo\u003e projectList = projectDao.select(\"select * from t_project_info order by created_at desc\", ProjectInfoVo.class);\r\n\r\n// 查询所有的项目，返回列表\r\nList\u003cTProjectInfo\u003e projectList = projectDao.select(\"select * from t_project_info order by created_at desc\");\r\n\r\n// 查询所以的项目，返回Map列表\r\nList\u003cMap\u003cString, Object\u003e\u003e projectList = projectDao.selectMap(\"select * from t_project_info order by created_at desc\");\r\n\r\n// 查询id=1的项目，返回列表\r\nList\u003cTProjectInfo\u003e projectList = projectDao.select(\"select * from t_project_info where id = ? \", 1);\r\n\r\n// 模糊查询项目，返回列表\r\nList\u003cTProjectInfo\u003e projectList = projectDao.select(\"select * from t_project_info where project_name like CONCAT('%', ?, '%')\", \"测试项目\");\r\n\r\n// 查询id=1的项目，返回对象\r\nTProjectInfo project = projectDao.selectOne(\"select * from t_project_info where id = ? \", 1);\r\n\r\n// 查询记录数\r\nInteger count = projectDao.selectForObject(\"select count(*) from t_project_info order by created_at desc\", Integer.class));\r\n\r\n// 分页查询id\u003e100的记录，第一页，每页10个\r\nPage\u003cTProjectInfo\u003e page = projectDao.paginate(\"select * from t_project_info order by created_at desc where id \u003e ?\", new Page\u003cTProjectInfo\u003e(1, 10), 100));\r\n\r\n// 查询id=3的项目信息列表\r\nTProjectInfo project = new TProjectInfo();\r\nproject.\r\n\r\nsetId(3L);\r\n\r\nList\u003cTProjectInfo\u003e projectList = projectDao.select(project);\r\n\r\n// 查询id=3的项目信息\r\nTProjectInfo project = new TProjectInfo();\r\nproject.\r\n\r\nsetId(3L);\r\n\r\nProject project = projectDao.selectOne(project);\r\n\r\n// 查询id=3的项目信息\r\nTProjectInfo project = projectDao.selectById(3L);\r\n\r\n// 查询id=3和id=4的项目信息\r\nList\u003cLong\u003e ids = new ArrayList\u003cLong\u003e();\r\nids.\r\n\r\nadd(3L);\r\nids.\r\n\r\nadd(4L);\r\n\r\nTProjectInfo project = projectDao.selectByIds(ids)\r\n\r\n// 查询id=3的项目信息\r\nLambdaQueryCriteria\u003cTProjectInfo\u003e criteria = new LambdaQueryCriteria\u003c\u003e().eq(Project::getId, 3L);\r\nTProjectInfo project = projectDao.selectOne(criteria);\r\n\r\n// 查询id=3的项目信息\r\nQueryCriteria\u003cTProjectInfo\u003e criteria = new QueryCriteria\u003c\u003e().eq(\"id\", 3L);\r\nTProjectInfo project = projectDao.selectOne(criteria);\r\n\r\n// 分页查询id=3的项目信息，第一页，每页10个\r\nTProjectInfo project = new TProjectInfo();\r\nproject.\r\n\r\nsetId(3L);\r\n\r\nPage\u003cTProjectInfo\u003e page = projectDao.paginate(project, new Page\u003cTProjectInfo\u003e(1, 10));\r\n\r\n// 分页查询id=3的项目信息，第一页，每页10个\r\nQueryCriteria\u003cTProjectInfo\u003e criteria = new QueryCriteria() \u003c\u003e.\r\n\r\neq(\"id\",3L);\r\n\r\nPage\u003cTProjectInfo\u003e page = projectDao.paginate(criteria, new Page\u003cTProjectInfo\u003e(1, 10));\r\n\r\n// 根据条件构造器构建复杂查询条件\r\n// 等价于 `SELECT id,project_name ,del_flag,created_by,updated_by,created_at AS createdAt,updated_at,remark FROM t_project_info WHERE created_by = 'admin' AND del_flag \u003e= 0 AND id IN (1, 5) OR (remark NOT LIKE '%XXX%') ORDER BY created_at DESC`\r\nList\u003cLong\u003e ids = new ArrayList\u003c\u003e();\r\nids.\r\n\r\nadd(1L);\r\nids.\r\n\r\nadd(5L);\r\n\r\nLambdaQueryCriteria\u003cTProjectInfo\u003e criteria = new LambdaQueryCriteria\u003c\u003e()\r\n        .eq(TProjectInfo::getCreatedBy, \"admin\")\r\n        .gte(TProjectInfo::getDelFlag, 0)\r\n        .in(TProjectInfo::getId, ids)\r\n        .or(i -\u003e i.notLike(TProjectInfo::getRemark, \"XXX\"))\r\n        .orderBy(TProjectInfo::getCreatedAt, true);\r\nList\u003cTProjectInfo\u003e projectList = projectDao.select(criteria);\r\n\r\n\r\n// 根据条件构造器构建复杂查询条件\r\n// 等价于：SELECT id,project_name,enable_at,remark,del_flag,created_by,updated_by,created_at,updated_at FROM t_project_info WHERE (del_flag = 1 AND project_name = 'xxx') OR (del_flag = 1 AND project_name = 'yyy') ORDER BY id\r\nList\u003cTProjectInfo\u003e tProjectInfo2s = projectInfoDao.select(\r\n        new QueryCriteria\u003cTProjectInfo\u003e()\r\n                .and(i -\u003e i.eq(\"del_flag\", 1)\r\n                        .eq(\"project_name\", \"xxx\")\r\n                )\r\n                .or(i -\u003e i.eq(\"del_flag\", 1)\r\n                        .eq(\"project_name\", \"yyy\")\r\n                )\r\n                .orderBy(\"id\"));\r\n\r\n\r\n// 根据条件构造器查询记录数量，等价于 `SELECT COUNT(*) FROM t_project_info WHERE id = 1695713712801116162`\r\nLambdaQueryCriteria\u003cTProjectInfo\u003e criteria = new LambdaQueryCriteria\u003c\u003e().eq(Project::getId, 1695713712801116162L);\r\nLong count = projectDao.selectCount(criteria);\r\n\r\n// 根据条件构造器查询记录是否存在，等价于 `SELECT COUNT(*) FROM t_project_info WHERE id = 1695713712801116162`，然后再判断结果count是否大于0\r\nboolean result = projectDao.exists(CriteriaBuilder.\u003cTProjectInfo\u003elambdaQuery().eq(Project::getId, 1695713712801116162L));\r\n\r\n```\r\n\r\n2. 新增操作\r\n\r\n```java\r\n\r\n@Autowired\r\nprivate ProjectDao projectDao;\r\n\r\n// 使用sql插入一条数据\r\nint result = projectDao.insert(\"insert t_into project_info(project_name, del_flag, remark) values (?,?,?)\", \"测试项目\", 1, \"XXXXXXX\");\r\n\r\n// 使用实体类插入一条数据，默认忽略null\r\nTProjectInfo project = new TProjectInfo();\r\nproject.\r\n\r\nsetProjectName(\"xxxx\");\r\nproject.\r\n\r\nsetDelFlag(1);\r\nproject.\r\n\r\nsetCreatedBy(\"admin\");\r\nproject.\r\n\r\nsetRemark(\"XXXX\");\r\n\r\nint result = projectDao.insert(project);\r\n\r\n// 获取生成的主键id，在主键策略为assignId、uuid或objectId时适用\r\nLong id = project.getId();\r\n\r\n// 使用实体类插入一条数据，不忽略null\r\nint result = projectDao.insert(project, false);\r\n\r\n// 获取生成的主键id，在主键策略为assignId、uuid或objectId时适用\r\nLong id = project.getId();\r\n\r\n// 使用实体类插入一条数据，并返回数据库自增的主键值，默认忽略null\r\nint result = projectDao.insertReturnAutoIncrement(project);\r\n\r\n```\r\n\r\n3. 更新操作\r\n\r\n```java\r\n\r\n@Autowired\r\nprivate ProjectDao projectDao;\r\n\r\n// 使用sql插入一条数据\r\nint result = baseDao.update(\"\"update project_info set project_name = ? where\r\nid=?\"\",new Object[]{\"测试项目\",1});\r\n\r\n// 使用实体类更新一条数据，其中以主键Id值为where条件，默认忽略null，等价于 `update t_project_info set project_name='测试项目',del_flag=1,created_by='admin',remark='XXXX' where id=1`\r\nTProjectInfo project = new TProjectInfo();\r\nproject.\r\n\r\nsetId(1);\r\nproject.\r\n\r\nsetProjectName(\"测试项目\");\r\nproject.\r\n\r\nsetDelFlag(1);\r\nproject.\r\n\r\nsetCreatedBy(\"admin\");\r\nproject.\r\n\r\nsetRemark(\"XXXX\");\r\n\r\nint result = baseDao.updateById(project);\r\n\r\n// 使用实体类更新一条数据，不忽略null，等价于 `update t_project_info set project_name='测试项目',del_flag=1,created_by='admin',remark='XXXX',updated_by=NULL,created_at=NULL,updated_at=NULL where id=1`\r\nint result = baseDao.updateById(project, false);\r\n\r\n// 根据条件构造器（Lambda）作为条件更新一条数据，默认忽略null，等价于 `update t_project_info set project_name='测试项目' where id=1`\r\nTProjectInfo project2 = new TProjectInfo();\r\nproject2.\r\n\r\nsetProjectName(\"测试项目\");\r\n\r\nLambdaUpdateCriteria\u003cTProjectInfo\u003e criteria = new LambdaUpdateCriteria\u003c\u003e().eq(TProjectInfo::getId(),1L)\r\nint result = baseDao.update(project2, criteria);\r\n\r\n// 根据实体类内容和条件构造器作为条件更新一条数据，默认忽略null，等价于 `update t_project_info set project_name='测试项目' where id=1`\r\nUpdateCriteria\u003cTProjectInfo\u003e criteria = new UpdateCriteria\u003c\u003e().eq(\"id\", 1L)\r\nint result = update.update(project2, criteria);\r\n\r\n// 根据实体类内容和条件构造器作为条件更新一条数据，不忽略null，等价于 `update t_project_info set project_name='测试项目',del_flag=NULL,created_by=NULL,remark=NULL,updated_by=NULL,created_at=NULL,updated_at=NULL where id=1`\r\nUpdateCriteria\u003cTProjectInfo\u003e criteria = new UpdateCriteria\u003c\u003e().eq(\"id\", 1L)\r\nint result = update.update(project2, false, criteria);\r\n\r\n// 只根据条件构造器作为条件更新一条数据，等价于 `update t_project_info set project_name='测试项目' where id=1`\r\nUpdateCriteria\u003cTProjectInfo\u003e criteria = new UpdateCriteria\u003c\u003e().set(\"project_name\", \"测试项目\").eq(\"id\", 1L);\r\nint result = baseDao.update(criteria);\r\n\r\n// 只根据条件构造器（Lambda）作为条件更新一条数据，等价于 `update t_project_info set project_name='测试项目' where id=1`\r\nLambdaUpdateCriteria\u003cTProjectInfo\u003e criteria = new LambdaUpdateCriteria\u003c\u003e().set(TProjectInfo::getProjectName, \"测试项目\").eq(\"id\", 1L);\r\nint result = baseDao.update(criteria);\r\n```\r\n\r\n4. 删除操作\r\n\r\n```java\r\n\r\n@Autowired\r\nprivate ProjectDao projectDao;\r\n\r\n// 使用sql删除一条数据\r\nint result = projectDao.delete(\"\"delete from t_project_info where id = ? \"\", new Object[]{1});\r\n\r\n// 根据实体类非null内容作为where条件删除一条数据，等价于 `delete from t_project_info where id = 1`\r\nTProjectInfo project = new TProjectInfo();\r\nproject.\r\n\r\nsetId(1);\r\n\r\nint result = baseDao.delete(project);\r\n\r\n// 根据主键id删除一条数据，等价于 `delete from t_project_info where id = 1`\r\nint result = baseDao.deleteById(1L);\r\n\r\n// 根据主键id列表删除多条数据，等价于 `delete from t_project_info where id in (1, 5)`\r\nList\u003cLong\u003e ids = new ArrayList\u003cLong\u003e();\r\nids.\r\n\r\nadd(1L);\r\nids.\r\n\r\nadd(5L);\r\n\r\nint result = baseDao.deleteByIds(ids);\r\n\r\n// 根据主键id数组删除多条数据，等价于 `delete from t_project_info where id in (1, 5)`\r\nList\u003cLong\u003e ids = new ArrayList\u003cLong\u003e();\r\nint result = baseDao.deleteByIds(1L, 5L);\r\n\r\n// 根据条件构造器（Lambda）作为查询条件删除一条数据，等价于 `delete from t_project_info where id = 1`\r\nLambdaUpdateCriteria\u003cTProjectInfo\u003e criteria = new LambdaUpdateCriteria\u003c\u003e().eq(Project::getId(),1L)\r\nint result = baseDao.delete(criteria);\r\n\r\n// 根据条件构造器作为查询条件删除一条数据，等价于 `delete from t_project_info where id = 1`\r\nUpdateCriteria\u003cTProjectInfo\u003e criteria = new UpdateCriteria\u003c\u003e().eq(\"id\", 1L)\r\nint result = baseDao.delete(criteria);\r\n``` \r\n\r\n## 11、安全使用说明\r\n\r\n使用`QueryCriteria`和`UpdateCriteria`时应避免前端传入字段名，防止`SQL注入`的风险；\r\n如若必须使用由前端传入的动态内容，如使用QueryCriteria.orderBy(\"任意前端传入字段\")\r\n进行动态排序，推荐使用工具类 `SqlInjectionUtils.check(内容)` 先行验证字符串是否存在 `SQL注入`， 存在则拒绝操作。\r\n\r\n## 12、SQL日志打印分析\r\n\r\n**该功能依赖 p6spy 组件，需进行配置后方可使用**\r\n\r\n**注意！**\r\n\r\n- driver-class-name 为 p6spy 提供的驱动类 com.p6spy.engine.spy.P6SpyDriver\r\n- url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址\r\n- 该插件有性能损耗，不建议在生产环境中使用。\r\n- 更多参考 p6spy 官方文档： https://p6spy.readthedocs.io/en/latest/index.html\r\n\r\n\r\n1. 引入 `p6spy` 依赖\r\n\r\n```xml\r\n\r\n\u003cdependency\u003e\r\n    \u003cgroupId\u003ep6spy\u003c/groupId\u003e\r\n    \u003cartifactId\u003ep6spy\u003c/artifactId\u003e\r\n    \u003cversion\u003e最新版本\u003c/version\u003e\r\n\u003c/dependency\u003e\r\n``` \r\n\r\n2. `application.yml` 配置，注意url的中间多了个p6spy\r\n\r\n```yaml\r\nspring:\r\n  datasource:\r\n    driver-class-name: com.p6spy.engine.spy.P6SpyDriver\r\n    url: jdbc:p6spy:mysql://127.0.0.1:3306/tiny_jdbc_test?useSSL=false\u0026serverTimezone=Asia/Shanghai\u0026characterEncoding=utf8\r\n    ...\r\n```\r\n\r\n3. `spy.properties` 配置\r\n\r\n请配置 `logMessageFormat=org.tinycloud.jdbc.p6spy.P6SpyLogger`\r\n\r\n其余根据提示信息自定义修改\r\n\r\n```properties\r\n#################################################################\r\n# P6Spy Options File                                            #\r\n# See documentation for detailed instructions                   #\r\n# http://p6spy.github.io/p6spy/2.0/configandusage.html          #\r\n# https://p6spy.readthedocs.io/en/latest/configandusage.html    #\r\n#################################################################\r\n#################################################################\r\n# MODULES                                                       #\r\n#                                                               #\r\n# Module list adapts the modular functionality of P6Spy.        #\r\n# Only modules listed are active.                               #\r\n# (default is com.p6spy.engine.logging.P6LogFactory and         #\r\n# com.p6spy.engine.spy.P6SpyFactory)                            #\r\n# Please note that the core module (P6SpyFactory) can't be      #\r\n# deactivated.                                                  #\r\n# Unlike the other properties, activation of the changes on     #\r\n# this one requires reload.                                     #\r\n#################################################################\r\n#modulelist=com.p6spy.engine.spy.P6SpyFactory,com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory\r\n################################################################\r\n# CORE (P6SPY) PROPERTIES                                      #\r\n################################################################\r\n# A comma separated list of JDBC drivers to load and register.\r\n# (default is empty)\r\n#\r\n# Note: This is normally only needed when using P6Spy in an\r\n# application server environment with a JNDI data source or when\r\n# using a JDBC driver that does not implement the JDBC 4.0 API\r\n# (specifically automatic registration).\r\n#driverlist=\r\n# for flushing per statement\r\n# (default is false)\r\n#autoflush=false\r\n# sets the date format using Java's SimpleDateFormat routine.\r\n# In case property is not set, milliseconds since 1.1.1970 (unix time) is used (default is empty)\r\n#dateformat=\r\n# prints a stack trace for every statement logged\r\n#stacktrace=false\r\n# if stacktrace=true, specifies the stack trace to print\r\n#stacktraceclass=\r\n# determines if property file should be reloaded\r\n# Please note: reload means forgetting all the previously set\r\n# settings (even those set during runtime - via JMX)\r\n# and starting with the clean table\r\n# (default is false)\r\n#reloadproperties=false\r\n# determines how often should be reloaded in seconds\r\n# (default is 60)\r\n#reloadpropertiesinterval=60\r\n# specifies the appender to use for logging\r\n# Please note: reload means forgetting all the previously set\r\n# settings (even those set during runtime - via JMX)\r\n# and starting with the clean table\r\n# (only the properties read from the configuration file)\r\n# (default is com.p6spy.engine.spy.appender.FileLogger)\r\n#appender=com.p6spy.engine.spy.appender.Slf4JLogger\r\nappender=com.p6spy.engine.spy.appender.StdoutLogger\r\n#appender=com.p6spy.engine.spy.appender.FileLogger\r\n# name of logfile to use, note Windows users should make sure to use forward slashes in their pathname (e:/test/spy.log)\r\n# (used for com.p6spy.engine.spy.appender.FileLogger only)\r\n# (default is spy.log)\r\n#logfile=spy.log\r\n# append to the p6spy log file. if this is set to false the\r\n# log file is truncated every time. (file logger only)\r\n# (default is true)\r\n#append=true\r\n# class to use for formatting log messages (default is: com.p6spy.engine.spy.appender.SingleLineFormat)\r\nlogMessageFormat=org.tinycloud.jdbc.p6spy.P6SpyLogger\r\n# Custom log message format used ONLY IF logMessageFormat is set to com.p6spy.engine.spy.appender.CustomLineFormat\r\n# default is %(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)\r\n# Available placeholders are:\r\n#   %(connectionId)            the id of the connection\r\n#   %(currentTime)             the current time expressing in milliseconds\r\n#   %(executionTime)           the time in milliseconds that the operation took to complete\r\n#   %(category)                the category of the operation\r\n#   %(effectiveSql)            the SQL statement as submitted to the driver\r\n#   %(effectiveSqlSingleLine)  the SQL statement as submitted to the driver, with all new lines removed\r\n#   %(sql)                     the SQL statement with all bind variables replaced with actual values\r\n#   %(sqlSingleLine)           the SQL statement with all bind variables replaced with actual values, with all new lines removed\r\n#customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)\r\n# format that is used for logging of the java.util.Date implementations (has to be compatible with java.text.SimpleDateFormat)\r\n# (default is yyyy-MM-dd'T'HH:mm:ss.SSSZ)\r\n#databaseDialectDateFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ\r\n# format that is used for logging of the java.sql.Timestamp implementations (has to be compatible with java.text.SimpleDateFormat)\r\n# (default is yyyy-MM-dd'T'HH:mm:ss.SSSZ)\r\n#databaseDialectTimestampFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ\r\n# format that is used for logging booleans, possible values: boolean, numeric\r\n# (default is boolean)\r\n#databaseDialectBooleanFormat=boolean\r\n# Specifies the format for logging binary data. Not applicable if excludebinary is true.\r\n# (default is com.p6spy.engine.logging.format.HexEncodedBinaryFormat)\r\n#databaseDialectBinaryFormat=com.p6spy.engine.logging.format.PostgreSQLBinaryFormat\r\n#databaseDialectBinaryFormat=com.p6spy.engine.logging.format.MySQLBinaryFormat\r\n#databaseDialectBinaryFormat=com.p6spy.engine.logging.format.HexEncodedBinaryFormat\r\n# whether to expose options via JMX or not\r\n# (default is true)\r\n#jmx=true\r\n# if exposing options via jmx (see option: jmx), what should be the prefix used?\r\n# jmx naming pattern constructed is: com.p6spy(.\u003cjmxPrefix\u003e)?:name=\u003coptionsClassName\u003e\r\n# please note, if there is already such a name in use it would be unregistered first (the last registered wins)\r\n# (default is none)\r\n#jmxPrefix=\r\n# if set to true, the execution time will be measured in nanoseconds as opposed to milliseconds\r\n# (default is false)\r\n#useNanoTime=false\r\n#################################################################\r\n# DataSource replacement                                        #\r\n#                                                               #\r\n# Replace the real DataSource class in your application server  #\r\n# configuration with the name com.p6spy.engine.spy.P6DataSource #\r\n# (that provides also connection pooling and xa support).       #\r\n# then add the JNDI name and class name of the real             #\r\n# DataSource here                                               #\r\n#                                                               #\r\n# Values set in this item cannot be reloaded using the          #\r\n# reloadproperties variable. Once it is loaded, it remains      #\r\n# in memory until the application is restarted.                 #\r\n#                                                               #\r\n#################################################################\r\n#realdatasource=/RealMySqlDS\r\n#realdatasourceclass=com.mysql.jdbc.jdbc2.optional.MysqlDataSource\r\n#################################################################\r\n# DataSource properties                                         #\r\n#                                                               #\r\n# If you are using the DataSource support to intercept calls    #\r\n# to a DataSource that requires properties for proper setup,    #\r\n# define those properties here. Use name value pairs, separate  #\r\n# the name and value with a semicolon, and separate the         #\r\n# pairs with commas.                                            #\r\n#                                                               #\r\n# The example shown here is for mysql                           #\r\n#                                                               #\r\n#################################################################\r\n#realdatasourceproperties=port;3306,serverName;myhost,databaseName;jbossdb,foo;bar\r\n#################################################################\r\n# JNDI DataSource lookup                                        #\r\n#                                                               #\r\n# If you are using the DataSource support outside of an app     #\r\n# server, you will probably need to define the JNDI Context     #\r\n# environment.                                                  #\r\n#                                                               #\r\n# If the P6Spy code will be executing inside an app server then #\r\n# do not use these properties, and the DataSource lookup will   #\r\n# use the naming context defined by the app server.             #\r\n#                                                               #\r\n# The two standard elements of the naming environment are       #\r\n# jndicontextfactory and jndicontextproviderurl. If you need    #\r\n# additional elements, use the jndicontextcustom property.      #\r\n# You can define multiple properties in jndicontextcustom,      #\r\n# in name value pairs. Separate the name and value with a       #\r\n# semicolon, and separate the pairs with commas.                #\r\n#                                                               #\r\n# The example shown here is for a standalone program running on #\r\n# a machine that is also running JBoss, so the JNDI context     #\r\n# is configured for JBoss (3.0.4).                              #\r\n#                                                               #\r\n# (by default all these are empty)                              #\r\n#################################################################\r\n#jndicontextfactory=org.jnp.interfaces.NamingContextFactory\r\n#jndicontextproviderurl=localhost:1099\r\n#jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\r\n#jndicontextfactory=com.ibm.websphere.naming.WsnInitialContextFactory\r\n#jndicontextproviderurl=iiop://localhost:900\r\n################################################################\r\n# P6 LOGGING SPECIFIC PROPERTIES                               #\r\n################################################################\r\n# filter what is logged\r\n# please note this is a precondition for usage of: include/exclude/sqlexpression\r\n# (default is false)\r\n#filter=false\r\n# comma separated list of strings to include\r\n# please note that special characters escaping (used in java) has to be done for the provided regular expression\r\n# (default is empty)\r\n#include=\r\n# comma separated list of strings to exclude\r\n# (default is empty)\r\n#exclude=\r\n# sql expression to evaluate if using regex\r\n# please note that special characters escaping (used in java) has to be done for the provided regular expression\r\n# (default is empty)\r\n#sqlexpression=\r\n#list of categories to exclude: error, info, batch, debug, statement,\r\n#commit, rollback, result and resultset are valid values\r\n# (default is info,debug,result,resultset,batch)\r\n#excludecategories=info,debug,result,resultset,batch\r\n#whether the binary values (passed to DB or retrieved ones) should be logged with placeholder: [binary] or not.\r\n# (default is false)\r\n#excludebinary=false\r\n# Execution threshold applies to the standard logging of P6Spy.\r\n# While the standard logging logs out every statement\r\n# regardless of its execution time, this feature puts a time\r\n# condition on that logging. Only statements that have taken\r\n# longer than the time specified (in milliseconds) will be\r\n# logged. This way it is possible to see only statements that\r\n# have exceeded some high water mark.\r\n# This time is reloadable.\r\n#\r\n# executionThreshold=integer time (milliseconds)\r\n# (default is 0)\r\n#executionThreshold=\r\n################################################################\r\n# P6 OUTAGE SPECIFIC PROPERTIES                                #\r\n################################################################\r\n# Outage Detection\r\n#\r\n# This feature detects long-running statements that may be indicative of\r\n# a database outage problem. If this feature is turned on, it will log any\r\n# statement that surpasses the configurable time boundary during its execution.\r\n# When this feature is enabled, no other statements are logged except the long\r\n# running statements. The interval property is the boundary time set in seconds.\r\n# For example, if this is set to 2, then any statement requiring at least 2\r\n# seconds will be logged. Note that the same statement will continue to be logged\r\n# for as long as it executes. So if the interval is set to 2, and the query takes\r\n# 11 seconds, it will be logged 5 times (at the 2, 4, 6, 8, 10 second intervals).\r\n#\r\n# outagedetection=true|false\r\n# outagedetectioninterval=integer time (seconds)\r\n#\r\n# (default is false)\r\n#outagedetection=false\r\n# (default is 60)\r\n#outagedetectioninterval=30\r\n```\r\n\r\n## 13、许可证\r\n\r\n[Apache License 2.0](https://github.com/llllllxy/tiny-jdbc/blob/master/LICENSE) 免费用于个人和商业，请放心使用","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllllllxy%2Ftiny-jdbc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fllllllxy%2Ftiny-jdbc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllllllxy%2Ftiny-jdbc/lists"}