{"id":13678553,"url":"https://github.com/javaoffers/briefest","last_synced_at":"2026-03-02T15:01:57.467Z","repository":{"id":37695694,"uuid":"435820884","full_name":"javaoffers/briefest","owner":"javaoffers","description":"Briefest ORM is a powerful object/relational mapping solution for Java, and makes it easy to develop persistence logic for applications, libraries, and frameworks.","archived":false,"fork":false,"pushed_at":"2026-01-26T02:16:07.000Z","size":4888,"stargazers_count":42,"open_issues_count":11,"forks_count":6,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2026-02-04T22:59:12.062Z","etag":null,"topics":["brief","jdbc","join","mysql","orm","spring-boot"],"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/javaoffers.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-12-07T09:37:58.000Z","updated_at":"2026-01-30T01:40:18.000Z","dependencies_parsed_at":"2023-10-10T13:41:31.093Z","dependency_job_id":"7c54901a-306b-4c82-9008-b3fa2b0c80b7","html_url":"https://github.com/javaoffers/briefest","commit_stats":null,"previous_names":["javaoffers/mybatis-jql","javaoffers/briefest","caomingjie-code/mybatis-modelhelper","javaoffers/brief-jql"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/javaoffers/briefest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaoffers%2Fbriefest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaoffers%2Fbriefest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaoffers%2Fbriefest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaoffers%2Fbriefest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/javaoffers","download_url":"https://codeload.github.com/javaoffers/briefest/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaoffers%2Fbriefest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29885799,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T23:51:21.483Z","status":"online","status_checked_at":"2026-02-27T02:00:06.759Z","response_time":57,"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":["brief","jdbc","join","mysql","orm","spring-boot"],"created_at":"2024-08-02T13:00:55.074Z","updated_at":"2026-03-02T15:01:57.460Z","avatar_url":"https://github.com/javaoffers.png","language":"Java","readme":"\n\u003ca href=\"https://github.com/javaoffers/briefest/blob/develop/readmeCN.md\"\u003e中文\u003c/a\u003e BaGuCommunity\n\n# Brief\n\u003cp\u003e\n\u003ccode\u003ebrief\u003c/code\u003e Is a high-performance, lightweight, easy to use, zero configuration orm framework. Let complex SQL disappear, development efficiency maximization  and less amount of code and sustainable higher readability and maintainability.\nThis is the reason for the existence of the \u003ccode\u003ebrief\u003c/code\u003e. \u003ccode\u003eBrief\u003c/code\u003eTake you to experience unprecedented silky.\u003cimg src=\"https://5b0988e595225.cdn.sohucs.com/images/20171206/5b69749fcaf34927872b15e21b86f44c.gif\" width=\"20px\"\u003e\n\u003c/p\u003e\n\n### Introduction\n\u003cp\u003e\n Simplify the development. To write SQL like writing Java code. Here we call JQL. And form a set of JQL API process to reduce the SQL error rate. JQL aimed at the complex SQL is decomposed into simple SQL, this is the core of the development brief.\n  \u003ccode\u003ebrief\u003c/code\u003e Support for multiple table joins and does not require any mapping configuration. Brief Support the new writing style. \u003ccode\u003eMapper\u003c/code\u003e The default method can directly manipulate JQL API（The premise is extends \u003ccode\u003eBriefMapper\u003c/code\u003e).\n  Integrates the function of brief, can directly use the API. Let me written in Java streams JQL, improve the development efficiency. Less code and more smooth writing. The performance is twice that of mybatis.\n\n\u003c/p\u003e\n\n\n## Lightweight machine version\n\u003cp\u003e\n\u003ccode\u003ebrief-speedier\u003c/code\u003e Can be used alone. Do not rely on any environment.\n\u003c/p\u003e\n\n- maven\n\n  ```java\n    \u003cproperties\u003e\n         \u003cbrief.version\u003e3.6.10\u003c/brief.version\u003e\n    \u003c/properties\u003e\n   \u003c!--brief Lightweight and can be used alone--\u003e\n     \u003cdependency\u003e\n         \u003cgroupId\u003ecom.javaoffers\u003c/groupId\u003e\n         \u003cartifactId\u003ebrief-speedier\u003c/artifactId\u003e\n         \u003cversion\u003e${brief.version}\u003c/version\u003e\n   \u003c/dependency\u003e\n   ```\n  \n   ```java\n    BriefSpeedier speedier = BriefSpeedier.getInstance(dataSource);\n    BriefMapper\u003cUser\u003e userBriefMapper = speedier.newDefaultBriefMapper(User.class);\n    userList = userBriefMapper.select().colAll().where().limitPage(1, 10).exs();\n    print(userList);\n    ```\n\n## Enhance mybatis\n\u003cp\u003e\nThe \u003ccode\u003ebrief-mybatis\u003c/code\u003e is mybatis increased, let \u003ccode\u003emybatis\u003c/code\u003e has brief ability. \nSo \u003ccode\u003ebrief-mybatis\u003c/code\u003e is fully compatible with \u003ccode\u003emybatis\u003c/code\u003e. \nIf your project is used in the \u003ccode\u003emybatis\u003c/code\u003e so you can directly introduced \u003ccode\u003ebrief-mybatis\u003c/code\u003e dependence. \nDo change, enhance not only introduce it won't affect the existing engineering, silky smooth. Without any configuration. \nJust need to let your Mapper class inheritance \u003ccode\u003eBriefMapper\u003c/code\u003e can be used in the feature.\n\u003c/p\u003e\n\n- maven\n  ```\n  \n   \u003c!--The brief-mybatis increased--\u003e\n   \u003cdependency\u003e\n       \u003cgroupId\u003ecom.javaoffers\u003c/groupId\u003e\n       \u003cartifactId\u003ebrief-mybatis\u003c/artifactId\u003e\n       \u003cversion\u003e${brief.version}\u003c/version\u003e\n   \u003c/dependency\u003e\n\n  ```\n\n## Brief-spring-boot-start\n\u003cp\u003e\nLater will support，support\u003ccode\u003espring-boot\u003c/code\u003e. If your spring - the boot project cited mybatis framework, \nThen you only need to introduce \u003ccode\u003ebrief-mybatis\u003c/code\u003e to mybatis can be enhanced..\n\u003c/p\u003e\n\n## Function is introduced\n- feature\n  - High performance queries and insert\n  - Don't have to write the native SQL. Can according to the stream of Java API to write.\n  - SQL function annotation, simple and easy to use\n  - New, supporting the mapper interface class write default default method.\n  - Powerful automatic type conversion functions.\n  - The optimization of the automatic identification of insert/update batch execution\n  - Provide optional automatic identification of difference data real-time update capability \n  - Multi-table query does not need to be configured. Automatically map one-to-one, one-to-many, many-to-many.\n  - Supports logical deletion, optimistic locking.\n  - Integrated with the commonly used API, to directly using the need for development.\n  - Support mysql, h2, oracle, sqlserver, clickhouse, sqlite, pgsql grammar standard\n  - Table fields automatic decryption (support like fuzzy query).\n  - Field query fuzzy desensitization\n  - SQL interceptors, are free to customize\n  - SQL filter, are free to customize\n  - Slow slow SQL monitor. Allow customizable handling of slow SQL.\n  - Support json field.\n  - Support automatic generation of unique keys\n  - Big data streaming \n  - Support sharding table\n\n  \n- Project of actual combat, which has been used internally. The effect is very good.\n![](note-doc/img/img2.png)\n\n### Based on using    \n#### Query operation\n \u003cp\u003e\nBefore we see operation, we first look at the data structure: there are two key annotation.\n @BaseModelUsed to represent the class belongs to the Model classes (class name is the same as the table name, the Model will Help the camel class name converted to underline the name of the table, attribute the same),\n @BaseUniqueIndicates the only class attributes (corresponding to A unique attribute in A table, when the primary key used in the table that can be more).\n We will be in the final detailed explanation of the use of annotations. The following is the basic use\n \u003c/p\u003e\n \n ```java\n@BaseModel\npublic class User {\n\n    @BaseUnique\n    private Long id;\n\n    private String name;\n\n    private String birthday;\n    \n    private Work work;\n    \n    private IsDel isDel;\n    \n    private Version version;  \n\n    @CaseWhen(whens = {\n            @CaseWhen.When(when = \"money \u003c 10\", then = \"'pool'\"),\n            @CaseWhen.When(when = \"money \u003e 10000\", then = \"'rich'\")},\n            elseEnd = @CaseWhen.Else(\"'civilian'\")\n    )\n    private String moneyDes;    \n\n    private ExtraInfo extraInfo; //json column\n\n    private List\u003cUserOrder\u003e orders; //Multi-table association zero configuration\n\n    // .... getter setter\n}\n\n@BaseModel\npublic class UserOrder {\n\n    @BaseUnique\n    private int id;\n    private String orderName;\n    private String orderMoney;\n      \n    //getter, setter  methods  \n} \n\n//json column. Just implement the Json Column interface.\npublic class ExtraInfo implements JsonColumn {\n    private String nickName;\n    private Integer age;\n\n    public String getNickName() {\n        return nickName;\n    }\n\n    public void setNickName(String nickName) {\n        this.nickName = nickName;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n}\n\n```\n\n##### A full table query\n ```java\n\n List\u003cUser\u003e  users = crudUserMapper \n                    .select() \n                    .colAll() \n                    .where() \n                    .exs(); \n\n ```\n \n  \u003cp\u003e\nThe JQL will eventually be translated into the select id, name, XXX.. From the user. Query all the table fields colall mean here. If you want to query the specified fields, such as your name and birthday field, can do it:\u003c/p\u003e\n\n##### The query specified table fields \n ```java\n List\u003cUser\u003e users = crudusermapper\n                    .select()\n                    .col (user:: getbirthday)\n                    .col (user:: getname)\n                    .where()\n                    .exs();\n ```\n \n##### The query specified conditions \n \u003cp\u003e\nBy col() specifies fields to query. Here's where the where keyword in the () and SQL is the same. Such as to query a user id value is 1, you can write like this: \u003c/p\u003e\n \n ```java\n User user = crudusermapper\n             .select() \n             .colAll() \n             .where() \n             .eq(User::getId, 1) \n             .ex();\n ```\n\n##### Paging query\n\n```java\n int pageNum = 1;\n int pageSize = 10;\n List\u003cUser\u003e users = crudusermapper\n                    .select()\n                    .col (user:: getbirthday)\n                    .col (user:: getname)\n                    .where()\n                    .limitPage(1, 10)//  1: the first page, query 10 data\n                    .exs();\n \n```\n\n##### Statistical query\n```java\nList\u003cUser\u003e users = this.crudUserMapper\n                       .select()\n                       .col(User::getId)\n                       .innerJoin(UserTeacher::new)\n                       .col(UserTeacher::getTeacherId)\n                       .on()\n                       .oeq(User::getId, UserTeacher::getId)\n                       .innerJoin(Teacher::new)\n                       .col(Teacher::getId)\n                       .col(AggTag.MAX, Teacher::getName)\n                       .on()\n                       .oeq(UserTeacher::getTeacherId, Teacher::getId)\n                       .where()\n                       .gt(User::getId, 0)\n                       .groupBy(Teacher::getId)\n                       .groupBy(UserTeacher::getTeacherId)\n                       .groupBy(User::getId)\n                       .having()\n                       .gt(AggTag.MAX, User::getId, 0)\n                       .gt(AggTag.MAX, UserTeacher::getId, 0)\n                       .gt(AggTag.MAX, Teacher::getId, 0)\n                       .orderA(User::getId)\n                       .orderA(UserTeacher::getId)\n                       .orderA(Teacher::getId)\n                       .exs();\n```\n\n \u003cp\u003e\nYou will find that there are two special function of exs(), the ex() these two functions on behalf of the trigger. \nExs() is usually used to query more data, and returns the result to the list, while the ex T () is used to return a result; \nJQL must pass to trigger the where and the ex/exs. Most work situations, WHERE behind will add filter conditions, \nin addition to the special all table data statistics, this design also is very good remind you remember to fill in the WHERE condition, of course, \nif you don't need to add any WHERE conditions for all table data in the query, you can use the WHERE() the ex(), WHERE() exs() \n\u003c/p\u003e  \n\n\n#### The insert\n\n```java\nId exOne = crudUserMapper\n                .insert()\n                .col(User::getBirthday, new Date())\n                .col(User::getName, \"Jom\")\n                .ex();\n```\n\u003cp\u003e\nA simple insert statement, returns a wrapper class Id, are usually the primary key of the newly inserted data. An insert it's as simple as that. There's a more simple way to insert the data. Insert the object. And support multiple. The formation logic for batch is optimized. For example, the following case\n\u003c/p\u003e\n\n```java\n        User user = User.builder().name(\"Jom1\").birthday(date).build();\n        \n        List\u003cId\u003e ex = crudUserMapper\n                      .insert()\n                      .colAll(user)\n                      .ex();\n        print(ex);\n```\n\n\u003cp\u003e\n  We can insert the whole model object, said to query all of the fields, for batch layer. Performance is very good.\n\u003c/p\u003e\n\n#### The update operation\n\u003cp\u003e\nAllows you to update the Null update npdate Null Null, are not allowed to update the Null values, there is update or insert, optimistic locking version update, batch updates,\nPlease see the following case\n\u003c/p\u003e\n\n```java\ncrudUserMapper\n        .update().npdateNull()\n                 .col(User::getBirthday, new Date())\n                 //The name does not update. Because of its npdate Null\n                 .col(User::getName,null)\n                 .where()\n                 .eq(User::getId, id)\n                 .ex();\n\ncrudUserMapper\n        .update().updateNull()\n                 .col(User::getBirthday, new Date())\n                 //The name will be updated. Because it is the update of the Null\n                 .col(User::getName,null)\n                 .where()\n                 .eq(User::getId, id)\n                 .ex();\n\nthis.crudUserMapper.general().saveOrModify(user);\n\nthis.crudUserMapper.general().saveOrUpdate(user);\n\nthis.crudUserMapper.general().vsModifyById(user);\n\nthis.crudUserMapper.general().modifyBatchById(user);\n\nthis.crudUserMapper.general().updateBatchById(user);\n\n```\n\n\u003cp\u003e\nThrough the above case, we can very good control in the business field of updates.\n\u003c/p\u003e\n\n\n#### Delete operation\n\u003cp\u003e\n\u003ccode\u003ebrief\u003c/code\u003eSupport rich delete functions. At the same time also delete support logic. \nUse logic to delete need use \u003ccode\u003eIsDel/RowStatus\u003c/code\u003e in the \u003ccode\u003eUser\u003c/code\u003e  enumeration.\n\u003c/p\u003e\n\n```java\n \ncrudUserMapper.delete()\n               .where()\n               .eq(User::getId, id)\n               .eq(User::getName, 'xxx')\n               .ex();   \nthis.crudUserMapper.general().remove(user);\nthis.crudUserMapper.general().removeById(id);\nthis.crudUserMapper.general().removeByIds(id1,id2,id3);\nthis.crudUserMapper.general().removeByIds(idList);\nthis.crudUserMapper.general().logicRemove(user);\nthis.crudUserMapper.general().logicRemoveById(id);\n```\n\n\n#### Support the default write JQL/SQL Mapper interfaces\n\u003cp\u003e\nA new kind of coding style. We can in \u003ccode\u003eMapper\u003c/code\u003e Write the default method in the interface.\nUsed for centralized management JQL/SQL. Prevent project in JQL/SQL are everywhere.\nFor example, the following case (we recommend this kind of style).\n\u003c/p\u003e\n\n```java\npublic interface CrudUserMapper extends BriefMapper\u003cUser\u003e {\n\n    default User queryUserById(Number id){\n        return select()\n                .colAll()\n                .where()\n                .eq(User::getId, id)\n                .ex();\n    }\n   \n}\n```\n\n\u003cp\u003e\nWhen we interface inheritance \u003ccode\u003eBriefMapper\u003c/code\u003e  ，\nWe can write our JQL logic by default。\n\u003c/p\u003e\n\n#### Multi-table join \n- This part mainly introduces how to use JQL to express complex query. Does not require any configuration to join multiple tables (zero configuration).\n\u003cp\u003e\nOn the basis of the above section, we explained some of the common and the most basic purpose. Next, we will introduce some scenes in the actual project. Some of the slightly more complicated cases. Mainly includes the join query, grouping query, statistic query and commonly used common operations.\n\u003c/p\u003e\n\n\u003cp\u003e\nThe commonly used API JQL provides rich. For example, \u003e =, =, and in between, like, like Left, like Right, exists, and so on. There is also a combination unite, mainly is the combined into a multiple conditions, such as xx or xx (xx \u003e xx) for a two associated conditions. At the same time we let you write native SQL entry, such as col (SQL), cond SQL (SQL), although we usually don't recommend to use native SQL. Because as far as possible do not use SQL for complex logical processing, such as capture some string. Or etc, these actions suggested in the business layer. Start with a simple join JQL case: write JQL recommended in the interface class\n\u003c/p\u003e\n\n```java\npublic interface CrudUserMapper extends BriefMapper\u003cUser\u003e {\n    \n    default List\u003cUser\u003e queryAllAndOrder(){\n        return   select()\n                .colAll()\n                .leftJoin(UserOrder::new)\n                .colAll()\n                .on()\n                .oeq(User::getId,UserOrder::getUserId)\n                .where()\n                .exs();\n    }\n}\n```\n\n\n##### use left join , group by , limitPage  \n  \n      \n```java\n crudUserMapper.select()\n                .col(AggTag.MAX, User::getName)\n                .leftJoin(UserOrder::new)\n                .col(AggTag.MAX, UserOrder::getOrderName)\n                .on()\n                //OXX The beginning indicates the relationship between two tables\n                .oeq(User::getId, UserOrder::getUserId)\n                .where()\n                //Group by main table\n                .groupBy(User::getName, User::getId)\n                //Group according to sub-table\n                .groupBy(UserOrder::getUserId)\n                //1:pageNum,10:pageSize\n                .limitPage(1,10)\n                .exs();\n\n```\n\n####  Generic API\n\n\u003cp\u003e\nI enclosed some of the commonly used functions, use rise very simple. And the code is very concise and clear. For example, by id query or change.\n\u003c/p\u003e\n\n\u003cp\u003e\n  Commonly used API just call the general () method can be used. Such as through the id data\n\u003c/p\u003e\n\n```java\n//query by id\nUser user = crudUserMapper.general().queryById(id);\n```\n\n\u003cp\u003e\n   Save the API, to save an object to the database\n\u003c/p\u003e\n\n```java\n User user = User.builder().name(\"general\").build();\n //save\n long saveId = crudUserMapper.general().save(user);\n```\n\n\u003cp\u003e\n    By id delete specified data\n\u003c/p\u003e\n\n```java\ncrudUserMapper.general().removeById(1);\n```\n\n\u003cp\u003e\n  Commonly used simple API is as follows\n\u003c/p\u003e\n\n```java\n\n     /**\n         * save model\n         * @param model class\n         * @return primary key id\n         */\n        public Id save(T model);\n    \n        /**\n         * save or modify.\n         * sql :  insert into on duplicate key update\n         * @param model class\n         * @return  primary key id. or modify count num. so return void\n         */\n        public void saveOrModify(T model);\n    \n        /**\n         * save or update.\n         * By the @UniqueId field to query data, if the query not null then to update, or to insert.\n         * @param model class\n         * @return  primary key id. or modify count num. so return void\n         */\n        public void saveOrUpdate(T model);\n    \n        /**\n         * save or replace\n         * sql: replace into\n         * @param model class\n         * @return   primary key id. or modify count num. so return void\n         */\n        public void saveOrReplace(T model);\n    \n        /**\n         * save model\n         * @param models class\n         * @return primary key ids\n         */\n        public List\u003cId\u003e saveBatch(Collection\u003cT\u003e models);\n    \n        /**\n         * save or modify.\n         * sql :  insert into on duplicate key update\n         * @param models class\n         * @return primary key id. or modify count num. so return void\n         */\n        public void saveOrModify(Collection\u003cT\u003e models);\n    \n        /**\n         * save or update.\n         * By the @UniqueId field to query data, if the query not null then to update, or to insert.\n         * @param models class\n         * @return  primary key id. or modify count num. so return void\n         */\n        public void saveOrUpdate(Collection\u003cT\u003e models);\n    \n        /**\n         * save or replace\n         * sql: replace into\n         * @param models class\n         * @return primary key id. or modify count num. so return void\n         */\n        public void saveOrReplace(Collection\u003cT\u003e models);\n    \n        /**\n         * delete model.Where conditions will be generated based on properties of the model\n         * class for which there is a value.\n         * Note that this is a physical deletion\n         * @param model\n         */\n        public int remove(T model);\n    \n        /**\n         * delete model by id\n         * Note that this is a physical deletion\n         */\n        public int removeById(Serializable id );\n    \n        /**\n         * delete model by ids\n         * Note that this is a physical deletion\n         */\n        public int removeByIds(Serializable... ids );\n    \n        /**\n         * delete model by ids\n         * Note that this is a physical deletion\n         */\n        public \u003cID extends Serializable\u003e int removeByIds(Collection\u003cID\u003e ids);\n    \n        /**\n         * logic delete model.Where conditions will be generated based on properties of the model\n         * class for which there is a value.\n         * {@link IsDel}\n         * {@link RowStatus}\n         * @param model\n         */\n        public int logicRemove(T model);\n    \n        /**\n         * logic delete model by id\n         * {@link IsDel}\n         * {@link RowStatus}\n         */\n        public int logicRemoveById(Serializable id );\n    \n        /**\n         * logic delete model by ids\n         * {@link IsDel}\n         * {@link RowStatus}\n         */\n        public int logicRemoveByIds(Serializable... ids );\n    \n        /**\n         * logic delete model by ids\n         * {@link IsDel}\n         * {@link RowStatus}\n         */\n        public \u003cID extends Serializable\u003e int logicRemoveByIds(Collection\u003cID\u003e ids);\n    \n        /**\n         * Update the model, note that the update condition is the property marked with the Unique annotation.\n         * Only properties with values ​​are updated.\n         * In other words, the @BaseUnique annotation will generate a Where condition, and other non-null properties will\n         * generate a set statement.\n         * 支持版本更新\n         * @param model model\n         * @return The number of bars affected by the update\n         */\n        public int modifyById(T model);\n    \n        /**\n         * Update the model, note that the update condition is the property marked with the Unique annotation.\n         * Only properties with values ​​are updated.\n         * In other words, the @BaseUnique annotation will generate a Where condition, and the field will\n         * generate a set statement\n         * @param model model\n         * @return The number of bars affected by the update\n         */\n        public int updateById(T model);\n    \n        /**\n         * batch update. Empty fields will not be able to update the database.\n         * @param models models\n         * @return Affect the number of bars\n         */\n        public int modifyBatchById(Collection\u003cT\u003e models);\n    \n        /**\n         * batch update ,Will update the database if the field is empty.\n         * @param models models\n         * @return Affect the number of bars\n         */\n        public int updateBatchById(Collection\u003cT\u003e models);\n        \n        /**\n         * Support version update.\n         * Update the model, note that the update condition is the property marked with the Unique annotation.\n         * Only properties with values ​​are updated.\n         * In other words, the @BaseUnique annotation will generate a Where condition, and other non-null properties will\n         * generate a set statement.\n         * @param model model\n         * @return The number of bars affected by the update\n         */\n        public int vsModifyById(T model);\n    \n        /**\n         * Support version update.\n         * Update the model, note that the update condition is the property marked with the Unique annotation.\n         * Only properties with values ​​are updated.\n         * In other words, the @BaseUnique annotation will generate a Where condition, and the field will\n         * generate a set statement\n         * @param model model\n         * @return The number of bars affected by the update\n         */\n        public int vsUpdateById(T model);\n    \n        /**\n         * Support version update.\n         * batch update. Empty fields will not be able to update the database.\n         * @param models models\n         * @return Affect the number of bars\n         */\n        public int vsModifyByIds(Collection\u003cT\u003e models);\n    \n        /**\n         * Support version update.\n         * batch update ,Will update the database if the field is empty.\n         * @param models models\n         * @return Affect the number of bars\n         */\n        public int vsUpdateByIds(Collection\u003cT\u003e models);\n    \n        /**\n         * Query the main model, be careful not to include child models. Non-null properties will generate a where statement.\n         * \u003c\u003eNote that properties such as Collection\u003cModel\u003e will be ignored, even if they are not null \u003c/\u003e\n         * @param model model\n         * @return return query result\n         */\n        public List\u003cT\u003e query(T model);\n    \n        /**\n         * Query the main model, be careful not to include child models. Non-null properties will generate a where statement.\n         * \u003c\u003eNote that properties such as Collection\u003cModel\u003e will be ignored, even if they are not null \u003c/\u003e\n         * @param model model\n         * @param pageNum page number\n         * @param pageSize Number of bars displayed per page\n         * @return return query result\n         */\n        public List\u003cT\u003e query(T model,int pageNum,int pageSize);\n    \n        /**\n         * Paging query full table data\n         * @param pageNum page number, If the parameter is less than 1, it defaults to 1\n         * @param pageSize Number of bars displayed per page， If the parameter is less than 1, it defaults to 10\n         * @return return query result\n         */\n        public List\u003cT\u003e query(int pageNum,int pageSize);\n    \n        /**\n         * query by id\n         * @param id primary key id\n         * @return model\n         */\n        public T queryById(Serializable id);\n    \n        /**\n         * query by id\n         * @param ids primary key id\n         * @return model\n         */\n        public List\u003cT\u003e queryByIds(Serializable... ids);\n    \n        /**\n         * query by id\n         * @param ids primary key id\n         * @return model\n         */\n        public \u003cID extends Serializable\u003e  List\u003cT\u003e queryByIds(Collection\u003cID\u003e ids);\n    \n        /**\n         * query by id\n         * @param ids primary key id\n         * @return model\n         */\n        public \u003cID extends Serializable\u003e List\u003cT\u003e queryByIds(List\u003cID\u003e ids);\n    \n        /**\n         * query by id\n         * @param ids primary key id\n         * @return model\n         */\n        public \u003cID extends Serializable\u003e List\u003cT\u003e queryByIds(Set\u003cID\u003e ids);\n    \n    \n        /**\n         * Map\u003cString,Object\u003e. String: Field names of the table. The value corresponding to the Object field\n         * @param param Parameters. key database field name, value field value\n         * @return model\n         */\n        public List\u003cT\u003e queryByParam(Map\u003cString,Object\u003e param);\n    \n        /**\n         * Map\u003cString,Object\u003e. String: Field names of the table. The value corresponding to the Object field\n         * @param param Parameters. key database field name, value field value\n         * @param pageNum page number\n         * @param pageSize Number of bars displayed per page\n         * @return model\n         */\n        public List\u003cT\u003e queryByParam(Map\u003cString,Object\u003e param,int pageNum,int pageSize);\n    \n        /**\n         * The number of statistical tables\n         * @return not null\n         */\n        public Number count();\n    \n        /**\n         * The number of statistical tables, through the specified field\n         * @return not null\n         */\n        public Number count(C c);\n    \n        /**\n         * The number of statistical tables, through the specified field\n         * Statistical results after deduplication. count(DISTINCT c)\n         * @return not null\n         */\n        public Number countDistinct(C c);\n    \n    \n        /**\n         * The number of statistical tables.  Will use the model as the where condition\n         * @return not null\n         */\n        public Number count(T model);\n    \n        /**\n         * The number of statistical tables, through the specified field.\n         * Will use the model as the where condition\n         * @return not null\n         */\n        public Number count(C c,T model);\n    \n        /**\n         * The number of statistical tables, through the specified field\n         * Statistical results after deduplication. count(DISTINCT c).\n         * Will use the model as the where condition\n         * @return not null\n         */\n        public Number countDistinct(C c,T model);\n\n```\n#### SQL function annotation\n\u003cp\u003e\n  We can pass on the field of class use annotations to use SQL functions. Here are some use cases:\n\u003c/p\u003e\n\n```java\npublic class FunAnnoParserSample {\n    @ColName(\"name\")\n    @Left(10)\n    private String colName1; //LEFT(name,10)\n\n    @ColName(\"name\")\n    @Left(10)\n    @Concat( {\"age\"})\n    private String colName2; //CONCAT(LEFT(name,10),age)\n\n\n    @Left(10)\n    @Concat( {\"age\"})\n    private String colName3;//CONCAT(LEFT(colName3,10),age)\n\n    @Now\n    @Left(10)\n    @Concat( {\"age\"})\n    private String colName4;//CONCAT(LEFT(NOW(),10),age)\n\n\n    @Concat( {\"age\"})\n    private String colName5;//CONCAT(colName5,age)\n\n    @Now\n    @Concat({\"age\"})\n    @Left(10)\n    private String colName6;//LEFT(CONCAT(NOW(),age),10)\n\n\n    @Concat({\"age\"})\n    @Left(10)\n    private String colName7;//LEFT(CONCAT(colName7,age),10)\n\n    @Now\n    @Left(10)\n    private String colName8;//LEFT(NOW(),10)\n\n\n    @Rand\n    private String colName9;//RAND()\n\n    @Rand\n    @ColName(\"name\")\n    private String colName10;//java.lang.IllegalArgumentException: @ColName and @RAND cannot be used together\n\n    @ColName(\"name\")\n    @IfNull(\"'Amop'\")\n    private String colName11;//IFNULL(name,'Amop')\n\n    @ColName(\"sex = 1\")\n    @If(ep1 = \"'boy'\",ep2 = \"'girl'\")\n    private String colName12;//IF(sex = 1,'boy','girl')\n\n    /**\n     * select if(1,'1','0') output 1\n     * select if(0,'1','0') output 0\n     */\n    @ColName(\"sex\")\n    @IfNull(\"1\")\n    @If(ep1 = \"'boy'\", ep2 = \"'girl'\")\n    private String colName13;// IF(IFNULL(sex,1),'boy','girl')\n\n    @ColName(\"sex\")\n    @IfEq(eq = \"1\",ep1 = \"'boy'\", ep2 = \"'girl'\")\n    private String colName14; //IF(sex = 1,'boy','girl')\n\n    @ColName(\"money\")\n    @IfNotNull(\"'rich'\")\n    private String colName15; // IF(money is not null ,'rich',null)\n\n    @ColName(\"money\")\n    @IfNotNull(value = \"'rich'\",ifNull = \"'poor'\")\n    private String colName16; //IF(money is not null ,'rich','poor')\n\n    @ColName(\"money\")\n    @IfNotNull(value = \"'rich'\",ifNull = \"'poor'\")\n    @IfEq(eq = \"'rich'\",ep1 = \"'i want to marry him'\", ep2 = \"'i want to break up with him'\")\n    private String colName17; //IF(IF(money is not null ,'rich','poor') = 'rich','i want to marry him','i want to break up with him')\n\n    @ColName(\"money\")\n    @IfGt(gt = \"100000\",ep1 = \"'rich'\", ep2 = \"'poor'\")\n    @IfEq(eq = \"'rich'\",ep1 = \"'i want to marry him'\", ep2 = \"'i want to break up with him'\")\n    private String colName18; //IF(IF(money \u003e 100000,'rich','poor') = 'rich','i want to marry him','i want to break up with him')\n\n    @ColName(\"name\")\n    @Trim\n    private String colName19; //TRIM(name)\n\n    @ColName(\"name\")\n    @Concat(value = \"'hello'\", position = -1)\n    private String colName20;//CONCAT('hello',name)\n\n    @ColName(\"name\")\n    @Concat(value = \"'hello'\", position = 1)\n    private String colName21; //CONCAT('hello',name)\n\n    @ColName(\"name\")\n    @Concat(value = {\"'hello'\",\" 'how are you?' \"}, position = 1)\n    private String colName22;//  CONCAT('hello',name, 'how are you?' )\n\n\n    @ColName(\"name\")\n    @GroupConcat\n    private String colName23;//GROUP_CONCAT( name )\n\n    @ColName(\"name\")\n    @GroupConcat(distinct = true)\n    private String colName24;//GROUP_CONCAT( distinct name )\n\n    @ColName(\"name\")\n    @GroupConcat(distinct = true, orderBy = @GroupConcat.OrderBy(colName = \"age\",sort = GroupConcat.Sort.ASC) )\n    private String colName25;//GROUP_CONCAT( distinct name  order by age ASC)\n\n    @ColName(\"name\")\n    @GroupConcat(distinct = true, orderBy = @GroupConcat.OrderBy(colName = \"age\",sort = GroupConcat.Sort.DESC) ,separator = \"-\")\n    private String colName26;//GROUP_CONCAT( distinct name  order by age DESC separator '-')\n\n    @ColName(\"name\")\n    @Concat(\"age\")\n    @GroupConcat(distinct = true, orderBy = @GroupConcat.OrderBy(colName = \"age\",sort = GroupConcat.Sort.DESC) ,separator = \"-\")\n    private String colName27;//GROUP_CONCAT( distinct CONCAT(name,age)  order by age DESC separator '-')\n    \n    @CaseWhen(whens = {\n            @CaseWhen.When(when = \"score \u003e 80\", then = \"'Grand'\"),\n            @CaseWhen.When(when = \"score \u003c 80 and score \u003e 50\", then = \"'General'\"),\n            @CaseWhen.When(when = \"score \u003c 50 and score \u003e 10\", then = \"'noGood'\"),\n    }, elseEnd = @CaseWhen.Else(\"'VeryBad'\"))\n    private String scoreDescription;\n\n}\n```\n#### Automatic type conversion\n\u003cp\u003e\nBuilt a large number of commonly used types of converters.\nSuch as database field birthday is a datetime/int, Number/varchar and enumeration class conversion between.\nEnumeration classes usually and @ Enum Value are used together, identifies the enumeration class the only attribute, the attribute and the fields in the table automatically.\n\u003c/p\u003e\n\n```\n   String2DoubleConvert  \n    DateOne2DateTwoConvert  \n    String2DateConvert  \n    Boolean2StringConvert  \n    Date2OffsetDateTimeConvert  \n    Date2LongConvert  \n    Number2SQLDateConvert  \n    String2ByteConvert  \n    ByteArray2StringConvert2  \n    Number2DateConvert  \n    Date2LocalDateTimeConvert  \n    String2LocalDateConvert  \n    String2OffsetDateTimeConvert  \n    Number2StringConvert  \n    String2FloatConvert  \n    Date2StringConvert  \n    String2BooleanConvert  \n    String2ShortConvert  \n    PrimitiveNumber2PrimitiveNumberConvert  \n    String2LongConvert  \n    LocalDate2StringConvert  \n    String2CharConvert  \n    Character2StringConvert  \n    String2IntegerConvert  \n    Number2LocalDateConvert  \n    Number2PrimitiveConvert  \n    String2LocalDateTimeConvert  \n    Date2LocalDateConvert  \n    String2SQLDateConvert  \n    ByteArray2StringConvert  \n    String2BigDecimalConvert  \n    Number2BooleanConvert  \n    String2BigIntegerConvert  \n    Number2LocalDateTimeConvert\n    Number2EnumConvert\n    String2EnumConvert\n\n```\n\n#### The interceptor pattern\n\u003cp\u003e\nSQL and parameters before the real execution will be interceptor intercepts. Can the interceptor defined in their secondary processing.\nCustom interceptors is very simple, you only need to implement the interface\n\u003ccode\u003eJqlInterceptor\u003c/code\u003e，And then perform \u003ccode\u003eInterceptorLoader.init()\u003c/code\u003e Initialize your interceptor.\n\u003c/p\u003e\n\n\n```java\n LogInterceptor logInterceptor = new LogInterceptor();\n smartBriefContext.getJqlInterceptors().add(logInterceptor)\n```\n\n```java\n//spring environment. Bean objects will be automatically assembled\n@Component\npublic class LogInterceptor implements JqlInterceptor {\n    @Override\n    public void handler(BaseSQLInfo baseSQLInfo) {\n        System.out.println(\"LogInterceptor: SQL :  \"+ baseSQLInfo.getSql());\n        System.out.println(\"LogInterceptor: Param: \" +baseSQLInfo.getParams());\n    }\n}\n```\n\n\n#### Support automatic encryption and decryption\n\u003cp\u003e\nWhen we need to add some fields in a database table. Mybatis JQL provides a simple configuration can be done;\nWe only need to specify a key (length is 32 hexadecimal). And then specify tables and the fields in the table.\n\"FFFFFFFFAAAAAAAAAAAAFFFFFAFAFAFA\" we specify a private key to encrypt the num encryption.\nIn table encrypt data configuration is as follows:\n\u003c/p\u003e\n  \u003cp\u003e\nEncryption and decryption module is designed as an independent module.\nUsing this feature service, you need to add the MVN references. The following\n  \u003c/p\u003e \n\n```java\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.javaoffers\u003c/groupId\u003e\n  \u003cartifactId\u003ebrief-encipher\u003c/artifactId\u003e\n  \u003cversion\u003e${brief.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```java\n  /**\n     * Configure the tables and fields that need to be decrypted.\n     * the key Is the length of 32 hexadecimal;\n     */\n    @AesEncryptConfig(key = \"FFFFFFFFAAAAAAAAAAAAFFFFFAFAFAFA\", encryptTableColumns = {\n            @EncryptTableColumns(tableName = \"encrypt_data\", columns = {\"encrypt_num\"})\n    })\n    @Configuration\n    static class EncryptConfig{ }\n```\n```java\n    EncryptData encryptData = new EncryptData();\n    String encryptNum = \"1234567890\";\n    encryptData.setEncryptNum(encryptNum);\n     //The data stored in the db is after encryption 396195EAF65E740AEC39E6FFF0714542\n    Id id = this.crudEncryptDataMapper.general().save(encryptData);\n    //The query will automatically declassified\n    encryptDatas = this.crudEncryptDataMapper.general().queryByIds(id); \n    print(encryptDatas); //[{\"id\":10,\"encryptNum\":\"1234567890\"}]\n    //Query, query is specified directly inscriptions. Inscriptions will convert ciphertext and at the bottom of the query\n    EncryptData ex = this.crudEncryptDataMapper.select().colAll()\n    .where().eq(EncryptData::getEncryptNum, encryptNum).ex();\n    print(ex);//{\"id\":10,\"encryptNum\":\"1234567890\"}\n```\n\n#### Field desensitization\n\u003cp\u003e\nSupport field desensitization. Only need a model class with @ Email can Blur annotations can be class. Note by plus annotation fields must be a String type.\n\u003c/p\u003e\n\n```\n   @EmailBlur\n   private String email; // 12345678@outlook.com encrypted data is 12***678@outlook.com\n```\n## HIGH sharding\n\u003cp\u003e\nSupport for sharding table strategy\n\u003c/p\u003e\n\n```java\n\n  \u003c!--brief-sharding maven--\u003e\n   \u003cdependency\u003e\n       \u003cgroupId\u003ecom.javaoffers\u003c/groupId\u003e\n       \u003cartifactId\u003ebrief-sharding\u003c/artifactId\u003e\n       \u003cversion\u003e${brief.version}\u003c/version\u003e\n   \u003c/dependency\u003e\n\n```\n\n### Define a sharding strategy\n```java\npublic class ShardingTableMonthStrategy implements ShardingTableStrategy\u003cDate\u003e {\n\n    @Override\n    public String shardingExactly(ShardingParams\u003cDate\u003e shardingParams) {\n        Date valueOne = shardingParams.getValueOne();\n        return shardingParams.getTableName()+\"_\"+DateFormatUtils.format(valueOne, \"yyyy_MM\");\n    }\n\n    @Override\n    public Set\u003cString\u003e shardingRange(ShardingParams\u003cDate\u003e shardingParams) {\n        Set\u003cString\u003e sets = new LinkedHashSet\u003cString\u003e();\n        List\u003cDate\u003e valueList = shardingParams.getValueList();\n        for (int i = 0; i \u003c valueList.size(); i++) {\n            String st = shardingParams.getTableName()+\"_\"+DateFormatUtils.format(valueList.get(i), \"yyyy_MM\");\n            sets.add(st);\n        }\n        return sets;\n    }\n}\n\n@BaseModel(\"sharding_user\")\n@Data\npublic class ShardingUser {\n\n    @BaseUnique\n    private Long id;\n\n    private String name;\n\n    @ShardingStrategy(ShardingTableMonthStrategy.class)\n    private Date birthday;\n\n}\n```\n### SHARDING TABLE TEST\n\n#### insert sharding \n```java\nShardingUser shardingUser = new ShardingUser();\nArrayList\u003cShardingUser\u003e list = Lists.newArrayList();\nList\u003cDate\u003e dates = Lists.newArrayList();\nfor(int i=0;i\u003c10;i++){\n    shardingUser = new ShardingUser();\n    shardingUser.setName(\"name:\"+1);\n    Date date = DateUtils.addDays(new Date(), random());\n    date.setTime((date.getTime() / 1000) * 1000); // clear milliseconds\n    dates.add(date);\n    shardingUser.setBirthday(date);\n    list.add(shardingUser);\n}\nList\u003cId\u003e exs = shardingUserMapper.insert().colAll(list).exs();\n```\n```sql\ninsert into sharding_user_2025_08 ( `name`, `birthday` )  values  ( #{name}, #{birthday} ) \ninsert into sharding_user_2025_10 ( `name`, `birthday` )  values  ( #{name}, #{birthday} ) \ninsert into sharding_user_2025_09 ( `name`, `birthday` )  values  ( #{name}, #{birthday} ) \ninsert into sharding_user_2025_07 ( `name`, `birthday` )  values  ( #{name}, #{birthday} ) \n```\n\n\n#### query sharding\n\n```java\nList\u003cShardingUser\u003e exs = this.shardingUserMapper.select()\n                .colAll()\n                .where()\n                .in(ShardingUser::getBirthday, list)\n                .exs();\n        print(exs);\n```\n```sql\nselect sharding_user.id as sharding_user__id, sharding_user.name as sharding_user__name, sharding_user.birthday as sharding_user__birthday  from  sharding_user_2025_08 sharding_user   where  1=1  and sharding_user.birthday in  (#{0},#{1},#{2},#{3},#{4},#{5},#{6},#{7},#{8},#{9}) \nselect sharding_user.id as sharding_user__id, sharding_user.name as sharding_user__name, sharding_user.birthday as sharding_user__birthday  from  sharding_user_2025_10 sharding_user   where  1=1  and sharding_user.birthday in  (#{0},#{1},#{2},#{3},#{4},#{5},#{6},#{7},#{8},#{9}) \nselect sharding_user.id as sharding_user__id, sharding_user.name as sharding_user__name, sharding_user.birthday as sharding_user__birthday  from  sharding_user_2025_07 sharding_user   where  1=1  and sharding_user.birthday in  (#{0},#{1},#{2},#{3},#{4},#{5},#{6},#{7},#{8},#{9}) \nselect sharding_user.id as sharding_user__id, sharding_user.name as sharding_user__name, sharding_user.birthday as sharding_user__birthday  from  sharding_user_2025_09 sharding_user   where  1=1  and sharding_user.birthday in  (#{0},#{1},#{2},#{3},#{4},#{5},#{6},#{7},#{8},#{9}) \n \n```\n\n\u003cp\u003e\nUpdate and delete are the same as above.\n\u003c/p\u003e\n\n\n#### Code contributions are welcome\n\u003cp\u003e\nThis project has used internally. Greatly improves the development efficiency and code cleanliness. If you feel good, please point a little encouragement\n\u003c/p\u003e\n","funding_links":[],"categories":["Java"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjavaoffers%2Fbriefest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjavaoffers%2Fbriefest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjavaoffers%2Fbriefest/lists"}