🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 自动Fetch 有时候查询结果出来后需要自动加载额外的数据,类似Hibernate 的关系映射。BeetlSQL3也支持这种自动抓取。不同hibernate的是,他不强制要求有外键关系 > 越来越多数据库设计不考虑外键,这样能提升一些性能。系统从某种角度来说也好维护。 > > Fetch不支持复合主键,只支持单主键 自动抓取通过@Fetch注解,提醒BeetlSQL3在执行完查询操作后有自动抓取需要完成,BeetlSQL3会解析此POJO的属性,如果一旦有@FetchMany或者@FetchOne,或者@FetchSql,则会执行查询操作 ```java @Data @Table(name="sys_order") @Fetch(level =2) public class CustomerOrder { @AutoID Integer id; String name; Integer customerId; @FetchOne(value="customerId") Customer customer; } @Data @Fetch(level = 2) @Table(name="sys_customer") public class Customer { @AutoID Integer id; String name; @FetchMany("customerId") List<CustomerOrder> order; } @Table(name="sys_order") @Fetch(level =2) public class CustomerOrder2 { @AutoID Integer id; String name; Integer customerId; @FetchSql("select * from sys_customer where id =#{customerId}") Customer customer; @FetchSql("select * from sys_customer s where s.id =#{customerId} order by s.id desc") List<Customer> customers; } ``` @Fetch的level属性表示抓取数据的深度,默认是一层,CustomerOrder设定为2,则不仅仅会自动抓取Customer数据,也会抓取Customer的CustomerOrder数据。如果CustomerOrder设定为3,那么,还会从CustomerOrder再次抓取Customer,实现3层抓取 > BeetlSQL3在Fetch过程中把已经抓取的过数据放入内存里,根据各自POJO类的主键判断,数据一旦曾经抓取过,则不会再从数据库里获取。因此不需要担心出现死循环.同时,缓存有利于性能优化,不需要查询数据库 @FetchOne 表示抓取一个,其value值是POJO的一个属性名,该属性名对应的值作为需要·抓取对象的主键,因此CustomerOrder的@FetchOne注解表明了需要使用CustomerOrder.customerId属性值作为主键来查询Customer。因此BeetlSQL3会发起类似如下查询 ```java Integer customerId = getAttrValue(customerOrderIns,"customerId") Customer customer = sqlMqnager.unique(Customer,customerId); ``` 对于Customer对象,需要自动抓取多个CustomerOrder,注解@FetchMany("customerId") 告诉BeetlSQL3.启用模板查询功能查询CustomerOrder,模板的key是“customerId”(也就是CustomerOrder属性customerId),值是POJO的主键,就是Customer.id.因此BeetlSQL会发起类似入如下查询 ```java Integer customerId = getPrimakeyValue(customerIns); CustomerOrder template = new CustomerOrder(); tempalte.setCustomerId(customerId); List<CustomerOrder> list = sqlManager.template(tempalte); ``` BeetlSQL3 的FetchOne操作会进行合并查询,比如查询所有CustomerOrder ```java List<CustomerOrder> orders = sqlManager.all(); ``` 在BeetlSQL3 进行自动抓取的时候,并不会逐一抓取Customer对象,而是调用sqlManager.selectByIds 一次性抓取所有Customer,提高性能 当使用自动Fetch,设置level=2的时候,出现A引用B,B又引用A的时候,需要特别设计A和B对象的hashcode方法和equals方法,避免出现无限循环,比如 ```java @Fetch(level = 2) @Table(name="sys_customer") @EqualsAndHashCode(of="id") public class Customer { @AutoID Integer id; String name; @FetchMany("customerId") List<CustomerOrder> order; } ``` 如果没有`@EqualsAndHashCode(of="id")` 那么Customer的hashcode方法包括CustomerOrder,而CustomerOrder又包含Customer,这样导致hashcode无需循环,出现StackOverflowError。 这并不是BeetlSQL的问题,是hash设计的问题 FetchOne和FetchMany支持符合条件时候抓取。如下 ```java @Data @Table(name="sys_order") @Fetch public class CustomerOrder { @AutoID Integer id; String name; Integer customerId; @FetchOne(value="customerId",enableOn="x") Customer customer; @FetchOne(value="customerId"") Account account; } ``` enableOn表示但BeetlSQL 存在变量x的时候,FetchOne才生效。 sql语句可以通过函数fetchEnableOn 来申明一个变量,如sql语句 ```sql dynamicFetchOrder1 === select * from sys_order where id = #{id} -- @ fetchEnableOn("c"); ``` fetchEnableOn的实现类是DynamicFetchEnableOnFunction,它能接受多个变量名字,并赋值一个固定值。FetchOne和FetchMany将检测是否存在此变量,如果不存在,则不会实现Fetch操作