## BeetlSQL中文文档
> - 作者: 闲大赋,Gavin.King,Sue,Zhoupan,woate
> - 社区 [http://ibeetl.com](http://ibeetl.com/)
> - qq群 219324263
> - 当前版本 2.7.3 , 另外还需要beetl([http://git.oschina.net/xiandafu/beetl2.0/attach_files](http://git.oschina.net/xiandafu/beetl2.0/attach_files)) 包
### 1. BeetlSQL 特点
BeetSql是一个全功能DAO工具, 同时具有Hibernate 优点 & Mybatis优点功能,适用于承认以SQL为中心,同时又需求工具能自动能生成大量常用的SQL的应用。
- 开发效率
- 无需注解,自动使用大量内置SQL,轻易完成增删改查功能,节省50%的开发工作量
- 数据模型支持Pojo,也支持Map/List这种快速模型,也支持混合模型
- SQL 模板基于Beetl实现,更容易写和调试,以及扩展
- 可以针对单个表(或者视图)代码生成pojo类和sql模版,甚至是整个数据库。能减少代码编写工作量
- 维护性
- SQL 以更简洁的方式,Markdown方式集中管理,同时方便程序开发和数据库SQL调试。
- 可以自动将sql文件映射为dao接口类
- 灵活直观的支持支持一对一,一对多,多对多关系映射而不引入复杂的OR Mapping概念和技术。
- 具备Interceptor功能,可以调试,性能诊断SQL,以及扩展其他功能
- 其他
- 内置支持主从数据库支持的开源工具
- 支持跨数据库平台,开发者所需工作减少到最小,目前跨数据库支持mysql,postgres,oracle,sqlserver,h2,sqllite.
### 2. 5分钟例子
#### 2.1. 安装
maven 方式:
```xml
com.ibeetl
beetlsql
2.7.3
```
或者依次下载beetlsql,beetl 最新版本 包放到classpath里
#### 2.2. 准备工作
为了快速尝试BeetlSQL,需要准备一个Mysql数据库或者其他任何beetlsql支持的数据库,然后执行如下sql脚本
```sql
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT NULL,
`age` int(4) DEFAULT NULL,
`userName` varchar(64) DEFAULT NULL COMMENT '用户名称',
`roleId` int(11) DEFAULT NULL COMMENT '用户角色',
`date` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
编写一个Pojo类,与数据库表对应(或者可以通过SQLManager的gen方法生成此类,参考一下节)
```java
import java.math.*;
import java.util.Date;
/*
*
* gen by beetlsql 2016-01-06
*/
public class User {
private Integer id ;
private Integer age ;
//用户角色
private Integer roleId ;
private String name ;
//用户名称
private String userName ;
private Date date ;
}
```
#### 2.3. 代码例子
写一个java的Main方法,内容如下
```java
ConnectionSource source = ConnectionSourceHelper.getSimple(driver, url, "", userName, password);
DBStyle mysql = new MySqlStyle();
// sql语句放在classpagth的/sql 目录下
SQLLoader loader = new ClasspathLoader("/sql");
// 数据库命名跟java命名一样,所以采用DefaultNameConversion,还有一个是UnderlinedNameConversion,下划线风格的
所以采用DefaultNameConversion nc = new 所以采用DefaultNameConversion();
// 最后,创建一个SQLManager,DebugInterceptor 不是必须的,但可以通过它查看sql执行情况
SQLManager sqlManager = new SQLManager(mysql,loader,source,nc,new Interceptor[]{new DebugInterceptor()});
//使用内置的生成的sql 新增用户,如果需要获取主键,可以传入KeyHolder
User user = new User();
user.setAge(19);
user.setName("xiandafu");
sqlManager.insert(user);
//使用内置sql查询用户
int id = 1;
user = sqlManager.unique(User.class,id);
//模板更新,仅仅根据id更新值不为null的列
User newUser = new User();
newUser.setId(1);
newUser.setAge(20);
sqlManager.updateTemplateById(newUser);
//模板查询
User query = new User();
query.setName("xiandafu");
List list = sqlManager.template(query);
//使用user.md 文件里的select语句,参考下一节。
User query2 = new User();
query.setName("xiandafu");
List list2 = sqlManager.select("user.select",User.class,query2);
```
#### 2.4. SQL文件例子
通常一个项目还是有少量复杂sql,可能只有5,6行,也可能有上百行,放在单独的sql文件里更容易编写和维护,为了能执行上例的user.select,需要在classpath里建立一个sql目录(ClasspathLoader 配置成sql目录,参考上一节ClasspathLoader初始化的代码)以及下面的user.md 文件,内容如下
```markdown
select
===
select * from user where 1=1
@if(!isEmpty(age)){
and age = #age#
@}
@if(!isEmpty(name)){
and name = #name#
@}
```
关于如何写sql模板,会稍后章节说明,如下是一些简单说明。
- 采用md格式,===上面是sql语句在本文件里的唯一标示,下面则是sql语句。
- @ 和回车符号是定界符号,可以在里面写beetl语句。
- "#" 是站位符号,生成sql语句得时候,将输出?,如果你想输出表达式值,需要用text函数,或者任何以db开头的函数,引擎则认为是直接输出文本。
- isEmpty是beetl的一个函数,用来判断变量是否为空或者是否不存在.
- 文件名约定为类名,首字母小写。
sql模板采用beetl原因是因为beetl 语法类似js,且对模板渲染做了特定优化,相比于mybatis,更加容易掌握和功能强大,可读性更好,也容易在java和数据库之间迁移sql语句
#### 2.5. 代码&sql生成
User类并非需要自己写,好的实践是可以在项目中专门写个类用来辅助生成pojo和sql片段,代码如下
```java
public static void main(String[] args){
SqlManager sqlManager = ...... //同上面的例子
sqlManager.genPojoCodeToConsole("user");
sqlManager.genSQLTemplateToConsole("user");
}
```
> 注意:我经常在我的项目里写一个这样的辅助类,用来根据表或者视图生成各种代码和sql片段,以快速开发.
genPojoCodeToConsole 方法可以根据数据库表生成相应的Pojo代码,输出到控制台,开发者可以根据这些代码创建相应的类,如上例子,控制台将输出
```java
package com.test;
import java.math.*;
import java.util.Date;
import java.sql.Timestamp;
/*
*
* gen by beetlsql 2016-01-06
*/
public class user {
private Integer id ;
private Integer age ;
//用户角色
private Integer roleId ;
private String name ;
//用户名称
private String userName ;
private Date date ;
}
```
上述生成的代码有些瑕疵,比如包名总是com.test,类名是小写开头(因为用了DefaultNameConversion),你需要修改成你要的包名和正常的类名,pojo类也没有生成getter,setter方法,你需要用ide自带的工具再次生成一下。
> #### 注意
>
> 生成属性的时候,id总是在前面,后面依次是类型为Integer的类型,最后面是日期类型,剩下的按照字母排序放到中间。
一旦有了User 类,如果你需要些sql语句,那么genSQLTemplateToConsole 将是个很好的辅助方法,可以输出一系列sql语句片段,你同样可以赋值粘贴到代码或者sql模板文件里(user.md),如上例所述,当调用genSQLTemplateToConsole的时候,生成如下
```markdown
sample
===
* 注释
select #use("cols")# from user where #use("condition")#
cols
===
id,name,age,userName,roleId,date
updateSample
===
`id`=#id#,`name`=#name#,`age`=#age#,`userName`=#userName#,`roleId`=#roleId#,`date`=#date#
condition
===
1 = 1
@if(!isEmpty(name)){
and `name`=#name#
@}
@if(!isEmpty(age)){
and `age`=#age#
@}
```
beetlsql生成了用于查询,更新,条件的sql片段和一个简单例子。你可以按照你的需要copy到sql模板文件里.实际上,如果你熟悉gen方法,你可以直接gen代码和sql到你的工程里,甚至是整个数据库都可以调用genAll来一次生成
> #### 注意
>
> sql 片段的生成顺序按照数据库表定义的顺序显示
### 3. BeetlSQL 说明
#### 3.1. 获得SQLManager
SQLManager 是系统的核心,他提供了所有的dao方法。获得SQLManager,可以直接构造SQLManager.并通过过单例获取如:
```java
ConnectionSource source = ConnectionSourceHelper.getSimple(driver, url, "", userName, password);
DBStyle mysql = new MySqlStyle();
// sql语句放在classpagth的/sql 目录下
SQLLoader loader = new ClasspathLoader("/sql");
// 数据库命名跟java命名一样,所以采用DefaultNameConversion,还有一个是UnderlinedNameConversion,下划线风格的
UnderlinedNameConversion nc = new UnderlinedNameConversion();
// 最后,创建一个SQLManager,DebugInterceptor 不是必须的,但可以通过它查看sql执行情况
SQLManager sqlManager = new SQLManager(mysql,loader,source,nc,new Interceptor[]{new DebugInterceptor()});
```
更常见的是,已经有了DataSource,创建ConnectionSource 可以采用如下代码
```java
ConnectionSource source = ConnectionSourceHelper.single(datasource);
```
如果是主从Datasource
```java
ConnectionSource source = ConnectionSourceHelper.getMasterSlave(master,slaves)
```
#### 3.2. 查询API
##### 3.2.1. 模板类查询(自动生成sql)
- public List all(Class clazz) 查询出所有结果集
- public List all(Class clazz, int start, int size) 翻页
- public int allCount(Class> clazz) 总数
- public List template(T t) 根据模板查询,返回所有符合这个模板的数据库 同上,mapper可以提供额外的映射,如处理一对多,一对一
- public List template(T t,int start,int size) 同上,可以翻页
- public long templateCount(T t) 获取符合条件的个数
翻页的start,系统默认位从1开始,为了兼容各个数据库系统,会自动翻译成数据库习俗,比如start为1,会认为mysql,postgres从0开始(从start-1开始),oralce从1开始(start-0)开始。
然而,如果你只用特定数据库,可以按照特定数据库习俗来,比如,你只用mysql,start为0代表起始纪录,需要配置
```properties
OFFSET_START_ZERO = true
```
这样,翻页参数start传入0即可。
注意:根据模板查询并不包含时间字段,也不包含排序,然而,可以通过在pojo class上使用@TableTemplate() 或者日期字段的getter方法上使用@DateTemplate()来定制,如下:
```java
@TableTemplate("order by id desc ")
public class User {
private Integer id ;
private Integer age ;
// ...
@DateTemplate(accept="minDate,maxDate")
public Date getDate() {
return date;
}
}
```
这样,模板查询将添加order by id desc ,以及date字段将按照日期范围来查询。 具体参考annotation一章
##### 3.2.2. 通过sqlid查询,sql语句在md文件里
- public List select(String sqlId, Class clazz, Map paras) 根据sqlid来查询,参数是个map
- public List select(String sqlId, Class clazz, Object paras) 根据sqlid来查询,参数是个pojo
- public List select(String sqlId, Class clazz, Map paras, int start, int size), 增加翻页
- public List select(String sqlId, Class clazz, Object paras, int start, int size) ,增加翻页
- public T selectSingle(String id,Object paras, Class target) 根据sqlid查询,输入是Pojo,将对应的唯一值映射成指定的taget对象,如果未找到,则返回空。需要注意的时候,有时候结果集本生是空,这时候建议使用unique
- public T selectSingle(String id,Map paras, Class target) 根据sqlid查询,输入是Map,将对应的唯一值映射成指定的taget对象,如果未找到,则返回空。需要注意的时候,有时候结果集本生是空,这时候建议使用unique
- public T selectUnique(String id,Object paras, Class target) 根据sqlid查询,输入是Pojo或者Map,将对应的唯一值映射成指定的taget对象,如果未找到,则抛出异常
- public T selectUnique(String id,Map paras, Class target) 根据sqlid查询,输入是Pojo或者Map,将对应的唯一值映射成指定的taget对象,如果未找到,则抛出异常
- public Integer intValue(String id,Object paras) 查询结果映射成Integer,如果找不到,返回null,输入是object
- public Integer intValue(String id,Map paras) 查询结果映射成Integer,如果找不到,返回null,输入是map,其他还有 longValue,bigDecimalValue
- public T unique(Class clazz,Object pk) 根据主键查询,如果未找到,抛出异常.
#### 3.3. 翻页查询API
- public void pageQuery(String sqlId,Class clazz,PageQuery query)
BeetlSQL 提供一个PageQUery对象,用于web应用的翻页查询,BeetlSql假定有sqlId 和sqlId$count,俩个sqlId,并用这来个来翻页和查询结果总数.如:
```markdown
queryNewUser
===
select * from user order by id desc ;
queryNewUser$count
===
select count(1) from user
```
对于俩个相似的sql语句,你可以使用use函数,把公共部分提炼出来.
大部分情况下,都不需要2个sql来完成,一个sql也可以,要求使用page函数或者pageTag标签,这样才能同时获得查询结果集总数和当前查询的结果
```markdown
queryNewUser
===
select
@pageTag(){
a.*,b.name role_name
@}
from user a left join b ...
```
如上sql,会在查询的时候转为俩条sql语句
```sql
select count(1) from user a left join b...
select a.*,b.name role_name from user a left join b...
```
如果字段较多,为了输出方便,也可以使用pageTag,字段较少,用page函数也可以. ,具体参考pageTag和page函数说明.翻页代码如下
```java
//从第一页开始查询,无参数
PageQuery query = new PageQuery();
sql.pageQuery("user.queryNewUser", User.class,query);
System.out.println(query.getTotalPage());
System.out.println(query.getTotalRow());
System.out.println(query.getPageNumber());
List list = query.getList();
```
PageQuery 对象也提供了 orderBy属性,用于数据库排序,如 "id desc"
> #### 跨数据库支持
>
> 如果你打算使用PageQuery做翻页,且只想提供一个sql语句+page函数,那考虑到垮数据库,应该不要在这个sql语句里包含排序,因为大部分数据库都不支持. page函数生成的查询总数sql语句,因为包含了oder by,在大部分数据库都是会报错的的,比如:select count(1) form user order by name,在sqlserver,mysql,postgres都会出错,oracle允许这种情况, 因此,如果你要使用一条sql语句+page函数,建议排序用PageQuery对象里有排序属性oderBy,可用于排序,而不是放在sql语句里.
>
> 如果你不打算使用PageQuery+一条sql的方式,而是用俩条sql来分别翻页查询和统计总数,那无所谓
>
> 或者你直接使用select 带有起始和读取总数的接口,也没有关系,可以在sql语句里包含排序
#### 3.4. 更新API
##### 3.4.1. 自动生成sql
- public void insert(Class> clazz,Object paras) 插入paras到paras关联的表
- public void insert(Class> clazz,Object paras,KeyHolder holder),插入paras到paras关联的表,如果需要主键,可以通过holder的getKey来获取
- public int insert(Class clazz,Object paras,boolean autoAssignKey) 插入paras,并且指定是否自动将数据库主键赋值到paras里
- public int updateById(Object obj) 根据主键更新,主键通过annotation表示,如果没有,则认为属性id是主键,所有值参与更新
- public int updateTemplateById(Object obj) 根据主键更新,组件通过annotation表示,如果没有,则认为属性id是主键,属性为null的不会更新
- public int updateTemplateById(Class> clazz,Map paras) 根据主键更新,组件通过clazz的annotation表示,如果没有,则认为属性id是主键,属性为null的不会更新。
- public int[] updateByIdBatch(List> list) 批量更新
- public void insertBatch(Class clazz,List> list) 批量插入数据
##### 3.4.2. 通过sqlid更新
- public int insert(String sqlId,Object paras,KeyHolder holder) 根据sqlId 插入,并返回主键,主键id由paras对象所指定
- public int insert(String sqlId,Object paras,KeyHolder holder,String keyName) 同上,主键由keyName指定
- public int insert(String sqlId,Map paras,KeyHolder holder,String keyName),同上,参数通过map提供
- public int update(String sqlId, Object obj) 根据sqlid更新
- public int update(String sqlId, Map paras) 根据sqlid更新,输出参数是map
- public int[] updateBatch(String sqlId,List> list) 批量更新
- public int[] updateBatch(String sqlId,Map[] maps) 批量更新,参数是个数组,元素类型是map
#### 3.5. 直接执行SQL
##### 3.5.1. 直接执行sql模板语句
- public List execute(String sql,Class clazz, Object paras)
- public List execute(String sql,Class clazz, Map paras)
- public int executeUpdate(String sql,Object paras) 返回成功执行条数
- public int executeUpdate(String sql,Map paras) 返回成功执行条数
#### 3.5.2. 直接执行JDBC sql语句
- 查询 public List execute(SQLReady p,Class clazz) SQLReady包含了需要执行的sql语句和参数,clazz是查询结果,如
```java
List list = sqlManager.execute(new SQLReady("select * from user where name=? and age = ?","xiandafu",18),User.class);)
```
- 更新 public int executeUpdate(SQLReady p) SQLReady包含了需要执行的sql语句和参数,返回更新结果
- 直接使用Connection public T executeOnConnection(OnConnection call),使用者需要实现onConnection方法的call方法,如调用存储过程
```java
String md5 = sql.executeOnConnection(new OnConnection(){
@Override
public String call(Connection conn) throws SQLException {
CallableStatement cstmt = conn.prepareCall("{ ? = call md5( ? ) }");
// 其他代码
return true;
}
});
```
#### 3.6. 其他
##### 3.6.1. 强制使用主或者从
- public void useMaster(DBRunner f) DBRunner里的beetlsql调用将使用主数据库库
- public void useSlave(DBRunner f) DBRunner里的beetlsql调用将使用从数据库库
##### 3.6.2. 生成Pojo代码和SQ片段
用于开发阶段根据表名来生成pojo代码和相应的sql文件
- genPojoCodeToConsole(String table), 根据表名生成pojo类,输出到控制台.
- genSQLTemplateToConsole(String table),生成查询,条件,更新sql模板,输出到控制台。
- genPojoCode(String table,String pkg,String srcPath,GenConfig config) 根据表名,包名,生成路径,还有配置,生成pojo代码
- genPojoCode(String table,String pkg,GenConfig config) 同上,生成路径自动是项目src路径,或者src/main/java (如果是maven工程)
- genPojoCode(String table,String pkg),同上,采用默认的生成配置
- genSQLFile(String table), 同上,但输出到工程,成为一个sql模版,sql模版文件的位置在src目录下,或者src/main/resources(如果是maven)工程.
- genALL(String pkg,GenConfig config,GenFilter filter) 生成所有的pojo代码和sql模版,
- genBuiltInSqlToConsole(Class z) 根据类来生成内置的增删改查sql语句,并打印到控制台
```java
sql.genAll("com.test", new GenConfig(), new GenFilter(){
public boolean accept(String tableName){
if(tableName.equalsIgnoreCase("user")){
return true;
}else{
return false;
}
// return false
}
});
```
第一个参数是pojo类包名,GenConfig是生成pojo的配置,GenFilter 是过滤,返回true的才会生成。如果GenFilter为null,则数据库所有表都要生成
> #### 警告
>
> 必须当心覆盖你掉你原来写好的类和方法,不要轻易使用genAll,如果你用了,最好立刻将其注释掉,或者在genFilter写一些逻辑保证不会生成所有的代码好sql模板文件
### 4. 命名转化,表和列名映射
Beetlsql 默认提供了三种列明和属性名的映射类。
- DefaultNameConversion 数据库名和java属性名保持一致,如数据库表User,对应Java类也是User,数据库列是sysytemId,则java属性也是systemId,反之亦然
- UnderlinedNameConversion 将数据库下划线去掉,首字母大写,如数据库是SYS_USER(oralce数据库的表和属性总是大写的), 则会改成SysUser
- JPANameConversion 支持JPA方式的映射,适合不能用确定的映射关系
- 自定义命名转化,如果以上3个都不合适,可以自己实现一个命名转化。实现DefaultNameConversion实现方式
- 因为数据库表和列都忽略大小写区别,所以,实现NameConversion也不需要考虑大小写
```java
public class DefaultNameConversion extends NameConversion {
@Override
public String getTableName(Class> c) {
Table table = (Table)c.getAnnotation(Table.class);
if(table!=null){
return table.name();
}
return c.getSimpleName();
}
@Override
public String getColName(Class> c, String attrName) {
return attrName;
}
@Override
public String getPropertyName(Class> c, String colName) {
return colName;
}
}
```
如果有特殊的表并不符合DefaultNameConversion实现方式,你可以重新实现上面的三个方法
### 5. 复合主键
beetlsql 支持复合主键,无需像其他dao工具那样创建一个特别的主键对象,主键对象就是实体对象本生
```sql
CREATE TABLE `party` (
`id1` int(11) NOT NULL,
`id2` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id1`,`id2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
```
Party代码如下
```java
public class Party {
private Integer id1 ;
private Integer id2 ;
private String name ;
//忽略其他 getter setter方法
}
```
根据主键获取Party
```java
Party key = new Party();
key.setId1(1);
key.setId2(2);
Party party = sql.unique(Party.class, key);
```
### 6. 使用Mapper
SQLManager 提供了所有需要知道的API,但通过sqlid来访问sql有时候还是很麻烦,因为需要手敲字符串,另外参数不是map就是para,对代码理解没有好处,BeetlSql支持Mapper,将sql文件映射到一个interface。如下示例
```java
public interface UserDao extends BaseMapper {
// 使用"user.getCount"语句,无参数
public int getCount();
//使用"user.setUserStatus" 语句
public void setUserStatus(Map paras); //更新用户状态
public void setUserAnnotherStatus(User user); //更新用户状态
//使用"user.findById", 传入参数id
public User findById(@Param("id") Integer id);
//or 使用params,一一对应
@SqlStatement(params="id,status")
public User findByIdAndStatus( Integer id,Integer status);
//翻页查询,使用"user.queryNewUser"
public void queryNewUser(PageQuery query) ;
// 使用_st,_sz 翻页
@SqlStatement(params="name,age,_st,_sz")
public List queryUser( String name, Integer age,int start, int size);
//使用sqlready
@Sql(value=" update user set age = ? where id = ? ")
public void updateAge(int age,int id);
@Sql(value=" select name from user",returnType=String.class)
public List allNames();
}
```
- Interface 可以继承BaseMapper,这样可以使用BaseMapper的一些公共方法,如insert,unqiue,single,updateById,deleteById等,也可以不继承
- Interface里的方法名与Sql文件对应,如果方法名对应错了,会在调用的时候报错找不到sql。
- 方法参数可以是一个Object,或者是Map,这样,BeetlSql 自动识别为 sql的参数,也可以使用注解@Param来标注,或者混合这俩种情况 如:
```java
public void setUserStatus(Map paras,@Param("name") String name);
}
```
方法如果是查询语句,可以使用@RowStart,@RowSize 作为翻页参数,BeetlSQL将自动完成翻页功能
注意 BeetlSQL 会根据 对应的方法对应的SQL语句,解析开头,如果是select开头,就认为是select操作,同理还有update,delete,insert。如果sql 模板不是以这些关键字开头,则需要使用注解 @SqlStatement
```java
@SqlStatement(type=SqlStatementType.INSERT)
public KeyHolder newUser(User user);// 添加用户
```
SqlStatement 也可在params申明参数名称
```java
public List queryUser(@Param("name") String name,@Param("age") Integer age,@RowStart int start,@RowSize int size);
// or
@SqlStatement(params="name,age,_st,_se")
public List queryUser(String name,Integer age,int start,int size);
```
- 查询语句返回的是List,则对应SQLManager.select
- 查询语句返回的是Pojo,原始类型等非List类型,则对应的SQLManager.selectSignle,如上面的getCount
- insert 语句 如果有KeyHolder,则表示需要获取主键,对应SQLManager.insert(….,keyHolder)方法
- 参数列表里只允许有一个Pojo或者Map,作为查询参数_root,否则,需要加上@Param
- 参数列表里如果有List 或者Map[],则期望对应的是一个updateBatch操作
- 参数列表里如果@RowStart ,@RowSize,则认为是翻页语句
- 参数里如果有PageQuery,则认为是翻页查询
- 在查询中,返回的是List,但类型非Mapper指定的类型,无论是用@Sql ,还是 @SqlStatement,需要用returnType来说明,如上例子allNames 返回一个List而不是List,因此需要使用returnType做额外说明
Mapper 也支持使用JDBC SQL,这时候需要采用Sql注解
```java
@Sql(value=" update user set age = ? where id = ? ")
public void updateAge(int age,int id);
@Sql("select * from user ")
public List selectAll();
```
使用Mapper能增加Dao维护性,并能提高开发效率,建议在项目中使用。
### 7. BeetlSQL Annotation
对于自动生成的sql,默认不需要任何annotaton,类名对应于表名(通过NameConverstion类),getter方法的属性名对应于列明(也是通过NameConverstion类),但有些情况还是需要anntation。
#### 7.1. @AutoID 和 @AssignID ,@SeqID
- @AutoID,作用于getter方法,告诉beetlsql,这是自增主键,对应于数据自增长
- @AssignID,作用于getter方法,告诉beetlsql,这是程序设定
```java
@AssignID()
public Long getId() {
return id;
}
```
代码设定主键允许像@AssignID 传入id的生成策略以自动生成序列,beetl默认提供了一个snowflake算法,一个用于分布式环境的id生成器([https://github.com/twitter/snowflake](https://github.com/twitter/snowflake))
```java
@AssignID("simple")
public Long getId() {
return id;
}
```
simple 是beetlsql提供的一个默认的snowflake实现,你可以通过sqlManager自己注册id生成器
```java
sqlManager.addIdAutonGen("uuid2", new IDAutoGen(){
@Override
public Object nextID(String params) {
return "hi"+new Random().nextInt(10000);
}
});
```
```java
@AssignID("uuid2")
public Long getId() {
return id;
}
```
- @SeqID(name="xx_seq",作用于getter方法,告诉beetlsql,这是序列主键。
对于属性名为id的自增主键,不需要加annotation,beetlsql默认就是@AutoID
> #### 备注
>
> - 对于支持多种数据库的,这些annotation可以叠加在一起
#### 7.2. @Tail
@Tail作用于类上,表示该对象是混合模型,参考下一章混合模型,sql查询无法在pojo映射的列或者结果集将使用Tail指定的方法
#### 7.3. @ColumnIgnore
在beetlsql 内置的insert或者update方法的时候,使用此注解的字段(作用于getter方法)将根据注解的属性来决定是否忽略此字段
```java
@ColumnIgnore(insert=true,update=false)
public Date getBir(){
return bir;
}
```
如上例子,插入的时候忽略bir属性(往往是因为数据库指定了默认值为当前时间),更新的时候不能忽略 @ColumnIgnore的insert默认是true,update是false,因此也可以直接用 @ColumnIgnore()
#### 7.4. @EnumMapping
对于Entity使用了枚举作为属性值,可以再枚举类上定义EnumMapping,指出如何将枚举与数据库值互相转化,有四种方法
- 如果没有使用@EnumMapping,则使用枚举的名称作为属性
- @EnumMapping(EnumMapping.EnumType.STRING) 同上,使用枚举名称作为属性,数据库对应列应该是字符列
- @EnumMapping(EnumMapping.EnumType.ORDINAL) 使用枚举的顺序作为属性,数据库对应列应该是int类型,用此作为映射需要防止重构枚举的时候导致数据库也重构,应该慎用
- @EnumMapping(“xxx”),如果不是上面的的定义,则beetlsql会查找枚举类的xxx属性,用这个值作为属性,比如
```java
@EnumMapping("value")
public enum Color {
RED("RED",1),BLUE ("BLUE",2);
private String name;
private int value;
private Color(String name, int value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
```
beetlsq 会获取枚举的value属性(调用getValue)来获取枚举属性值
#### 7.5. @Table
标签 @Table(name="xxxx") 告诉beetlsql,此类对应xxxx表。比如数据库有User表,User类对应于User表,也可以创建一个UserQuery对象,也对应于User表
```java
@Table(name="user")
public class QueryUser ..
```
注:可以为对象指定一个数据库shcema,如name="cms.user",此时将访问cms库(或者cms用户,对不同的数据库,称谓不一样)下的user数据表
#### 7.6. @TableTemplate
- @TableTemplate() 用于模板查询,如果没有任何值,将按照主键降序排,也就是order by 主键名称 desc
- @DateTemplate(),作用于日期字段的getter方法上,有俩个属性accept 和 compare 方法,分别表示 模板查询中,日期字段如果不为空,所在的日期范围,如
```java
@DateTemplate(accept="minDate,maxDate",compare=">=,<")
public Date getDate() {
}
```
在模板查询的时候,将会翻译成
```javascript
@if(!isEmpty(minDate)){
and date>=#minDate#
@}
@if(!isEmpty(maxDate)){
and date<#maxDate#
@}
```
> #### 注意
>
> minDate,maxDate 是俩个额外的变量,需要定义到pojo类里,DateTemplate也可以有默认值,如果@DateTemplate(),相当于@DateTemplate(accept="min日期字段,max日期字段",compare=">=,<")
#### 7.7. Mapper相关注解
Mapper 是将sql模板文件映射成一个具体的Dao方法类,这样方位代码开发和维护
Mapper中的注解,包括常用的 SqlStatement ,SqlStatementType ,Sql,Param 还有不常用的 RowSize ,RowStart,具体参考Mapper
#### 7.8. ORMQuery
beetlsql 支持在实体类上增加ORMQuery注解,这样对于实体的查询,会触发懒加载,从而实现ORM 查询功能,具体参考ORM 查询一章
### 8. BeetlSQL 数据模型
BeetlSQL是一个全功能DAO工具,支持的模型也很全面,包括
- Pojo, 也就是面向对象Java Objec。Beetlsql操作将选取Pojoe属性和sql列的交集。额外属性和额外列将忽略.
- Map/List, 对于一些敏捷开发,可以直接使用Map/List 作为输入输出参数
```java
List