{"id":20264352,"url":"https://github.com/fang-yan-peng/badger","last_synced_at":"2025-04-11T02:11:17.931Z","repository":{"id":37285102,"uuid":"170458231","full_name":"fang-yan-peng/badger","owner":"fang-yan-peng","description":"轻量级单表操作dao框架，支持分库分表","archived":false,"fork":false,"pushed_at":"2022-06-21T00:56:13.000Z","size":192,"stargazers_count":13,"open_issues_count":4,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T23:35:28.910Z","etag":null,"topics":["badger","mango","mybatis","sharding"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fang-yan-peng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-13T07:04:45.000Z","updated_at":"2022-01-04T13:51:23.000Z","dependencies_parsed_at":"2022-08-18T22:11:30.116Z","dependency_job_id":null,"html_url":"https://github.com/fang-yan-peng/badger","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fang-yan-peng%2Fbadger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fang-yan-peng%2Fbadger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fang-yan-peng%2Fbadger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fang-yan-peng%2Fbadger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fang-yan-peng","download_url":"https://codeload.github.com/fang-yan-peng/badger/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248328160,"owners_count":21085261,"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":["badger","mango","mybatis","sharding"],"created_at":"2024-11-14T11:39:43.719Z","updated_at":"2025-04-11T02:11:17.912Z","avatar_url":"https://github.com/fang-yan-peng.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Badger\n\n# 概要\n\nBadger轻量级单表操作dao框架，提供分库分表，类型映射等功能。\n\n# 例子\n\n\u003e 例子中使用了lombok，简化bean。\n\n## 添加依赖\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.jfaster\u003c/groupId\u003e\n    \u003cartifactId\u003ebadger\u003c/artifactId\u003e\n    \u003cversion\u003e2.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\n\n## 实例化，以使用mysql和HikariCp连接池为例\n\n```java\nHikariConfig config = new HikariConfig();\nconfig.setDriverClassName(\"com.mysql.jdbc.Driver\");\nconfig.setJdbcUrl(\"jdbc:mysql://127.0.0.1:3306/store\");\nconfig.setUsername(\"yanpengfang\");\nconfig.setPassword(\"8888888888\");\nconfig.setMaximumPoolSize(10);\n\nHikariDataSource dataSource = new HikariDataSource(config);\nBadger badger = Badger.newInstance(dataSource);\n```\n\n## 定义实体类\n\n```xml\nCREATE TABLE `driver` (\n  `driver_id` int(11) NOT NULL AUTO_INCREMENT,\n  `driver_name` varchar(64) DEFAULT NULL,\n  `age` int(11) DEFAULT NULL,\n  `type` int(11) DEFAULT NULL,\n  `create_date` timestamp NULL DEFAULT NULL,\n  `update_date` timestamp NULL DEFAULT NULL,\n  PRIMARY KEY (`driver_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n```\n\n```java\npublic enum TypeEnum {\n\n    SELF(\"自营\"), JOIN(\"加盟\");\n\n    @Getter\n    private String desc;\n\n    TypeEnum(String desc) {\n        this.desc = desc;\n    }\n}\n```\n\n```java\n@Data\n@Table(tableName = \"driver\")\npublic class Driver {\n\n    @Id\n    @Column\n    private int driverId;\n\n    @Column\n    private String driverName;\n\n    @Column\n    private int age;\n\n    @Column(convert = EnumIntegerConverter.class)\n    private TypeEnum type;\n\n    @Column\n    private Date createDate;\n\n    @Column\n    private Date updateDate;\n\n}\n```\n\u003e Table注解有tableName属性如果不指定默认是类的名转下划线，dataSourceName用于指定数据源工厂名称，如果是单库不用指定，如果是多库需要指定，指定注册到badger里的数据源工厂名称即可，见下文。\n\u003e Column注解的name属性可以指定与数据库字段对应关系，如果不写默认是驼峰转下划线，convert属性是将bean的类型映射成数据库的类型，如果需要可以实现TypeConverter接口自行定义，默认提供EnumIntegerConverter、EnumStringConverter、FastJsonObjectConverter、IntArrayStringConverter、IntegerListStringConverter、IntegerSetStringConverter、StringArrayStringConverter、StringListStringConverter、StringSetStringConverter等。\n\n## 插入\n\n```java\n/**\n * 插入，插入所有字段，插入非空字段。\n */\n@Test\npublic void insertTest() {\n    Date now = new Date();\n    Driver driver = new Driver();\n    driver.setAge(43);\n    driver.setDriverName(\"王叼蛋\");\n    driver.setType(TypeEnum.JOIN);\n    driver.setCreateDate(now);\n\n    //保存非空字段并且回填自增主键id\n    badger.saveNotNull(driver);\n\n    driver = new Driver();\n    driver.setAge(43);\n    driver.setDriverName(\"刘叼蛋\");\n    driver.setType(TypeEnum.SELF);\n    driver.setCreateDate(now);\n    driver.setUpdateDate(now);\n    //保存数据并且回填自增主键id\n    badger.save(driver);\n    System.out.println(\"司机ID:\" + driver.getDriverId());\n    \n    //忽略唯一索引冲突\n    badger.saveIgnore(driver);\n    System.out.println(\"司机ID:\" + driver.getDriverId());\n}\n\n```\n\n\u003e badger还提供了saveIgnore方法，用于忽略唯一索引冲突\n\n## 删除\n\n### 根据id删除\n\n```java\n/**\n *  根据id删除。\n */\n@Test(expected = MappingException.class)\npublic void deleteTest() throws Exception {\n    badger.delete(Driver.class, 3);\n}\n```\n\n### 根据条件删除\n\n```java\n/**\n * 根据条件删除\n */\n@Test\npublic void deleteByConditionTest() {\n    DeleteStatement statement = badger.createDeteleStatement(Driver.class, \n                                                             \"type=? and age=?\");\n    statement.addParam(TypeEnum.JOIN)\n            .addParam(43)\n            .execute();\n  \n    //也可以简化写成如下，因为addParam提供了多个重载方法。\n    badger.createDeteleStatement(Driver.class, \"type=? and age=?\").addParam(TypeEnum.JOIN,43).execute();\n}\n```\n\n## 修改\n\n### 根据id修改所有字段\n\n```java\n/**\n * 根据id更新所有字段\n */\n@Test\npublic void updateTest() {\n    Driver driver = badger.get(Driver.class, 14);\n    if (driver == null || driver.getDriverId() == 0) {\n        return;\n    }\n    driver.setAge(53);\n    driver.setType(TypeEnum.SELF);\n    badger.update(driver);\n}\n```\n\n### 根据条件修改指定字段\n\n```java\n/**\n * 根据条件更新指定字段。\n */\n@Test\npublic void updateByConditionTest() {\n    UpdateStatement statement = badger.createUpdateStatement(Order.class,\n                                                             \"age=?, update_date=?\",\n                                                             \"type=? and driver_id=?\");\n    statement.addParam(54)\n            .addParam(new Date())\n            .addParam(TypeEnum.SELF)\n            .addParam(13) //根据driver_id\n            .execute();\n  \n    //简化写法\n    badger.createUpdateStatement(Order.class,\"age=?, update_date=?\",\"type=? and driver_id=?\")\n      .addParam(54,new Date(),TypeEnum.SELF,13).execute();\n}\n```\n\n## 查询\n\n### 根据id查询所有字段\n\n```java\n@Test\npublic void selectTest() {\n    Driver driver = badger.get(Driver.class, 14);\n    System.out.println(driver);\n}\n```\n\n### 根据条件查询所有字段\n\n```java\n/**\n * 根据条件查询所有字段。\n */\n@Test\npublic void selectAllByConditionTest() {\n    //根据条件查询所有字段\n    List\u003cDriver\u003e drivers = badger.createQuery(Driver.class, \n                                             \"driver_id \u003e=1 and driver_id \u003c= ?\")\n      \t\t\t\t\t.addParam(14)\n      \t\t\t\t\t.list();\n    System.out.println(drivers);\n}\n```\n\n### 根据条件查询指定字段\n\n```java\n/**\n * 根据条件查询指定字段。\n */\n@Test\npublic void selectColumnsByConditionTest() {\n    //根据条件查询指定字段\n    Query\u003cDriver\u003e queryDriver = badger.createQuery(Driver.class, \n                                                   \"age,type\", \n                                                   \"type = ? and create_date \u003c ?\");\n    List\u003cDriver\u003e drivers = queryDriver.addParam(TypeEnum.SELF)\n               .addParam(new Date())\n               .list();\n    //简化写法\n    List\u003cDriver\u003e drivers = badger.createQuery(Driver.class, \"age,type\", \"type = ? and create_date \u003c ?\")\n      .addParam(TypeEnum.SELF,new Date()).list();\n    System.out.println(drivers);\n}\n```\n\n### like和in查询\n\n\u003e in 查询可以使用后面介绍的Condition，省去了自己拼接逗号。\n\n```java\n@Test\npublic void selectByConditionTest() {\n    //like查询\n    List\u003cDriver\u003e drivers = badger.createQuery(Driver.class, \"driver_name like ?\")\n                                 .addParam(\"%叼蛋%\")\n                                 .list();\n    System.out.println(drivers);\n\n    //in 查询\n    drivers = badger.createQuery(Driver.class, \"driver_id in (?,?,?)\")\n                    .addParam(17)\n                    .addParam(19)\n                    .addParam(20)\n                    .list();\n    System.out.println(drivers);\n}\n```\n\n### 分页查询\n\u003e 分页查询的pageIndex从1开始，1，2，3....\n```java\n/**\n * 分页查询\n */\n@Test\npublic void selectByPageTest() {\n    Date now = new Date();\n    Date before = new Date(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(10));\n    Query\u003cDriver\u003e query = badger.createQuery(Driver.class, \n                                             \"create_date \u003e= ? and create_date \u003c= ?\")\n                                .addParam(before)\n                                .addParam(now);\n                                .setPageIndex(1) //相当于limit 0,10\n                                .setPageSize(10)\n\n    //一共多少条\n    long count = query.count();\n    System.out.println(\"总条数:\" + count);\n\n    List\u003cDriver\u003e drivers = query.list();\n    System.out.println(drivers);\n}\n```\n\n### 指定查询返回的类型\n\n\u003e 指定查询类型，允许自定义返回值的类型，例如返回单值等，也支持bean类型。\n\n```java\n\n/**\n * 指定查询返回的类型\n */\n@Test\npublic void selectType() {\n  Integer avg = badger.createQuery(Driver.class, Integer.class,\"avg(age)\", \"1=1 group by driver_id\").getOne();\n  System.out.println(avg);\n}\n\n@Data\npublic class DriverExt {\n\n    @Column(name = \"avgAge\")\n    int avgAge;\n\n    @Column\n    int driverId;\n}\n\n/**\n  * 指定查询返回的类型\n  */\n@Test\npublic void selectBeanType() {\n  List\u003cDriverExt\u003e avg = badger.createQuery(Driver.class, DriverExt.class,\"avg(age) as avgAge, driver_id\", \"1=1 group by driver_id\").list();\n  System.out.println(avg);\n}\n```\n\n### 扩展查询\n\n\u003e 根据其他类定义好的表结构，进行一些操作，比如sum，min等等产生的字段，这些字段并不属于原来的表，但是是根据原来的表生成的。也可以通过上一节讲的，指定返回值类型实现。\n\n```java\n@Data\n@Extension(extend = Driver.class)\npublic class DriverExt {\n\n    @Column(name = \"avgAge\")\n    int avgAge;\n\n    @Column\n    int driverId;\n}\n```\n\n```java\nQuery\u003cDriverExt\u003e query = badger.createQuery(DriverExt.class, \n                                            \"avg(age) as avgAge, driver_id\", \n                                            \"1=1 group by driver_id\");\nList\u003cDriverExt\u003e driverExts = query.list();\nSystem.out.println(driverExts);\n```\n\n## 条件\n\n\u003e 查询、删除、修改时条件可以直接传入，也可以动态的构建。此功能比较适合于动态条件和in查询，根据不同参数条件不同。静态条件也可以使用。Condition会自动跳过参数为null的字段，也可以自定义判断条件。\n\n* 下面条件的例子相当于driver_id \u003e=1 and driver_id \u003c=30 忽略name, 因为值null。查询所有字段。\n\n```java\n@Test\npublic void selectByLogicConditionTest() {\n  //根据条件查询所有字段\n  Condition condition = badger.createCondition()\n    .gte(\"driver_id\", 1)\n    .and()\n    .lte(\"driver_id\", 30)\n    .and()\n    .eq(\"name\", null);\n  //\n  List\u003cDriver\u003e drivers = badger.createQuery(Driver.class, condition).list();\n  System.out.println(drivers);\n}\n```\n\n* 下面条件的例子相当于driver_id in(1,10,18)，只查询name和age字段。\n\n```java\n@Test\npublic void selectByLogicConditionTest() {\n  //根据条件查询所有字段\n  List\u003cInteger\u003e driverIds = new ArrayList\u003c\u003e();\n  driverIds.add(1);\n  driverIds.add(10);\n  driverIds.add(18);\n  \n  condition = badger.createCondition().in(\"driver_id\", driverIds);\n  List\u003cDriver\u003e drivers1 = badger.createQuery(Driver.class, \"name, age\", condition).list();\n  System.out.println(drivers1);\n}\n```\n\n* 自定义过滤条件，如下条件相当于name=\"张三\"，因为age的值为30小于35所以忽略了。\n\n   ```java\n  Condition condition = badger.createCondition()\n                  .eq(\"name\", \"张三\")\n                  .and()\n                  .eq(\"age\", 30, a-\u003e a\u003e35);\n  ```\n\n  \n\n* 根据条件删除\n\n```java\n@Test\npublic void selectByLogicConditionTest() {\n  Condition condition = badger.createCondition()\n                  .gte(\"driver_id\", 1)\n                  .and()\n                  .lte(\"driver_id\", 30);\n  badger.createDeleteStatement(Driver.class, condition).execute();\n}\n```\n\n* 根据条件修改指定字段 \n\n```java\n@Test\npublic void selectByLogicConditionTest() {\n  Condition condition = badger.createCondition()\n                .eq(\"order_no\", \"P224378961549892939886\")\n                .and()\n                .eq(\"driver_id\", 15);\n  badger.createUpdateStatement(Order.class,\n                               \"money=?, update_date=?\", condition.getSql())\n    .addParam(new BigDecimal(\"126\"))\n    .addParam(new Date())\n    .addParam(condition.getParams())\n    .execute();\n}\n```\n\n\n\n* eq 等于\n* ne 不等于\n* gt 大于\n* gte 大于等于\n* lt 小于\n* lte 小于等于\n* groupBy 相当于group by\n* orderByAsc 升序排序，如果是多个字段排序如condition.orderByAsc(col1,col2)，相当于 order by col1 asc, col2 asc\n* orderByDesc 降序排序，如果是多个字段如condition.orderByDesc(col1,col2)，相当于order by col1 desc, col2 desc\n* orderBy 可以为每个列指定排序规则，如condition.orderBy(OrderByColumn.asc(\"col1\"), OrderByColumn.desc(\"col2\"))，相当于order by col1 asc, col2 desc\n* and 与\n* or 或\n* like 相当于like\n* in 相当于in\n* subLeft 相当于\"(\"\n* subRight 相当于\")\"\n\n## 分库分表\n\n\u003e 根据某个字段进行分库分表。如果根据某个字段进行分库分表则所有的操作必须带有分库分表字段。目前只支持单值分库分表，只要在分库分表的属性上打上@ShardColumn\n\u003e 即可，框架会自动提取值调用指定的分库分表算法。\n\n```xml\nCREATE TABLE `driver_order_0` (\n  `order_no` varchar(64) DEFAULT NULL,\n  `money` decimal(10,2) DEFAULT NULL,\n  `driver_id` int(11) DEFAULT NULL,\n  `create_date` timestamp NULL DEFAULT NULL,\n  `update_date` timestamp NULL DEFAULT NULL,\n  UNIQUE KEY `uniq_order_no` (`order_no`),\n  UNIQUE KEY `UK_order` (`driver_id`,`order_no`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `driver_order_1` (\n  `order_no` varchar(64) DEFAULT NULL,\n  `money` decimal(10,2) DEFAULT NULL,\n  `driver_id` int(11) DEFAULT NULL,\n  `create_date` timestamp NULL DEFAULT NULL,\n  `update_date` timestamp NULL DEFAULT NULL,\n  UNIQUE KEY `uniq_order_no` (`order_no`),\n  UNIQUE KEY `UK_order` (`driver_id`,`order_no`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n```\n\n\u003e ShardTable注解指定此表是需要分库或者分表的。其中tableShardStrategy是指定分表策略，实现TableShardStrategy接口；dbShardStrategy是指定分库策略，实现DatasourceShardStrategy接口。两种可以同时存在也可以只存在其一。下面的例子是把分库策略暂时注释掉，只实现分表功能，分库功能会在后续演示。\n\n```java\n/**\n * 分表分库\n * @author yanpengfang\n * @create 2019-01-31 9:41 PM\n */\n@ShardTable(tables = {\"driver_order_0\", \"driver_order_1\"},\n        tableShardStrategy = Order.OrderTableShardStrategy.class\n        /*,dbShardStrategy = Order.OrderDataSourceShardStrategy.class*/)\n@Data\npublic class Order {\n\n    @Id\n    @Column\n    private String orderNo;\n\n    @Column\n    private BigDecimal money;\n\n    @ShardColumn\n    @Column\n    private int driverId;\n\n    @Column\n    private Date createDate;\n\n    @Column\n    private Date updateDate;\n\n    public static class OrderTableShardStrategy implements TableShardStrategy\u003cInteger\u003e {\n        @Override\n        public String shardSingle(List\u003cString\u003e tables, Integer shardValue) {\n            int mod = shardValue % 2;\n            for (String table : tables) {\n                if (table.endsWith(\"_\" + mod)) {\n                    return table;\n                }\n            }\n            return tables.get(0);\n        }\n    }\n\n    /*public static class OrderDataSourceShardStrategy implements DataSourceShardStrategy\u003cInteger\u003e {\n        @Override\n        public String shardSingle(Integer shardValue) {\n            int mod = shardValue % 2;\n            return \"db_\" + mod;\n        }\n    }*/\n}\n\n```\n\n### 分表操作\n\n\u003e 以插入为例。所有的操作都和不分表的操作一样，直接使用即可，分库分表的动作都由框架层实现，用户只需要指定自己的分库分表算法即可。\n\n```java\n/**\n * 插入唯一索引冲突忽略。\n */\n@Test\npublic void insertTest() {\n    Order order = new Order();\n    order.setOrderNo(\"P22437896\" + System.currentTimeMillis());\n    System.out.println(\"订单号:\" + order.getOrderNo());\n    //根据driver_id分表，则按照例子的算法应该分到driver_order_1表\n    order.setDriverId(13);\n    order.setMoney(new BigDecimal(\"189.02\"));\n    order.setUpdateDate(now);\n    order.setCreateDate(now);\n    //忽略唯一索引冲突\n    badger.saveIgnore(order);\n}\n```\n\n### 分库操作\n\n\u003e 按照如下配置Badger，然后将上一节中定义的Order类中的分库策略注释打开，就可以实现分库了。分库和分表可以同时使用，也可以只使用其中之一。实现分库算法时，根据业务需要返回在badger中事先注册好的连接池的名称即可。例如下面的例子，注册了两个连接池，名字分别叫db_0和db_1。\n\n```java\nHikariConfig config = new HikariConfig();\nconfig.setDriverClassName(\"com.mysql.jdbc.Driver\");\nconfig.setJdbcUrl(\"jdbc:mysql://127.0.0.1:3306/store\");\nconfig.setUsername(\"yanpengfang\");\nconfig.setPassword(\"88888888\");\nconfig.setMaximumPoolSize(10);\n\nHikariDataSource dataSource = new HikariDataSource(config);\n\nHikariConfig config1 = new HikariConfig();\nconfig1.setDriverClassName(\"com.mysql.jdbc.Driver\");\nconfig1.setJdbcUrl(\"jdbc:mysql://127.0.0.1:3306/store1\");\nconfig1.setUsername(\"yanpengfang\");\nconfig1.setPassword(\"8888888\");\nconfig1.setMaximumPoolSize(10);\n\nHikariDataSource dataSource1 = new HikariDataSource(config1);\n\nBadger badger = Badger.newInstance();\n//指定数据源工厂名称为db_0\nbadger.setDataSourceFactory(new SingleDataSourceFactory(\"db_0\", dataSource));\n//指定数据源工厂名称为db_1\nbadger.setDataSourceFactory(new SingleDataSourceFactory(\"db_1\", dataSource1));\n```\n### 手动指定分库分表\n\n\u003e 如果使用了分库分表功能，框架会自动根据@ShardColumn获取分库分表的值，则任何db操作都必须带上分库分表字段，但是存在一些特殊情况，比如分了10张表，有一种需求是遍历这10张表，那么这样查询条件就比较麻烦了，badger支持手动指定分库分表的值，手动指定会覆盖框架提取的值。\n\n#### 增加\n\n```java\n/**\n * 插入 手动指定分库分表字段\n */\n@Test\npublic void insertManualShardTest() {\n    Date now = new Date();\n    Driver driver = new Driver();\n    driver.setAge(47);\n    driver.setDriverName(\"指定分表\");\n    driver.setType(TypeEnum.SELF);\n    driver.setCreateDate(now);\n    driver.setUpdateDate(now);\n    //保存数据并且回填自增主键id\n    badger.save(driver);\n    System.out.println(\"司机ID:\" + driver.getDriverId());\n\n    Order order = new Order();\n\n    order.setOrderNo(\"P22437896\" + System.currentTimeMillis());\n    System.out.println(\"订单号:\" + order.getOrderNo());\n    order.setDriverId(driver.getDriverId());\n    order.setMoney(new BigDecimal(\"189.02\"));\n    order.setUpdateDate(now);\n    order.setCreateDate(now);\n    //忽略唯一索引冲突, 并且指定分库分表的值为11，会覆盖系统提取的值。\n    badger.saveIgnore(order, 11);\n}\n```\n\n\u003e 只需要在保存的时候指定一个分库分表的值。同理根据id更新、查找和删除，只需要在方法里传入指定的分库分表值即可。\n\n#### 查询\n\n```java\n/**\n * 根据条件查询，查询指定字段。\n */\n@Test\npublic void selectManualShardByConditionTest() {\n    //根据条件查询所有字段\n    Query\u003cOrder\u003e query = badger.createQuery(Order.class, \"order_no=?\");\n    //指定分库分表字段的值为11，如果不指定则查询条件必须带有driverId，因为是按照driverId分库分表，手动指定会覆盖程序提取。\n    Order order = query.addParam(\"P224378961552032130141\")\n                        .setShardValue(11)\n                        .getOne();\n    System.out.println(order);\n}\n```\n\n\u003e 只需要在查询的时候调用setShardValue方法指定分库分表的值即可，根据条件删除、修改也是一样。\n\n### 读写分离\n\n\u003e 指定MasterSlaveDataSourceFactory数据源工厂，则查询语句自动走从库。\n\n```java\nHikariConfig config = new HikariConfig();\nconfig.setDriverClassName(\"com.mysql.jdbc.Driver\");\nconfig.setJdbcUrl(\"jdbc:mysql://127.0.0.1:3306/store\");\nconfig.setUsername(\"yanpengfang\");\nconfig.setPassword(\"8888888\");\nconfig.setMaximumPoolSize(10);\n\nHikariDataSource dataSource = new HikariDataSource(config);\n\nHikariConfig config1 = new HikariConfig();\nconfig1.setDriverClassName(\"com.mysql.jdbc.Driver\");\nconfig1.setJdbcUrl(\"jdbc:mysql://127.0.0.1:3306/store1\");\nconfig1.setUsername(\"yanpengfang\");\nconfig1.setPassword(\"88888888\");\nconfig1.setMaximumPoolSize(10);\n\nHikariDataSource dataSource1 = new HikariDataSource(config1);\n\nBadger badger = Badger.newInstance();\nbadger.setDataSourceFactory(new MasterSlaveDataSourceFactory(dataSource,Collections.singletonList(dataSource1)));\n\n```\n\n#### 读写分离，查询强制走主库\n\n```java\n/**\n * 根据id更新所有字段。\n */\n@Test\npublic void updateTest() {\n    Driver driver = badger.getFromMaster(Driver.class, 14);\n    System.out.println(driver);\n}\n```\n\n```java\n/**\n * 根据条件查询，查询指定字段。\n */\n@Test\npublic void selectByConditionTest() {\n    //根据条件查询所有字段\n    List\u003cDriver\u003e driver = badger.createQuery(Driver.class, \n                                             \"driver_id \u003e=1 and driver_id \u003c= ?\")\n      .addParam(14)\n      .userMaster()\n      .list();\n    System.out.println(drivers);\n}\n\n```\n\n## 事务\n\u003e Badger既实现了自己的事务管理，同时也支持spring的事务管理器，支持spring的事务传播机制。使用其中一种即可。\n### Badger自身事务\n\n\u003e 实现TransactionAction方法，在这个方法中把要执行的一系列事务操作放在其中。\n\n```java\n/**\n * badger事务\n */\n@Test(expected = MappingException.class)\npublic void transactionTest() {\n    TransactionTemplate.execute(status -\u003e {\n        badger.delete(Driver.class, 15);\n        //根据id删除，但是分库分表字段不是id则抛异常\n        badger.delete(Order.class, \"P224378961549867525895\");\n    });\n}\n```\n\n### 使用spring提供的事务管理器\n\n\u003e 使用spring的事务管理器，同时支持spring的事务传递机制。springboot同样可以使用。\n\n### 添加依赖\n\n```xml\n\u003c!--spring事务管理器--\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.jfaster\u003c/groupId\u003e\n    \u003cartifactId\u003ebadger-spring-transaction\u003c/artifactId\u003e\n    \u003cversion\u003e1.7\u003c/version\u003e\n    \u003cexclusions\u003e\n        \u003cexclusion\u003e\n            \u003cgroupId\u003eorg.jfaster\u003c/groupId\u003e\n            \u003cartifactId\u003ebadger\u003c/artifactId\u003e\n        \u003c/exclusion\u003e\n    \u003c/exclusions\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.springframework\u003c/groupId\u003e\n    \u003cartifactId\u003espring-jdbc\u003c/artifactId\u003e\n    \u003cversion\u003e5.1.4.RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.jfaster\u003c/groupId\u003e\n    \u003cartifactId\u003ebadger\u003c/artifactId\u003e\n    \u003cversion\u003e2.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\n\n#### 配置xml文件\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cbeans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://www.springframework.org/schema/context\n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://www.springframework.org/schema/tx\n                           http://www.springframework.org/schema/tx/spring-tx.xsd\"\n\u003e\n\n    \u003ccontext:component-scan base-package=\"org.jfaster.test\"/\u003e\n\n    \u003c!-- 加载db配置文件 --\u003e\n    \u003ccontext:property-placeholder location=\"classpath*:*.properties\" ignore-unresolvable=\"true\"/\u003e\n\n    \u003cbean id=\"hikariConfig\" class=\"com.zaxxer.hikari.HikariConfig\"\u003e\n        \u003c!--poolName属性自定义即可--\u003e\n        \u003cproperty name=\"poolName\" value=\"springHikariCP\"/\u003e\n        \u003cproperty name=\"driverClassName\" value=\"${jdbc.driver}\"/\u003e\n        \u003cproperty name=\"maximumPoolSize\" value=\"${jdbc.maximumPoolSize}\"/\u003e\n        \u003cproperty name=\"jdbcUrl\" value=\"${jdbc.url}\"/\u003e\n        \u003cproperty name=\"username\" value=\"${jdbc.username}\"/\u003e\n        \u003cproperty name=\"password\" value=\"${jdbc.password}\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- HikariCP dataSource配置 --\u003e\n    \u003cbean id=\"hikaricpDataSource\" class=\"com.zaxxer.hikari.HikariDataSource\" destroy-method=\"close\"\u003e\n        \u003cconstructor-arg ref=\"hikariConfig\"/\u003e\n    \u003c/bean\u003e\n\n\n    \u003c!-- 注册事务管理类 --\u003e\n    \u003cbean id=\"transactionManager\"\n          class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\"\u003e\n        \u003cproperty name=\"dataSource\" ref=\"hikaricpDataSource\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- 开启事务行为 --\u003e\n    \u003ctx:annotation-driven/\u003e\n\n    \u003c!--初始化badger--\u003e\n    \u003cbean id=\"badger\" class=\"org.jfaster.badger.Badger\" factory-method=\"newInstance\"\u003e\n        \u003cproperty name=\"dataSource\" ref=\"hikaricpDataSource\"/\u003e\n        \u003c!--设置事务管理器为spring--\u003e\n        \u003cproperty name=\"transactionManager\" value=\"spring\"/\u003e\n    \u003c/bean\u003e\n\n\u003c/beans\u003e\n```\n\n### 定义dao\n\n```java\n/**\n *\n * @author yanpengfang\n * @create 2019-02-13 10:27 AM\n */\n@Repository\npublic class DriverDao {\n\n    @Resource\n    private Badger badger;\n\n    public int deleteDriverById(int driverId) {\n        return badger.delete(Driver.class, driverId);\n    }\n\n}\n```\n\n```java\n/**\n *\n * @author yanpengfang\n * @create 2019-02-13 10:27 AM\n */\n@Repository\npublic class DriverOrderDao {\n\n    @Resource\n    private Badger badger;\n\n    public int deleteDriverOrderByOrderNo(String orderNo) {\n        return badger.delete(Order.class, orderNo);\n    }\n\n}\n```\n\n#### 定义service\n\n```java\n/**\n *\n * @author yanpengfang\n * @create 2019-02-13 10:37 AM\n */\npublic interface DriverOrderService {\n    boolean deleteDriverAndOrder(int driverId, String orderNo);\n}\n```\n\n#### 定义service的实现\n\n\u003e 打上@Transactional注解\n\n```java\n/**\n *\n * @author yanpengfang\n * @create 2019-02-13 10:37 AM\n */\n@Service\npublic class DriverOrderServiceImpl implements DriverOrderService {\n\n    @Resource\n    private DriverDao driverDao;\n\n    @Resource\n    private DriverOrderDao driverOrderDao;\n\n    @Override\n    @Transactional\n    public boolean deleteDriverAndOrder(int driverId, String orderNo) {\n        return driverDao.deleteDriverById(driverId) \u003e 0\n                \u0026\u0026 driverOrderDao.deleteDriverOrderByOrderNo(orderNo) \u003e 0;\n    }\n}\n\n```\n\n## 设置拦截器\n\n\u003e 设置拦截器，可以在sql执行之前和之后做一些操作，比如统计sql的执行时间等等\n\n```java\nbadger.setInterceptor(new SqlInterceptor() {\n\n    @Override\n    public void before(String sql) {\n        System.out.println(\"sql:\" + sql + \" begin to execute\");\n        SqlInterceptor.put(\"startTime\", System.currentTimeMillis());\n    }\n\n    @Override\n    public void after(String sql) {\n        long startTime = SqlInterceptor.get(\"startTime\", Long.class);\n        System.out.println(\"sql:\" + sql + \" execute success, execute time:\" + (System.currentTimeMillis() - startTime));\n    }\n\n    @Override\n    public void error(String sql, Throwable e) {\n        System.out.println(\"sql:\" + sql + \" execute fail \" + e.getMessage());\n    }\n});\n```\n\n## 自定义sql\n\n\u003e 自定义sql，不建议使用。脱离了单表操作，根据个人需要自定义sql。在自定义sql情况下，Badger不解析sql，所以不会重写表名，不支持分库分表。分表的信息需要自己实现，拼接到sql中。分库操作则需要指定库名。复杂sql查询可以拆分成多次单表查询。大表本身不建议join等操作。\n\n### 查询\n\n```java\n/**\n *\n * @author yanpengfang\n * @create 2019-02-11 4:00 PM\n */\n@Data\npublic class DriverOrder {\n\n    private int driverId;\n\n    private String orderNo;\n}\n```\n\n\n\n```java\n@Test\npublic void selectBySelfDefine() {\n    SQLQuery\u003cDriverOrder\u003e query = badger.createSqlQuery(DriverOrder.class, \"select a.driver_id,b.order_no from driver a join driver_order_1 b on a.driver_id=b.driver_id where a.driver_id=?\");\n    query.addParam(13);\n    //query.setDataSourceName(\"xx\"); 如果分库需要自己指定。\n    List\u003cDriverOrder\u003e driverOrders = query.list();\n    System.out.println(driverOrders);\n}\n```\n\n### 更新\n\n```java\n/**\n * 自定义sql更新，不支持分库分表，分库分表信息得自己实现\n */\n@Test\npublic void updateBySelfDefine() {\n    UpdateSqlStatement sqlStatement = badger.createUpdateSqlStatement(\"update driver set update_date=? where driver_id=?\");\n    //sqlStatement.setDataSourceName(\"xx\");如果分库需要自己指定。\n    sqlStatement.addParam(new Date())\n                .addParam(14)\n                .execute();\n}\n```\n\n## Badger为spring boot提供了插件，方便在spring boot中使用\n\n插件只需要简单配置即可，不用再手动初始化Badger实例了，插件会根据配置自动生成Badger类。\n\n\u003e 请参考[https://github.com/fang-yan-peng/badger-spring-boot-starter]\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffang-yan-peng%2Fbadger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffang-yan-peng%2Fbadger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffang-yan-peng%2Fbadger/lists"}