# fastquery
**Repository Path**: big_data_enthusiasts/fastquery
## Basic Information
- **Project Name**: fastquery
- **Description**: FastQuery 基于Java语言. 他的使命是:简化Java操作数据层.做为一个开发者,仅仅只需要设计编写DAO接口即可,在项目初始化阶段采用ASM生成好实现类. 因此,开发代码不得不简洁而优雅.从而,大幅度提升开发效率.
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: http://fastquery.org
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 67
- **Created**: 2020-05-22
- **Last Updated**: 2021-09-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README

### Apache Maven
```xml
org.fastquery
fastquery
1.0.86
```
### Gradle/Grails
```
compile 'org.fastquery:fastquery:1.0.86'
```
# FastQuery 数据持久层框架
FastQuery 基于Java语言.他的使命是:简化Java操作数据层.
提供少许`Annotation`,消费者只用关心注解的含义,这就使得框架的核心便于重构,便于持续良性发展.
## FastQuery 主要特性如下:
1. 遵循非侵入式原则,设计优雅或简单,极易上手
2. 在项目初始化阶段采用ASM生成好字节码,因此支持编译前预处理,可最大限度减少运行期的错误,显著提升程序的强壮性
3. 支持安全查询,防止SQL注入
4. 支持与主流数据库连接池框架集成
5. 支持 `@Query` 查询,使用 `@Condition`,可实现动态 `where` 条件查询
6. 支持查询结果集以JSON类型返回
7. 拥有非常优雅的`Page`(分页)设计
8. 支持`AOP`,注入拦截器只需要标识几个简单的注解,如: `@Before` , `@After`
9. 使用`@Source`可实现动态适配数据源.这个特性特别适合多租户系统中要求数据库彼此隔离其结构相同的场景里
10. 支持`@QueryByNamed`命名式查询,SQL动态模板
11. 支持存储过程
12. 支持批量更新集合实体(根据主键,批量更新不同字段,不同内容).
## 运行环境要求
JRE 8+
## 配置文件
### 配置文件的存放位置
默认从`classpath`目录下去寻找配置文件. 配置文件的存放位置支持自定义, 如: `System.setProperty("fastquery.config.dir","/data/fastquery/configs");`, 它将会覆盖`classpath`目录里的同名配置文件. 如果项目是以jar包的形式启动,那么可以通过java命令的 `-D` 参数指定配置文件的目录, 如: `java -jar Start.jar -Dfastquery.config.dir=/data/fastquery/configs`.
### c3p0-config.xml
完全支持c3p0官方配置,详情配置请参照c3p0官网的说明.
```xml
com.mysql.cj.jdbc.Driver
jdbc:mysql://192.168.1.1:3306/xk?useSSL=false
xk
abc123
50
100
50
1000
0
5
... ...
```
### druid.xml
用于配置支持Druid连接池,详细配置请参照 https://github.com/alibaba/druid
```xml
```
### hikari.xml
用于配置支持HikariCP连接池,详细配置选项请参照 https://github.com/brettwooldridge/HikariCP
连接MySQL,为了得到更好的性能,推荐配置
```xml
... ...
```
支持多连接池共存,如,同时让Druid,HikariCP工作,并配置多个数据源.
### fastquery.json
配置数据源的作用范围
```js
// @author xixifeng (fastquery@126.com)
// 配置必须遵循标准的json语法.
{
"scope":[
// config 用于指定由谁来提供数据源,如,"c3p0","druid","hikari"等等
{
"config": "c3p0", // 表示由c3p0负责提供数据源
"dataSourceName": "xk-c3p0", // 数据源的名称
"basePackages": [ // 该数据源的作用范围
"org.fastquery.example", // 包地址
"org.fastquery.dao.UserInfoDBService" // 完整类名称
// 在这可以配置多个DB接口或包地址,以","号隔开
// 提醒:在json结构中,数组的最后一个元素的后面不能加","
]
},
/*
再配置一个数据源作用域
*/
{
"config" : "mySQLDriver", // 表示由mySQLDriver负责提供数据源
"dataSourceName": "shtest_db", // 数据源的名称
"basePackages": [ // 该数据源的作用范围
"org.fastquery.example.DataAcquireDbService"
// 在这可以配置多个DB接口,以","号隔开
]
},
{
"config": "c3p0", // 表示由c3p0负责提供数据源
"basePackages": [
"org.fastquery.dao2.UserInfoDBService2"
]
}
]
}
```
**注意**: 在fastquery.json中配置作用域,其中"dataSourceName"不是必须的,"dataSourceName"要么不指定,要指定的话那么必须正确.如果没有指定"dataSourceName",那么在调用接口的时候必须指定数据源的名称.下面的适配数据源章节会讲到."basePackages"若配置了包地址,那么对应的数据源会作用这个包的所有类,及所有子包中的类.
数据源的初始化是从"fastquery.json"开始的,根据从里面读到"dataSourceName"的值,取相应的配置,继而完成数据源的创建.如,创建一个名为"rex-db"的数据源:
```js
{
"config": "c3p0",
"dataSourceName": "rex-db"
}
```
在这里,"basePackages"不是必须的,该数据源可以当做是一个服务,供没有明确指定数据源的Repository使用.
## 入门例子
当看到一个例子时,切勿断章取义,多看一眼,往往会有意想不到的结果.
- 准备一个实体
```java
public class Student
{
private String no;
private String name;
private String sex;
private Integer age;
private String dept;
// getter / setter 省略...
}
```
**实体属性跟数据库映射的字段必须为包装类型,否则被忽略**. 在实体属性上标识`@Transient`,表示该字段不参与映射.
- DAO接口
```java
public interface StudentDBService extends org.fastquery.core.Repository {
@Query("select no, name, sex from student")
JSONArray findAll();
@Query("select no,name,sex,age,dept from student")
Student[] find();
}
```
- 使用DAO接口.
```java
public class StudentDBServiceTest {
// 获取实现类
private static StudentDBService studentDBService = FQuery.getRepository(StudentDBService.class);
@Test
public void test() {
// 调用 findAll 方法
JSONArray jsonArray = studentDBService.findAll();
// 调用 find 方法
Student[] students = studentDBService.find();
}
}
```
**注意**:不用去实现StudentDBService接口.通过`FQuery.getRepository`获取DAO接口对应的实例,虽然每次获取实例消耗的性能微乎其微可以忽略不计,但是,作为一个接口并且频繁被调用,因此,建议把获取到的实例赋值给类成员变量,最好是用`static`修饰.`FQuery.getRepository`获得的实例是唯一的,不可变的.
一个接口不实现它的`public abstract`方法就毫无作用可言,因此,与之对应的实例对象是必须的,只不过是FastQuery内部替用户实现了.读者可能会问,这个自动生成的实例在什么时候生成? 动态生成的效率如何保持高效? 为此, 笔者做了相当多的功课:让所有DB实现类在项目初始化阶段进行,并且尽可能地对接口方法做静态分析,把有可能在运行期发生的错误尽最大努力提升到初始化阶段,生成代码前会检测SQL绑定是否合法有效、检测方法返回值是否符合常规、方法的参数是否满足模版的调用、是否正确地使用了分页...诸如此类问题.这些潜在问题一旦暴露,项目都启动不起来,错误信息将在开发阶段详细输出,并且必须干掉这些本该在生产环境才发生的错误,才能继续开发,迫使开发者必须朝正确的道路走,或者说框架的优良设计其核心理念引导开发者不得不写出稳健的程式.项目进入运行期,大量的校验就没必要写了,从而最大限度保证快速执行.
唯一的出路,只能引用接口,这就使得开发者编程起来不得不简单,因为面对的是一个高度抽象的模型,而不必去考虑细枝末节.接口可以看成是一个能解析SQL并能自动执行的模型,方法的参数、绑定的模版和标识的注解无不是为了实现一个目的:执行SQL,返回结果.
这种不得不面向接口的编程风格,有很多好处:耦合度趋向0,天然就是**对修改封闭,对扩展开放**,不管是应用层维护还是对框架增加新特性,这些都变得特别容易.隐藏实现,可以减少bug或者是能消灭bug,就如**解决问题,不如消灭问题**一般,解决问题的造诣远远落后于消灭问题,原因在于问题被解决后,不能证明另一个潜在问题在解决代码中不再出现,显然消灭问题更胜一筹.应用层只用写声明抽象方法和标识注解,试问bug从何而来?该框架最大的优良之处就是让开发者没办法去制造bug,至少说很难搞出问题来.不得不简便,没法造bug,显然是该项目所追求的核心目标之一.
不管用不用这个项目,笔者期望读者至少能快速地检阅一下该文档,有很多设计是众多同类框架所不具备的,希望读者从中得到正面启发或反面启发,哪怕一点点,都会使你收益.
## 针对本文@Query的由来
该项目开源后,有些习惯于繁杂编码的开发者表示,"*使用`@Query`语义不强,为何不用@SQL,@Select,@Insert,@Update...?*". SQL的全称是 Structured Query Language,本文的 `@Query` 就是来源于此. `@Query`只作为运行SQL的载体,要做什么事情由SQL自己决定.因此,不要片面的认为Query就是select操作. 针对数据库操作的注解没有必要根据SQL的四种语言(DDL,DML,DCL,TCL)来定义,定义太多,只会增加复杂度,并且毫无必要,如果是改操作加上`@Modifying`注解,反之,都是"查",这样不更简洁实用吗? 诸如此类:`@Insert("insert into table (name) values('Sir.Xi')")`,`@Select("select * from table")`,SQL的表达能力还不够吗? 就不觉得多出`@insert`和`@Select`有拖泥带水之嫌? SQL的语义本身就很强,甚至连`@Query`和`@Modifying`都略显多余,但是毕竟SQL需要有一个载体和一个大致的分类.
## 带条件查询
```java
// sql中的?1 表示对应当前方法的第1个参数
// sql中的?2 表示对应当前方法的第2个参数
// ?N 表示对应当前方法的第N个参数
// 查询返回数组格式
@Query("select no,name,sex,age,dept from student s where s.sex=:sex and s.age > ?1")
Student[] find(Integer age,@Param("sex")String sex);
// 查询返回JSON格式
@Query("select no, name, sex from student s where s.sex=:sex and s.age > ?2")
JSONArray find(@Param("sex")String sex,Integer age);
// 查询返回List Map
@Query("select no, name, sex from student s where s.sex=?1 and s.age > :age")
List