feat: 增加缓存机制,sql在生命周期内仅构建一次
This commit is contained in:
parent
b9a34446ae
commit
4f8384ee88
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
20
fluent-sql-core/src/main/java/group/flyfish/fluent/utils/cache/BoundObject.java
vendored
Normal file
20
fluent-sql-core/src/main/java/group/flyfish/fluent/utils/cache/BoundObject.java
vendored
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
23
fluent-sql-core/src/main/java/group/flyfish/fluent/utils/cache/CachedWrapper.java
vendored
Normal file
23
fluent-sql-core/src/main/java/group/flyfish/fluent/utils/cache/CachedWrapper.java
vendored
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user