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

View File

@ -14,7 +14,7 @@ public interface AfterOrderSqlChain extends ExecutableSql {
/** /**
* 执行并获取结果 * 执行并获取结果
* *
* @param <T> 泛型 * @param <T> 泛型
* @return 单一结果值 * @return 单一结果值
*/ */
<T> T one(); <T> T one();
@ -31,7 +31,7 @@ public interface AfterOrderSqlChain extends ExecutableSql {
/** /**
* 执行并获取多条结果以主表class为结果 * 执行并获取多条结果以主表class为结果
* *
* @param <T> 结果泛型 * @param <T> 结果泛型
* @return 结果列表 * @return 结果列表
*/ */
<T> List<T> list(); <T> List<T> list();
@ -44,5 +44,4 @@ public interface AfterOrderSqlChain extends ExecutableSql {
* @return 结果列表 * @return 结果列表
*/ */
<T> List<T> list(Class<T> clazz); <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(), 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", "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", "root",
"oI3WtMO8h%mSYARp" "Unicom#2018" // "oI3WtMO8h%mSYARp"
); );
// 准备待测试用例 // 准备待测试用例
List<TestCase<?>> cases = Arrays.asList( List<TestCase<?>> cases = Arrays.asList(
// jdbc测试
new JdbcTestCase(dataSource), new JdbcTestCase(dataSource),
// Mybatis测试
new MybatisTestCase(dataSource), new MybatisTestCase(dataSource),
new FluentSqlTestCase(dataSource) // FluentSQL测试
new FluentSqlTestCase(dataSource),
// 单表测试
new SingleTableTestCase()
); );
// 执行测试 // 执行测试
cases.forEach(TestCase::test); 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); Name anno = getClass().getAnnotation(Name.class);
assert anno != null; assert anno != null;
String name = anno.value(); String name = anno.value();
long current = System.currentTimeMillis(); print("=====准备执行任务《{0}》=====", name);
T result = null;
try { try {
result = run(); long current = System.currentTimeMillis();
T result = run();
print("【初次执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current); print("【初次执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current);
current = System.currentTimeMillis(); for (int i = 0; i < 10; i ++) {
result = run(); current = System.currentTimeMillis();
result = run();
print("【正常执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current);
}
printResult(result);
return result; return result;
} catch (Exception e) { } catch (Exception e) {
print("执行失败!{0}", e.getMessage()); print("执行失败!{0}", e.getMessage());
throw new RuntimeException(e); throw new RuntimeException(e);
} finally { } finally {
print("【正常执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current); print("=====完成执行任务《{0}》=====");
printResult(result);
} }
} }
} }

View File

@ -1,7 +1,8 @@
package group.flyfish.framework.cases; 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.operations.JdbcTemplateFluentSQLOperations;
import group.flyfish.fluent.utils.cache.CachedWrapper;
import group.flyfish.framework.TestCase; import group.flyfish.framework.TestCase;
import group.flyfish.framework.entity.SaasOrder; import group.flyfish.framework.entity.SaasOrder;
import group.flyfish.framework.entity.SaasPlan; import group.flyfish.framework.entity.SaasPlan;
@ -11,6 +12,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import static group.flyfish.fluent.chain.SQL.select; import static group.flyfish.fluent.chain.SQL.select;
import static group.flyfish.fluent.chain.select.SelectComposite.composite; 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") @TestCase.Name("使用fluent-sql")
public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> { public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
private AfterWhereSqlChain sql;
public FluentSqlTestCase(DataSource dataSource) { public FluentSqlTestCase(DataSource dataSource) {
super(dataSource); super(dataSource);
} }
@ -32,6 +36,18 @@ public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
public void initialize() throws Exception { public void initialize() throws Exception {
// 基于构造器自动绑定注册在实际应用中使用@Bean声明即可可参考下面的demo // 基于构造器自动绑定注册在实际应用中使用@Bean声明即可可参考下面的demo
new JdbcTemplateFluentSQLOperations(new JdbcTemplate(dataSource)); 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(); // FluentSqlDebugger.enable();
} }
@ -45,17 +61,6 @@ public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
@Override @Override
public List<TenantContext> run() throws Exception { public List<TenantContext> run() throws Exception {
// 一个平平无奇的查询 // 一个平平无奇的查询
return select( return sql.list(TenantContext.class);
// 查询租户全量字段
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);
} }
} }