7. BeetlSQL Annotation
对于自动生成的sql,默认不需要任何annotaton,类名对应于表名(通过NameConversion类),getter方法的属性名对应于列明(也是通过NameConversion类),但有些情况还是需要annotation。
BeetlSQL 支持自定义属性或者类注解来增强Dao,参考7.11 节
7.1. @AutoID 和 @AssignID ,@SeqID
- @AutoID,作用于属性字段或者getter方法,告诉beetlsql,这是自增主键,对应于数据自增长
- @AssignID,作用于属性字段或者getter方法,告诉beetlsql,这是程序设定
@AssignID()
public Long getId() {
return id;
}
代码设定主键允许像@AssignID 传入id的生成策略以自动生成序列,beetl默认提供了一个snowflake算法,一个用于分布式环境的id生成器(https://github.com/twitter/snowflake)
@AssignID("simple")
public Long getId() {
return id;
}
simple 是beetlsql提供的一个默认的snowflake实现,你可以通过sqlManager自己注册id生成器
sqlManager.addIdAutonGen("uuid2", new IDAutoGen(){
@Override
public Object nextID(String params) {
return "hi"+new Random().nextInt(10000);
}
});
@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. 忽略属性
BeetlSql提供InsertIgnore,UpdateIgnore俩个注解,作用于属性字段或者getter方法,前者用于内置插入的时候忽略,后者用于内置更新的时候忽略。
@UpdateIgnore
public Date getBir(){
return bir;
}
在beetlsql较早版本提供了ColumnIgnore, 提供insert或者update属性用来忽略
@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属性,用这个值作为属性,比如
@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表
@Table(name="user")
public class QueryUser ..
注:可以为对象指定一个数据库shcema,如name="cms.user",此时将访问cms库(或者cms用户,对不同的数据库,称谓不一样)下的user数据表
考虑到跨数据库,最好采用大写方式,比如USER,CMS.USER,oracle 识别大写
7.6. @TableTemplate
- @TableTemplate() 用于模板查询,如果没有任何值,将按照主键降序排,也就是order by 主键名称 desc
- @DateTemplate(),作用于日期字段的属性字段或者getter方法,有俩个属性accept 和 compare 方法,分别表示 模板查询中,日期字段如果不为空,所在的日期范围,如
@DateTemplate(accept="minDate,maxDate",compare=">=,<")
public Date getDate() {
}
在模板查询的时候,将会翻译成
@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 查询一章
7.9. @Version
注解@Version作用在类型为int,long的属性或者getter方法上,用于乐观锁实现。
public class Credit implements Serializable{
private Integer id ;
private Integer balance ;
@Version
private Integer version ;
当调用内置的updateById,或者updateTemlateById的时候,被@Version注解的字段将作为where条件的一部分
┏━━━━━ Debug [credit._gen_updateTemplateById] ━━━
┣ SQL: update `credit` set `balance`=?, `version`=`version`+1 where `id` = ? and `version` = ?
┣ 参数: [15, 1, 5]
┣ 位置: org.beetl.sql.test.QuickTest.main(QuickTest.java:38)
┣ 时间: 4ms
┣ 更新: [1]
┗━━━━━ Debug [credit._gen_updateTemplateById] ━━━
BeetlSQL 也支持悲观锁实现,即采用select for update 方式,只要调用SQLManager.lock(Class cls,Object key)就可以对cls对应的的表的主键为key的记录使用行锁。只有事务结束后,才释放此锁
7.10 @SqlResource
用在Mapper接口上,说明MD文件的位置,可以通过此注解指定一个在根目录下的某一个子目录位置。
@SqlResource("platform.sysDict")
public interface SysDictDao extends BaseMapper<SysDict> {
public List<SysDict> findAllList(@Param(value = "type") String type);
}
如上findAllList方法对应的sql,将位于resources/sql/platform/sysDict.md(sql)里。
这通常用在系统数据库表较多或者有多个模块的时候。
注解也可以混合作用于方法上,表示位于不同的sql文件里
7.12 @SqlProvider
了解这个注解,需要先参考第六章 Mapper,表示Sql语句来源于特定的一个类的方法提供,而不是来源于注解或者md文件
@SqlProvider(provider = UserSqlProvider.class)
User selectAll1( Integer id);
BeetlSQL 会查找UserSqlProvider的“selectAll1”方法,selectAll1会提供功一个模板语句
public class UserSqlProvider {
public String selectAll1(Integer id){
StringBuilder sql = new StringBuilder("SELECT * FROM `user` WHERE 2 = 2 ");
if (id!= null){
sql.append("AND id = #id#");
}
return sql.toString();
}
}
SqlProvider注解也可以配合@Sql注解,提供JDBC sql操作,这时候要求参数必须返回SQLReady类
@SqlProvider(provider = UserSqlProvider.class)
@Sql()
User selectAll2( Integer id);
public SQLReady selectAll2(Integer id){
StringBuilder sql = new StringBuilder("SELECT * FROM `user` WHERE 2 = 2 ");
if (id!= null){
sql.append("AND id = ?");
}
SQLReady sqlReady = new SQLReady(sql.toString(),new Object[]{id});
return sqlReady;
}
7.11 自定义属性注解
BeetlSQL 可以自定义属性注解用于生成sql片段(用于内置的插入更新),或者用于反序列化,如内置的@UpdateTime,用于插入和更新的时候自动向数据库插入一个当前时间
@UpdateTime
private Date date
UpdateTime定义如下
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD,ElementType.FIELD})
@Builder(value = SampleUpdateTimeBuilder.class)
public @interface UpdateTime {
}
SampleUpdateTimeBuilder 表示会在BeetlSQL的内置SQL生成阶段生成一个新的SQL片段,用于插入当前时间
public class SampleUpdateTimeBuilder implements AttributePersistBuilder {
@Override
public String toSql(AbstractDBStyle dbStyle, String fieldName, String colName, Annotation an, TableDesc tableDesc){
//#date()#,返回一个当前时间
return "date()";
}
}
SampleUpdateTimeBuilder实现了 AttributePersistBuilder,因此在更新或者插入的时候起作用,他会反馈一个SQL片段 #date()#,
insert into User values (#name#,#date()#)
date函数是内置的输出当前时间。
Builder类也可以实现AttributeSelectBuilder 接口,以实现数据库查询结果赋值到Bean属性,比如User对象有个Role对象是以Json格式传入
@Jackson
private Role role;
@Jackson 使用了SampleJsonAtrributeBuilder实现,定义如下
public class SampleJsonAtrributeBuilder extends BaseAttributeBuilder {
public static ObjectMapper mapper = new ObjectMapper();
public static Jackson json = new Jackson();
@Override
public Object toObject(SQLManager sqlManager,Annotation an, String sqlId,TypeParameter typeParameter, PropertyDescriptor property) throws SQLException{
if(typeParameter.getRs().wasNull()){
return null;
}
String data = typeParameter.getRs().getString(typeParameter.getIndex());
if(data==null){
return null;
}
try {
Object o = mapper.readValue(data,typeParameter.getTarget());
return o;
} catch (IOException e) {
throw new SQLException("beetlsql 无法转化为json:"+data,e);
}
}
@Override
public String toSql(AbstractDBStyle dbStyle, String fieldName, String colName, Annotation an, TableDesc tableDesc){
return "jackson("+fieldName+")";
}
注意,BeetlSQL并没有内置Jackson,如果你需要使用@Jackson注解,需要引入pom,并且,注册一个叫jackson的Beetl函数