{"id":20064102,"url":"https://github.com/sagframe/sqltoy-quickstart","last_synced_at":"2025-05-05T17:33:29.010Z","repository":{"id":103366286,"uuid":"291880262","full_name":"sagframe/sqltoy-quickstart","owner":"sagframe","description":"sqltoy-orm 快速上手学习演示项目","archived":false,"fork":false,"pushed_at":"2024-11-14T15:31:07.000Z","size":68616,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-09T02:12:50.231Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/sagframe.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}},"created_at":"2020-09-01T02:54:40.000Z","updated_at":"2024-11-14T15:31:10.000Z","dependencies_parsed_at":"2024-11-09T06:20:34.228Z","dependency_job_id":"d9761a41-44e9-42ef-ae5e-6e08747bbd67","html_url":"https://github.com/sagframe/sqltoy-quickstart","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/sagframe%2Fsqltoy-quickstart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sagframe%2Fsqltoy-quickstart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sagframe%2Fsqltoy-quickstart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sagframe%2Fsqltoy-quickstart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sagframe","download_url":"https://codeload.github.com/sagframe/sqltoy-quickstart/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252542556,"owners_count":21764989,"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":[],"created_at":"2024-11-13T13:44:48.946Z","updated_at":"2025-05-05T17:33:28.994Z","avatar_url":"https://github.com/sagframe.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sqltoy-orm 快速上手项目\n* quickstart只演示了部分功能,核心是让大家快速上手，详细功能参见文档\n* 理论上来sqltoy可以解决您项目上全部数据库交互，我们的erp、数据平台、电商平台已经验证了这一点\n\n# 学习步骤\n## 1. 配置pom引入sqltoy的依赖\n\n```xml\n\u003cdependency\u003e\n\t\u003cgroupId\u003ecom.sagframe\u003c/groupId\u003e\n\t\u003cartifactId\u003esagacity-sqltoy-spring-starter\u003c/artifactId\u003e\n\t\u003cversion\u003e5.6.31\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003c!-- \n注意注意: 配置连接池依赖\n\n1、druid连接池\n\u003cdependency\u003e\n\t\u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n\t\u003cartifactId\u003edruid-spring-boot-starter\u003c/artifactId\u003e\n   \u003cversion\u003e1.2.23\u003c/version\u003e\n\u003c/dependency\u003e\n\n2、springboot自带的hikari连接池需要额外增加依赖\n\u003cdependency\u003e\n\t\u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n\t\u003cartifactId\u003espring-boot-starter-jdbc\u003c/artifactId\u003e\n\t\u003cversion\u003e3.3.5\u003c/version\u003e\n\u003c/dependency\u003e\n--\u003e\n```\n\n## 2. 配置正确pom build避免sql文件无法编译到classes下面\n* 核心配置:src/main/java 下面的\u003cinclude\u003e**/*.xml\u003c/include\u003e\n\n```xml\n\u003cresources\u003e\n\t\u003cresource\u003e\n\t\t\u003cdirectory\u003esrc/main/java\u003c/directory\u003e\n\t\t\u003cexcludes\u003e\n\t\t\t\u003cexclude\u003e**/*.java\u003c/exclude\u003e\n\t\t\u003c/excludes\u003e\n\t\t\u003cincludes\u003e\n\t\t\t\u003cinclude\u003e**/*.xml\u003c/include\u003e\n\t\t\u003c/includes\u003e\n\t\u003c/resource\u003e\n\t\u003cresource\u003e\n\t\t\u003cdirectory\u003esrc/main/resources\u003c/directory\u003e\n\t\t\u003cincludes\u003e\n\t\t\t\u003cinclude\u003e**/*.xml\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.properties\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.yml\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.sql\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.jpg\u003c/include\u003e\n            \u003cinclude\u003e**/*.key\u003c/include\u003e\n\t\t\u003c/includes\u003e\n\t\u003c/resource\u003e\n\u003c/resources\u003e\n\u003ctestResources\u003e\n\t\u003ctestResource\u003e\n\t\t\u003cdirectory\u003esrc/test/java\u003c/directory\u003e\n\t\t\u003cexcludes\u003e\n\t\t\t\u003cexclude\u003e**/*.java\u003c/exclude\u003e\n\t\t\u003c/excludes\u003e\n\t\t\u003cincludes\u003e\n\t\t\t\u003cinclude\u003e**/*.xml\u003c/include\u003e\n\t\t\u003c/includes\u003e\n\t\u003c/testResource\u003e\n\t\u003ctestResource\u003e\n\t\t\u003cdirectory\u003esrc/test/resources\u003c/directory\u003e\n\t\t\u003cincludes\u003e\n\t\t\t\u003cinclude\u003e**/*.xml\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.properties\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.yml\u003c/include\u003e\n\t\t\t\u003cinclude\u003e**/*.sql\u003c/include\u003e\n            \u003cinclude\u003e**/*.key\u003c/include\u003e\n\t\t\u003c/includes\u003e\n\t\u003c/testResource\u003e\n\u003c/testResources\u003e\n```\n\n## 3. 配置application.yml，注意阅读配置上的备注\n*  注意要点:sqlResourcesDir 是路径名,多个路径用逗号分隔,不要填错\n* spring.sqltoy千万不要写成sqltoy漏掉spring开头\n\n```\n#完整路径:spring.sqltoy\nspring:\n   sqltoy:\n        # 多个路径用逗号分隔(这里要注意是路径,sqltoy会自动向下寻找以sql.xml结尾的文件,不要写成classpath:com/**/*.sql.xml)\n        sqlResourcesDir: classpath:com/sqltoy/quickstart\n        # 默认值为classpath:sqltoy-translate.xml，一致则可以不用设置\n        translateConfig: classpath:sqltoy-translate.xml\n\t\t# 默认开启跨数据库函数自动适配(如oracle的nvl,当数据库切到mysql时会自动替换成ifnull)\n        #functionConverts: default\n        # 默认为false，debug模式将打印执行sql,并自动检测sql文件更新并重新加载\n        debug: true\n        # 提供统一字段:createBy createTime updateBy updateTime 等字段补漏性(为空时)赋值(可选配置)\n        unifyFieldsHandler: com.sqltoy.plugins.SqlToyUnifyFieldsHandler\n        # sql执行超过多长时间则进行日志输出,用于监控哪些慢sql(可选配置:默认30秒)\n        printSqlTimeoutMillis: 300000\n        # 数据库保留字兼容处理(原则上不要使用数据库保留字,多个用逗号分隔)\n        #reservedWords: maxvalue,minvalue\n```\n\n* 最简单配置(注意:spring.sqltoy开头)\n\n```\n#完整路径:spring.sqltoy\nspring:\n   sqltoy:\n        # 多个路径用逗号分隔(注意这里填路径、路径!会自动相信寻找)\n        sqlResourcesDir: classpath:com/sqltoy/quickstart\n```\n* properties 模式\n\n```\n# sqltoy config\nspring.sqltoy.sqlResourcesDir=classpath:com/sqltoy/quickstart\n# 默认配置:classpath:sqltoy-translate.xml;classpath:translates,可以多个.trans.xml 放于classpath:translates目录下面\nspring.sqltoy.translateConfig=classpath:sqltoy-translate.xml\n# 默认关闭函数替换\n#spring.sqltoy.functionConverts=default\n# 是否开启debug模式,在开发阶段建议为true,会打印sql\nspring.sqltoy.debug=true\n#项目中用到的数据库保留字定义,这里是举例，正常情况下不用定义\n#spring.sqltoy.reservedWords=status,sex_type\n# 设置获取数据源的策略实现类,只在多数据源场景下需要设置,DefaultDataSourceSelector是默认实现\n#dataSourceSelector: org.sagacity.sqltoy.plugins.datasource.impl.DefaultDataSourceSelector\n#spring.sqltoy.defaultDataSource=dataSource\nspring.sqltoy.unifyFieldsHandler=com.sqltoy.plugins.SqlToyUnifyFieldsHandler\n#spring.sqltoy.printSqlTimeoutMillis=200000\n```\n\n## 4. 编写springboot 主程序,注意@ComponentScan配置\n* 参见:src/main/java 下面的SqlToyApplication\n\n```java\npackage com.sqltoy;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n/**\n * \n * @project sqltoy-quickstart\n * @description quickstart 主程序入口\n * @author zhongxuchen \n * @version v1.0, Date:2020年7月17日\n * @modify 2020年7月17日,修改说明\n */\n@SpringBootApplication\n@ComponentScan(basePackages = { \"com.sqltoy.config\", \"com.sqltoy.quickstart\" })\n@EnableTransactionManagement\npublic class SqlToyApplication {\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SqlToyApplication.class, args);\n\t}\n}\n\n```\n\n## 5. 初始化数据库\n* 参见src/test/java 下面的InitDataBaseTest,生成数据库表结构和初始化数据\n\n```java\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = SqlToyApplication.class)\npublic class InitDataBaseTest {\n\n\t@Autowired\n\tprivate InitDBService initDBService;\n\n\t@Test\n\tpublic void testInitDB() {\n\t\tString dbSqlFile = \"classpath:mock/quickstart_init.sql\";\n\t\tSystem.err.println(\"开始执行数据库初始化!\");\n\t\tinitDBService.initDatabase(dbSqlFile);\n\t}\n}\n```\n\n## 6. 利用quickvo生产VO(或POJO)\n* 在出问题时关注dataSource中的schema、catalog配置,其他问题请参见quickvo.xml中的注释\n* pom.xml中增加quickvo的maven插件\n\n\n```xml\n\u003cplugin\u003e\n\t\u003cgroupId\u003ecom.sagframe\u003c/groupId\u003e\n\t\u003cartifactId\u003equickvo-maven-plugin\u003c/artifactId\u003e\n\t\u003cversion\u003e1.0.2\u003c/version\u003e\n\t\u003cconfiguration\u003e\n\t\t\u003cconfigFile\u003e./src/main/resources/quickvo.xml\u003c/configFile\u003e\n\t\t\u003cbaseDir\u003e${project.basedir}\u003c/baseDir\u003e\n\t\u003c/configuration\u003e\n\t\u003cdependencies\u003e\n\t\t\u003cdependency\u003e\n\t\t\t\u003cgroupId\u003ecom.mysql\u003c/groupId\u003e\n\t\t\t\u003cartifactId\u003emysql-connector-j\u003c/artifactId\u003e\n\t\t\t\u003cversion\u003e${mysql.version}\u003c/version\u003e\n\t\t\u003c/dependency\u003e\n\t\u003c/dependencies\u003e\n\u003c/plugin\u003e\n```\n\n* 配置src/main/resources/quickvo.xml 中的任务,关键部分如下\n\n```xml\n\u003c!-- db配置文件 --\u003e\n\u003cproperty file=\"db.properties\" /\u003e\n\u003cproperty name=\"project.version\" value=\"1.0.0\" /\u003e\n\u003cproperty name=\"project.name\" value=\"sqltoy-quickstart\" /\u003e\n\u003cproperty name=\"project.package\" value=\"com.sqltoy\" /\u003e\n\u003cproperty name=\"include.schema\" value=\"false\" /\u003e\n\u003c!--set method 是否支持返回对象自身(默认是false),即: public VO setName(String name){this.name=name;return this;} --\u003e\n\u003cproperty name=\"field.support.linked.set\" value=\"true\" /\u003e\n\u003c!-- schema 对照关系:mysql 对应  db 名称; oracle 对应 用户名称;   --\u003e\n\u003c!-- 注意:当在多schema或tablespace场景下，会出现一个表中出现重复字段，是因为schema和catalog 配置不正确，没有完成隔离   --\u003e\n\u003cdatasource name=\"quickstart\" url=\"${spring.datasource.url}\" driver=\"${spring.datasource.driver-class-name}\" schema=\"${spring.datasource.username}\"\n\t\tcatalog=\"${spring.datasource.username}\" username=\"${spring.datasource.username}\" password=\"${spring.datasource.password}\" /\u003e\n\u003ctasks dist=\"src/main/java\" encoding=\"UTF-8\"\u003e\n\t\u003c!-- include 是表名匹配的正则表达式  --\u003e\n\t\u003ctask active=\"true\" author=\"zhongxuchen\" include=\"^SQLTOY_\\w+\" datasource=\"quickstart\" swagger-model=\"false\"\u003e\n\t\t\u003c!-- substr 表示截取表名的前缀部分(一般表会按模块增加前缀),如不截取则substr=\"\" name=\"#{subName}VO\" subName是约定词,VO这两个字符可以随意改变  --\u003e\n\t\t\u003centity package=\"${project.package}.quickvo.vo\" substr=\"Sqltoy\" name=\"#{subName}VO\" /\u003e\n\t\u003c/task\u003e\n\u003c/tasks\u003e\n```\n\n* 点击mvn-quickvo.bat 即可生产VO了\n* windows环境下:\n\n```\nmvn quickvo:quickvo\n```\n\n# 源码导航\n*  阅读的入口 src/test/java com.sqltoy.quickstart\n* InitDataBaseTest 数据库初始化测试调用\n* StaffInfoServiceTest 演示常规的CRUD\n* TreeTableTest 演示树形表结构的构建和查询\n* ShardingSearchTest 演示分表记录保存和查询(Sharding策略请参见src/main/java com.sqltoy.config.ShardingStrategyConfig )\n* AdvanceQueryTest 查询相关的演示\n* UniqueCaseTest 演示唯一性验证\n* CascadeCaseTest 演示级联操作 \n* LockCaseTest 演示锁记录修改操作\n* StoreTest 演示存储过程调用\n* JavaCodeSqlTest 演示在代码中写sql实现原本xml中的功能\n* DTOConvertPOJOTest 演示在严格分层场景下DTO和POJO互转的范例\n* LinkOptCaseTest 演示链式操作\n* EntityOptsCaseTest 基于POJO类型的单表操作演示\n* JsonTypeCaseTest 演示json等特殊类型的支持\n* TransLedgerConcurrentTest 演示类似订单交易台账高并发事务处理\n* ExecuteSql 演示executeSql和batchUpdate 执行sql更新或批量更新操作\n* SecureEncryptDecryptTest 演示字段加解密功能\n\n# 疑问解答\n## 为什么要将*.sql.xml 放在java路径下?\n* sqltoy推荐大家项目按照业务划分先分模块(消息中心、系统管理、订单管理等)后分层(web层、service)，sql文件放于模块中便于模块整体迁移和产品化\n* 有利于开发过程，一般项目按模块分工，让开发者不需要不断的切换目录\n* 当然这个是sqltoy推荐做法，开发者则可以根据自身实际情况而定,并非强制!\n\n## 为什么缓存不用redis?\n* 这里的缓存主要用于频繁的结果字段翻译，一旦你用了缓存翻译后你就会发现会在极为广泛的范围内使用，只有本地内存级缓存才能经得起频繁任意反复的调用，没有必要再来一个redis的IO消耗\n* 你可以通过扩展实现ehcache+redis模式，来提升缓存的刷新实时性,但代价比较大造成了项目的复杂性,sqltoy提供的增量更新模式基本可以控制秒级更新 \n\n## 为什么quickvo任务不是一个，而是按模块分多个任务\n* sqltoy强调项目模块化，便于开发提炼出相对产品化的功能模块，逐步减少每次项目重复性工作，让不通过业务代码集中于一个模块下便于模块成熟后的抽离\n\n## 如何分VO和POJO\n* 请参见sqltoy-strict项目 https://github.com/sagframe/sqltoy-strict\n\n## 如何分库分表\n* 在本项目里面已经演示了分表\n* 分库分表含事务型的范例: https://github.com/sagframe/sqltoy-showcase/tree/master/trunk/sqltoy-sharding\n\n## 为什么dao不采用mybatis plus的接口模式？\n* mybatis dao采用接口模式，是其向jpa方向靠拢的一种模式，而sqltoy本身就是jpa+查询模式，也就是说jpa向查询方向加强，正好相反！\n* 什么接口?能够用接口来完成就是意味着可以用一个通用方法来代替！因此接口式dao的存在必要性就值得商榷！\n\n```java\n@Service(\"organInfoService\")\npublic class OrganInfoServiceImpl implements OrganInfoService {\n    //lightDao 就可以代替接口式的dao\n\t@Autowired\n\tLightDao lightDao;\n\n\t@Transactional\n\tpublic void saveOrganInfo(OrganInfoVO organInfoVO) {\n\t\t// 先保存机构\n\t\tlightDao.saveOrUpdate(organInfoVO);\n\t\t// 设置树形表的节点路径等字段值,便于统一树形查询\n\t\t// id字段根据vo找表的主键会自动匹配上,其它的NODE_ROUTE\\NODE_LEVEL\\IS_LEAF 为标准命名无需额外设置\n\t\t//idField 如果是主键则无需设置\n\t\tlightDao.wrapTreeTableRoute(new TreeTableModel(organInfoVO).pidField(\"organPid\"));\n\t}\n}\n\n```\n* 考虑一些场景下dao仍然要做一些数据的封装处理(简化service层，将service尽量体现业务逻辑，减少一些dao的数据组装干扰)，sqltoy仍然可以写dao，但dao时实体类！\n\n如下：实体类又有何不妥呢！清晰又可以针对一些特殊情况自己完善一些小处理，mybatis那种接口通过aop方式谈不上什么酷和高技术，不要被带到沟里去了，清晰、可维护、好拓展才是正道!\n\n```java\n@Repository(\"staffInfoDao\")\npublic class StaffInfoDao extends SqlToyDaoSupport {\n\t/**\n\t * @TODO 提供一个分页并动态设置缓存翻译的演示\n\t * @param pageModel\n\t * @param staffInfoVO\n\t * @return\n\t */\n\tpublic Page\u003cStaffInfoVO\u003e findStaff(Page\u003cStaffInfoVO\u003e pageModel, StaffInfoVO staffInfoVO) {\n\t\t// sql可以直接在代码中编写,复杂sql建议在xml中定义\n\t\t// 单表entity查询场景下sql字段可以写成java类的属性名称\n\t\t// 单表查询一般适用于接口内部查询\n\t\tString sql = \"#[staffName like :staffName]#[and createTime\u003e=:beginDate]#[and createTime\u003c=:endDate]\";\n\t\treturn findPageEntity(pageModel,StaffInfoVO.class, EntityQuery.create().where(sql).values(staffInfoVO)\n\t\t\t\t// 字典缓存必须要设置cacheType\n\t\t\t\t// 单表对象查询需设置keyColumn构成select keyColumn as column模式\n\t\t\t\t.translates(new Translate(\"dictKeyName\").setColumn(\"sexTypeName\").setCacheType(\"SEX_TYPE\")\n\t\t\t\t\t\t.setKeyColumn(\"sexType\"))\n\t\t\t\t.translates(new Translate(\"organIdName\").setColumn(\"organName\").setKeyColumn(\"organId\")));\n\t}\n```\n\n## 多数据源怎么弄?\n* sqltoy可以配置默认数据源\n\n```properties\nspring.sqltoy.defaultDataSource=dataSourceName\n```\n\n* 如果是同类单据根据特定规则分多个库，请参见分库策略进行\n* 通过多个lightDao模式\n\n```java\n\t@Bean(name = \"skyLightDao\")\n    public LightDao sqlToySkylineDao(@Qualifier(\"dataSourceSkyline\") DataSource dataSource){\n        LightDao dao = new LightDaoImpl();\n        dao.setDataSource(dataSource);\n        return dao;\n    }\n\n    @Bean(name = \"lightDdao\")\n    public LightDao sqlToyLazyDao(@Qualifier(\"dataSource\") DataSource dataSource) {\n        LightDao dao = new LightDaoImpl();\n        dao.setDataSource(dataSource);\n        return dao;\n    }\n```\n\n* 通过lightDdao里面调用时指定dataSource,save、update、load等都有链式操作\n\n```java\nlightDdao.save().dataSource(dataSource).saveMode(SaveMode.IGNORE).many(entities);\nlightDdao.query().sql(\"qstart_fastPage\").dataSource(dataSource).entity(staffVO).findPage(pageModel);\n```\n\n## 我想通过包路径来实现不同数据库访问\n* 请扩展实现org.sagacity.sqltoy.plugins.datasource.DataSourceSelector 接口\n* 当前默认实现(你可以通过aop+ThreadLocal来修改实现)\n\n```java\npublic class DefaultDataSourceSelector implements DataSourceSelector {\n\n\t@Override\n\tpublic DataSource getDataSource(ApplicationContext applicationContext, DataSource pointDataSouce,\n\t\t\tString sqlDataSourceName, DataSource injectDataSource, DataSource defaultDataSource) {\n\t\t// 第一优先:直接指定的数据源不为空\n\t\tif (pointDataSouce != null) {\n\t\t\treturn pointDataSouce;\n\t\t}\n\t\tDataSource result = null;\n\t\t// 第二优先:sql中指定的数据源\u003csql id=\"xxx\" datasource=\"xxxxDataSource\"\u003e\n\t\tif (StringUtil.isNotBlank(sqlDataSourceName)) {\n\t\t\tresult = getDataSourceBean(applicationContext, sqlDataSourceName);\n\t\t}\n\t\t// 第三优先:dao中autowired注入的数据源\n\t\tif (result == null) {\n\t\t\tresult = injectDataSource;\n\t\t}\n\t\t// 第四优先:sqltoy 统一设置的默认数据源\n\t\tif (result == null) {\n\t\t\tresult = defaultDataSource;\n\t\t}\n\t\t// 如果项目中只定义了唯一的数据源，则直接使用\n\t\tif (result == null) {\n\t\t\tMap\u003cString, DataSource\u003e dataSources = applicationContext.getBeansOfType(DataSource.class);\n\t\t\t// 只有一个dataSource,直接使用\n\t\t\tif (dataSources.size() == 1) {\n\t\t\t\tresult = dataSources.values().iterator().next();\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n```\n## sqltoy传参支持map吗？\n* sqltoy传参可以三种\n\n```java\n    /**\n\t * @todo 通过对象传参数,简化paramName[],paramValue[] 模式传参\n\t * @param \u003cT\u003e\n\t * @param sqlOrNamedSql 可以是具体sql也可以是对应xml中的sqlId\n\t * @param entity        通过对象传参数,并按对象类型返回结果\n\t * @return\n\t */\n\tpublic \u003cT extends Serializable\u003e List\u003cT\u003e findBySql(final String sqlOrNamedSql, final T entity);\n\t\n\t/**\n\t * @todo 通过给定sql、sql中的参数名、参数的数值以及返回结果的对象类型进行条件查询\n\t */\n\tpublic \u003cT\u003e List\u003cT\u003e findBySql(final String sqlOrSqlId, final String[] paramsNamed, final Object[] paramsValue,\n\t\t\tfinal Class\u003cT\u003e voClass);\n\t/**\n\t * @todo 通过map传参\n\t */\n    public \u003cT\u003e List\u003cT\u003e findBySql(final String sqlOrSqlId, final Map\u003cString, Object\u003e paramsMap, final Class\u003cT\u003e voClass);\n```\n\n## sqltoy必须返回VO吗?\n* sqltoy返回结果可以是VO、map、二维List，List\u003cObject[]\u003e\n\n```java\n    /**\n\t * @todo 通过给定sql、sql中的参数、参数的数值以及返回结果的对象类型进行条件查询\n\t * @param sqlOrSqlId\n\t * @param paramsNamed 如果sql是select * from table where xxx=?\n\t *                    问号传参模式，paramNamed设置为null\n\t * @param paramsValue 对应Named参数的值\n\t * @param voClass     返回结果List中的对象类型(可以是VO、null:表示返回List\u003cList\u003e;HashMap.class,Array.class 返回List\u003cObject[])\n\t * @return\n\t */\n\tpublic \u003cT\u003e List\u003cT\u003e findBySql(final String sqlOrSqlId, final String[] paramsNamed, final Object[] paramsValue,\n\t\t\tfinal Class\u003cT\u003e voClass);\n```\n\n## sqltoy 的sql必须写在xml中吗？\n* sqltoy强调复杂sql放于xml中，但不限制您,如下面的代码第一个参数是sql或者sqlId，你可以直接传sql语句\n\n```java\npublic \u003cT\u003e List\u003cT\u003e findBySql(final String sqlOrSqlId, final String[] paramsNamed, final Object[] paramsValue,\n\t\t\tfinal Class\u003cT\u003e voClass);\n```\n\n## 还有??\n* 请阅读sqltoy下面的word文档说明\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsagframe%2Fsqltoy-quickstart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsagframe%2Fsqltoy-quickstart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsagframe%2Fsqltoy-quickstart/lists"}