java开发之Java ORM 框架推荐( 四 )

SELECT ((((SUM(`T0`.`amount` ) / SUM(`T0`.`quantity` ) )) * 100)) AS unit_amountFROM `orders` AS `T0`WHERE ((1 = 1) AND `T0`.`NO` IN ('202000001', '202000002', '202000003') )GROUP BY `T0`.`member_id`6 高级使用6.1 日志集成由于 ObjectiveSQL 无法决定应用系统使用哪一个日志框架,所以ObjectiveSQL 并未集成任何第三方日志框架,确认使用JDK 自身的日志框架,如果应用系统需要使用自身的日志框架,并在系统启动完成后注入ObjectiveSQL,请按下列方式集成(以Slf4j 为例) 。
6.1.1 LoggerFactory 扩展实现public class ObjLoggerFactoryImpl implements LoggerFactory {private class ObjLoggerImpl implements Logger {private final org.slf4j.Logger logger;public ObjLoggerImpl(org.slf4j.Logger logger) {this.logger = logger;}@Overridepublic void debug(long elapsedTime, String sql, Object[] params) {logger.debug(createLogContent(elapsedTime, sql, params));}@Overridepublic void info(long elapsedTime, String sql, Object[] params) {logger.info(createLogContent(elapsedTime, sql, params));}@Overridepublic void error(String message, Throwable throwable) {logger.error(message, throwable);}private String createLogContent(long elapsedTime, String sql, Object[] params) {String[] paramStrings = Arrays.stream(params).map(param -> String.valueOf(param)).toArray(String[]::new);String paramString = String.join(",", paramStrings);return String.format("[%dms] %s, with: [%s]",elapsedTime, sql, String.join(",",paramString.length() > 100 ? StringUtil.truncate(paramString, 99) : paramString));}}@Overridepublic Logger create(Class<?> clazz) {org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(clazz);return new ObjLoggerImpl(logger);}}6.1.1 普通应用程序注入方式public class Application {public static void main(String[] args) {Databases.installLoggerFactory(new ObjLoggerFactoryImpl());// others}}6.1.2 Spring Boot 应用程序注入方式@SpringBootApplication@EnableAutoConfigurationpublic class Application {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(Application.class);springApplication.addListeners(new ApplicationListener<ApplicationReadyEvent>() {@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {Databases.installLoggerFactory(new ObjLoggerFactoryImpl());}});springApplication.run(args);}}6.2 基于SQL 语句的对象缓存应用系统中对时间性不强的数据会进行数据缓存,通常会将数据缓存至redis 中,针对些特性,可以扩展ObjectiveSQL 的 SQLExecutor 接口轻易实现 。
6.1.1 SQLExecutor 扩展实现public class CacheableSQLExecutor<T> extends DefaultSQLExecutor<T> {private static final List<Class<? extends Serializable>> CACHEABLE_CLASSES =Arrays.asList(new Class[]{Member.class});private static final Integer CACHED_OBJECT_EXPIRED = 60;private static final String KEY_SHA = "SHA";private Jedis jedis = new Jedis("localhost", 6379);private MessageDigest messageDigest;public CacheableSQLExecutor() {try {messageDigest = MessageDigest.getInstance(KEY_SHA);} catch (NoSuchAlgorithmException e) {throw new IllegalArgumentException(e.getMessage(), e);}}@Overridepublic List<T> query(Connection connection, String sql,TableRowAdapter tableRowAdapter, Object... params)throws SQLException {Class<?> domainClass = tableRowAdapter.getDomainModelClass();if (CACHEABLE_CLASSES.contains(domainClass)) {if(!Serializable.class.isAssignableFrom(domainClass)) {throw new IllegalArgumentException(String.format("The %s cannot be serialized"));}messageDigest.update(sql.getBytes());String hashedSqlId = new BigInteger(messageDigest.digest()).toString(64);byte[] rawObjects = jedis.get(hashedSqlId.getBytes());if (rawObjects != null) {return (List<T>) SerializationUtils.deserialize(rawObjects);} else {List<T> objects = super.query(connection, sql, tableRowAdapter, params);byte[] encodedObjects = SerializationUtils.serialize(objects);SetParams expiredParams = SetParams.setParams().ex(CACHED_OBJECT_EXPIRED);jedis.set(hashedSqlId.getBytes(), encodedObjects, expiredParams);return objects;}}return super.query(connection, sql, tableRowAdapter, params);}}6.1.1 注入方式public class Application {public static void main(String[] args) {Databases.installSqlExecutor(new CacheableSQLExecutor());// others}}

Spring Boot 的注入方式去 LogFactory 的注入方式相同
6.3 ColumnTransition 扩展ColumnTransition 是ObjectiveSQL 对外提供的一种数据类型转的扩展接口,该接口的详细定义请参考:ColumnTransition.java,以日期形式为例,介绍ColumnTransition 的扩展方式 。
public class SqlDateTimeTransition<T> implements ColumnTransition<T> {@Overridepublic Object sinking(DatabaseMetaData databaseMetaData, T object,TableRowAdapter tableRowDescriptor,String fieldName, FieldValue fieldValue)throws SQLException {String databaseName = databaseMetaData.getDatabaseProductName();if (fieldValue != null && fieldValue.getValue() != null) {if (SQLite.equals(databaseName) || Oracle.equals(databaseName)) {return fieldValue;} else if (PostgreSQL.equals(databaseName)) {if (fieldValue.getValue() instanceof Timestamp) {return fieldValue.getValue();} else if (fieldValue.getValue() instanceof Long) {Instant value = https://www.isolves.com/it/cxkf/yy/JAVA/2021-12-13/Instant.ofEpochMilli((Long) fieldValue.getValue());return Timestamp.from(value);} else {return Timestamp.valueOf(String.valueOf(fieldValue.getValue()));}} else {return fieldValue;}}return null;}@Overridepublic Object rising(DatabaseMetaData databaseMetaData,ResultSetMetaData resultSetMetaData,T object, TableRowAdapter tableRowDescriptor,String columnName, Object columnValue) throws SQLException {String databaseName = databaseMetaData.getDatabaseProductName();try {if (columnValue != null) {if (SQLite.equals(databaseName)) {Instant value = Instant.ofEpochMilli(Long.valueOf(String.valueOf(columnValue)))return Timestamp.from(value);} else {return columnValue;}}} catch (DateTimeParseException ex) {String message = String.format("Invalid raw DataTime of '%s' from database: %s",columnName, columnValue);throw new IllegalArgumentException(message, ex);}return null;}}


推荐阅读