7. BeetlSQL Annotation

对于自动生成的sql,默认不需要任何annotaton,类名对应于表名(通过NameConversion类),getter方法的属性名对应于列明(也是通过NameConversion类),但有些情况还是需要annotation。

BeetlSQL 支持自定义属性或者类注解来增强Dao,参考7.11 节

7.1. @AutoID 和 @AssignID ,@SeqID

  • @AutoID,作用于属性字段或者getter方法,告诉beetlsql,这是自增主键,对应于数据自增长
  • @AssignID,作用于属性字段或者getter方法,告诉beetlsql,这是程序设定
  1. @AssignID()
  2. public Long getId() {
  3. return id;
  4. }

代码设定主键允许像@AssignID 传入id的生成策略以自动生成序列,beetl默认提供了一个snowflake算法,一个用于分布式环境的id生成器(https://github.com/twitter/snowflake)

  1. @AssignID("simple")
  2. public Long getId() {
  3. return id;
  4. }

simple 是beetlsql提供的一个默认的snowflake实现,你可以通过sqlManager自己注册id生成器

  1. sqlManager.addIdAutonGen("uuid2", new IDAutoGen(){
  2. @Override
  3. public Object nextID(String params) {
  4. return "hi"+new Random().nextInt(10000);
  5. }
  6. });
  1. @AssignID("uuid2")
  2. public Long getId() {
  3. return id;
  4. }
  • @SeqID(name="xx_seq",作用于getter方法,告诉beetlsql,这是序列主键。 对于属性名为id的自增主键,不需要加annotation,beetlsql默认就是@AutoID

备注

  • 对于支持多种数据库的,这些annotation可以叠加在一起

7.2. @Tail

@Tail作用于类上,表示该对象是混合模型,参考下一章混合模型,sql查询无法在pojo映射的列或者结果集将使用Tail指定的方法

7.3. 忽略属性

BeetlSql提供InsertIgnore,UpdateIgnore俩个注解,作用于属性字段或者getter方法,前者用于内置插入的时候忽略,后者用于内置更新的时候忽略。

  1. @UpdateIgnore
  2. public Date getBir(){
  3. return bir;
  4. }

在beetlsql较早版本提供了ColumnIgnore, 提供insert或者update属性用来忽略

  1. @ColumnIgnore(insert=true,update=false)
  2. public Date getBir(){
  3. return bir;
  4. }

如上例子,插入的时候忽略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属性,用这个值作为属性,比如
  1. @EnumMapping("value")
  2. public enum Color {
  3. RED("RED",1),BLUE ("BLUE",2);
  4. private String name;
  5. private int value;
  6. private Color(String name, int value) {
  7. this.name = name;
  8. this.value = value;
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getValue() {
  17. return value;
  18. }
  19. public void setValue(int value) {
  20. this.value = value;
  21. }
  22. }

beetlsq 会获取枚举的value属性(调用getValue)来获取枚举属性值

7.5. @Table

标签 @Table(name="xxxx") 告诉beetlsql,此类对应xxxx表。比如数据库有User表,User类对应于User表,也可以创建一个UserQuery对象,也对应于User表

  1. @Table(name="user")
  2. 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 方法,分别表示 模板查询中,日期字段如果不为空,所在的日期范围,如
  1. @DateTemplate(accept="minDate,maxDate",compare=">=,<")
  2. public Date getDate() {
  3. }

在模板查询的时候,将会翻译成

  1. @if(!isEmpty(minDate)){
  2. and date>=#minDate#
  3. @}
  4. @if(!isEmpty(maxDate)){
  5. and date<#maxDate#
  6. @}

注意

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方法上,用于乐观锁实现。

  1. public class Credit implements Serializable{
  2. private Integer id ;
  3. private Integer balance ;
  4. @Version
  5. private Integer version ;

当调用内置的updateById,或者updateTemlateById的时候,被@Version注解的字段将作为where条件的一部分

  1. ┏━━━━━ Debug [credit._gen_updateTemplateById] ━━━
  2. SQL update `credit` set `balance`=?, `version`=`version`+1 where `id` = ? and `version` = ?
  3. 参数: [15, 1, 5]
  4. 位置: org.beetl.sql.test.QuickTest.main(QuickTest.java:38)
  5. 时间: 4ms
  6. 更新: [1]
  7. ┗━━━━━ Debug [credit._gen_updateTemplateById] ━━━

BeetlSQL 也支持悲观锁实现,即采用select for update 方式,只要调用SQLManager.lock(Class cls,Object key)就可以对cls对应的的表的主键为key的记录使用行锁。只有事务结束后,才释放此锁

7.10 @SqlResource

用在Mapper接口上,说明MD文件的位置,可以通过此注解指定一个在根目录下的某一个子目录位置。

  1. @SqlResource("platform.sysDict")
  2. public interface SysDictDao extends BaseMapper<SysDict> {
  3. public List<SysDict> findAllList(@Param(value = "type") String type);
  4. }

如上findAllList方法对应的sql,将位于resources/sql/platform/sysDict.md(sql)里。

这通常用在系统数据库表较多或者有多个模块的时候。

注解也可以混合作用于方法上,表示位于不同的sql文件里

7.12 @SqlProvider

了解这个注解,需要先参考第六章 Mapper,表示Sql语句来源于特定的一个类的方法提供,而不是来源于注解或者md文件

  1. @SqlProvider(provider = UserSqlProvider.class)
  2. User selectAll1( Integer id);

BeetlSQL 会查找UserSqlProvider的“selectAll1”方法,selectAll1会提供功一个模板语句

  1. public class UserSqlProvider {
  2. public String selectAll1(Integer id){
  3. StringBuilder sql = new StringBuilder("SELECT * FROM `user` WHERE 2 = 2 ");
  4. if (id!= null){
  5. sql.append("AND id = #id#");
  6. }
  7. return sql.toString();
  8. }
  9. }

SqlProvider注解也可以配合@Sql注解,提供JDBC sql操作,这时候要求参数必须返回SQLReady类

  1. @SqlProvider(provider = UserSqlProvider.class)
  2. @Sql()
  3. User selectAll2( Integer id);
  1. public SQLReady selectAll2(Integer id){
  2. StringBuilder sql = new StringBuilder("SELECT * FROM `user` WHERE 2 = 2 ");
  3. if (id!= null){
  4. sql.append("AND id = ?");
  5. }
  6. SQLReady sqlReady = new SQLReady(sql.toString(),new Object[]{id});
  7. return sqlReady;
  8. }

7.11 自定义属性注解

BeetlSQL 可以自定义属性注解用于生成sql片段(用于内置的插入更新),或者用于反序列化,如内置的@UpdateTime,用于插入和更新的时候自动向数据库插入一个当前时间

  1. @UpdateTime
  2. private Date date

UpdateTime定义如下

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(value={ElementType.METHOD,ElementType.FIELD})
  3. @Builder(value = SampleUpdateTimeBuilder.class)
  4. public @interface UpdateTime {
  5. }

SampleUpdateTimeBuilder 表示会在BeetlSQL的内置SQL生成阶段生成一个新的SQL片段,用于插入当前时间

  1. public class SampleUpdateTimeBuilder implements AttributePersistBuilder {
  2. @Override
  3. public String toSql(AbstractDBStyle dbStyle, String fieldName, String colName, Annotation an, TableDesc tableDesc){
  4. //#date()#,返回一个当前时间
  5. return "date()";
  6. }
  7. }

SampleUpdateTimeBuilder实现了 AttributePersistBuilder,因此在更新或者插入的时候起作用,他会反馈一个SQL片段 #date()#,

  1. insert into User values (#name#,#date()#)

date函数是内置的输出当前时间。

Builder类也可以实现AttributeSelectBuilder 接口,以实现数据库查询结果赋值到Bean属性,比如User对象有个Role对象是以Json格式传入

  1. @Jackson
  2. private Role role;

@Jackson 使用了SampleJsonAtrributeBuilder实现,定义如下

  1. public class SampleJsonAtrributeBuilder extends BaseAttributeBuilder {
  2. public static ObjectMapper mapper = new ObjectMapper();
  3. public static Jackson json = new Jackson();
  4. @Override
  5. public Object toObject(SQLManager sqlManager,Annotation an, String sqlId,TypeParameter typeParameter, PropertyDescriptor property) throws SQLException{
  6. if(typeParameter.getRs().wasNull()){
  7. return null;
  8. }
  9. String data = typeParameter.getRs().getString(typeParameter.getIndex());
  10. if(data==null){
  11. return null;
  12. }
  13. try {
  14. Object o = mapper.readValue(data,typeParameter.getTarget());
  15. return o;
  16. } catch (IOException e) {
  17. throw new SQLException("beetlsql 无法转化为json:"+data,e);
  18. }
  19. }
  20. @Override
  21. public String toSql(AbstractDBStyle dbStyle, String fieldName, String colName, Annotation an, TableDesc tableDesc){
  22. return "jackson("+fieldName+")";
  23. }

注意,BeetlSQL并没有内置Jackson,如果你需要使用@Jackson注解,需要引入pom,并且,注册一个叫jackson的Beetl函数