feat: 增加缓存机制,sql在生命周期内仅构建一次

This commit is contained in:
wangyu 2023-03-01 11:12:28 +08:00
parent b9a34446ae
commit 4f8384ee88
8 changed files with 107 additions and 30 deletions

View File

@ -14,6 +14,7 @@ import group.flyfish.fluent.query.Parameterized;
import group.flyfish.fluent.query.Query;
import group.flyfish.fluent.update.Update;
import group.flyfish.fluent.update.UpdateImpl;
import group.flyfish.fluent.utils.cache.CachedWrapper;
import group.flyfish.fluent.utils.context.AliasComposite;
import group.flyfish.fluent.utils.data.ParameterUtils;
import group.flyfish.fluent.utils.sql.ConcatSegment;
@ -25,6 +26,7 @@ import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
@ -42,6 +44,9 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
// 主表class默认是第一个from的表为主表
private Class<?> primaryClass;
// sql实体提供者
private final Supplier<SQLEntity> entity = CachedWrapper.wrap(this::entity);
/**
* 绑定实现类
*
@ -190,7 +195,7 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
* @param <T> 泛型
*/
public <T> T one(Class<T> clazz) {
return SHARED_OPERATIONS.selectOne(entity(), clazz);
return SHARED_OPERATIONS.selectOne(entity.get(), clazz);
}
@Override
@ -206,7 +211,7 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
*/
@Override
public <T> List<T> list(Class<T> clazz) {
return SHARED_OPERATIONS.select(entity(), clazz);
return SHARED_OPERATIONS.select(entity.get(), clazz);
}
/**
@ -265,6 +270,7 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
* @return 转换结果
*/
private SQLEntity entity() {
return SQLEntity.of(this::sql, this::parsedParameters);
return SQLEntity.of(CachedWrapper.wrap(this::sql), this::parsedParameters);
}
}

View File

@ -44,5 +44,4 @@ public interface AfterOrderSqlChain extends ExecutableSql {
* @return 结果列表
*/
<T> List<T> list(Class<T> clazz);
}

View File

@ -0,0 +1,20 @@
package group.flyfish.fluent.utils.cache;
import java.util.function.Supplier;
/**
* 绑定的单值对象
*
* @param <T> 泛型
*/
public class BoundObject<T> {
private T object;
public T computeIfAbsent(Supplier<T> supplier) {
if (null == object) {
object = supplier.get();
}
return object;
}
}

View File

@ -0,0 +1,23 @@
package group.flyfish.fluent.utils.cache;
import java.util.function.Supplier;
/**
* 缓存的supplier
*
* @author wangyu
*/
public interface CachedWrapper {
/**
* 包装简单的supplier
*
* @param supplier 提供者
* @param <T> 泛型
* @return 结果
*/
static <T> Supplier<T> wrap(Supplier<T> supplier) {
BoundObject<T> object = new BoundObject<>();
return () -> object.computeIfAbsent(supplier);
}
}

View File

@ -0,0 +1,18 @@
package group.flyfish.fluent.utils.sql;
/**
* sql方法用于缓存执行
*
* @param <R> 返回值泛型
*/
@FunctionalInterface
public interface SqlMethod<R> {
/**
* 执行方法
*
* @param parameters 参数
* @return 结果
*/
R execute(Object... parameters);
}

View File

@ -37,18 +37,21 @@ public class FluentJdbcTest {
new Driver(),
"jdbc:mysql://127.0.0.1:3306/epi_project?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=Asia/Shanghai",
"root",
"oI3WtMO8h%mSYARp"
"Unicom#2018" // "oI3WtMO8h%mSYARp"
);
// 准备待测试用例
List<TestCase<?>> cases = Arrays.asList(
// jdbc测试
new JdbcTestCase(dataSource),
// Mybatis测试
new MybatisTestCase(dataSource),
new FluentSqlTestCase(dataSource)
// FluentSQL测试
new FluentSqlTestCase(dataSource),
// 单表测试
new SingleTableTestCase()
);
// 执行测试
cases.forEach(TestCase::test);
// 单表测试
new SingleTableTestCase().test();
}
/**

View File

@ -43,20 +43,23 @@ public abstract class AbstractTestCase<T> implements TestCase<T> {
Name anno = getClass().getAnnotation(Name.class);
assert anno != null;
String name = anno.value();
long current = System.currentTimeMillis();
T result = null;
print("=====准备执行任务《{0}》=====", name);
try {
result = run();
long current = System.currentTimeMillis();
T result = run();
print("【初次执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current);
for (int i = 0; i < 10; i ++) {
current = System.currentTimeMillis();
result = run();
print("【正常执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current);
}
printResult(result);
return result;
} catch (Exception e) {
print("执行失败!{0}", e.getMessage());
throw new RuntimeException(e);
} finally {
print("【正常执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current);
printResult(result);
print("=====完成执行任务《{0}》=====");
}
}
}

View File

@ -1,7 +1,8 @@
package group.flyfish.framework.cases;
import group.flyfish.fluent.debug.FluentSqlDebugger;
import group.flyfish.fluent.chain.select.AfterWhereSqlChain;
import group.flyfish.fluent.operations.JdbcTemplateFluentSQLOperations;
import group.flyfish.fluent.utils.cache.CachedWrapper;
import group.flyfish.framework.TestCase;
import group.flyfish.framework.entity.SaasOrder;
import group.flyfish.framework.entity.SaasPlan;
@ -11,6 +12,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.util.List;
import java.util.function.Supplier;
import static group.flyfish.fluent.chain.SQL.select;
import static group.flyfish.fluent.chain.select.SelectComposite.composite;
@ -19,6 +21,8 @@ import static group.flyfish.fluent.query.Query.where;
@TestCase.Name("使用fluent-sql")
public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
private AfterWhereSqlChain sql;
public FluentSqlTestCase(DataSource dataSource) {
super(dataSource);
}
@ -32,6 +36,18 @@ public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
public void initialize() throws Exception {
// 基于构造器自动绑定注册在实际应用中使用@Bean声明即可可参考下面的demo
new JdbcTemplateFluentSQLOperations(new JdbcTemplate(dataSource));
// 缓存构建结果
this.sql = select(
// 查询租户全量字段
composite(SaasTenant::getId, SaasTenant::getName, SaasTenant::getIdentifier, SaasTenant::getDatasource,
SaasTenant::getStorage, SaasTenant::getStatus, SaasTenant::getEnable),
// 查询套餐
composite(SaasOrder::getQuotaConfig, SaasOrder::getOrderTime, SaasOrder::getExpireTime,
SaasOrder::getOrderType))
.from(SaasTenant.class)
.leftJoin(SaasOrder.class).on(where(SaasOrder::getTenantId).eq(SaasTenant::getId))
.leftJoin(SaasPlan.class).on(where(SaasPlan::getId).eq(SaasOrder::getPlanId))
.matching(where(SaasTenant::getEnable).eq(true));
// 启用调试
// FluentSqlDebugger.enable();
}
@ -45,17 +61,6 @@ public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
@Override
public List<TenantContext> run() throws Exception {
// 一个平平无奇的查询
return select(
// 查询租户全量字段
composite(SaasTenant::getId, SaasTenant::getName, SaasTenant::getIdentifier, SaasTenant::getDatasource,
SaasTenant::getStorage, SaasTenant::getStatus, SaasTenant::getEnable),
// 查询套餐
composite(SaasOrder::getQuotaConfig, SaasOrder::getOrderTime, SaasOrder::getExpireTime,
SaasOrder::getOrderType))
.from(SaasTenant.class)
.leftJoin(SaasOrder.class).on(where(SaasOrder::getTenantId).eq(SaasTenant::getId))
.leftJoin(SaasPlan.class).on(where(SaasPlan::getId).eq(SaasOrder::getPlanId))
.matching(where(SaasTenant::getEnable).eq(true))
.list(TenantContext.class);
return sql.list(TenantContext.class);
}
}