001/*
002 *  Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016
017package com.mybatisflex.spring.service.impl;
018
019import com.mybatisflex.core.BaseMapper;
020import com.mybatisflex.core.query.QueryTable;
021import com.mybatisflex.core.query.QueryWrapper;
022import com.mybatisflex.core.service.IService;
023import com.mybatisflex.core.table.TableInfo;
024import com.mybatisflex.core.table.TableInfoFactory;
025import com.mybatisflex.core.util.ClassUtil;
026import org.springframework.beans.factory.annotation.Autowired;
027
028/**
029 * <p>可缓存数据的 Service 实现类。
030 *
031 * <p>该实现类对缓存做了以下处理:
032 *
033 * <ul>
034 *     <li>重写 {@link #saveOrUpdate(Object)} 方法,分别调用 {@link #save(Object)} 和 {@link #updateById(Object)}
035 *     方法,避免缓存无法更新造成数据不一致。
036 *     <li>重写 {@link #query()} 方法,解决使用 {@link QueryWrapper#toSQL()} 作为缓存
037 *     的主键时,"SELECT * FROM" 后面没有表名的问题。
038 * </ul>
039 *
040 * @author 王帅
041 * @since 2023-05-30
042 */
043public class CacheableServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
044
045    @Autowired
046    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
047    protected M mapper;
048
049    /**
050     * {@inheritDoc}
051     */
052    @Override
053    public BaseMapper<T> getMapper() {
054        return mapper;
055    }
056
057    /**
058     * {@inheritDoc}
059     */
060    @Override
061    public boolean saveOrUpdate(T entity) {
062        TableInfo tableInfo = TableInfoFactory.ofEntityClass(entity.getClass());
063        Object[] pkArgs = tableInfo.buildPkSqlArgs(entity);
064        if (pkArgs.length == 0 || pkArgs[0] == null) {
065            return save(entity);
066        } else {
067            return updateById(entity);
068        }
069    }
070
071    /**
072     * <p>获取默认的 {@link QueryWrapper}。
073     *
074     * <p>使用 {@link QueryWrapper#create()} 构建默认查询条件的时候,
075     * 要使用 {@link QueryWrapper#from(String...)} 方法指定从哪个表
076     * 查询数据,不然使用 {@link QueryWrapper#toSQL()} 生成的
077     * SQL 语句就是 {@code "SELECT * FROM"},没有表名信息。
078     *
079     * <p>默认通过反射获取表名,建议重写,根据情况设置默认表名,以提升效率。
080     *
081     * <p>例如:
082     *
083     * <pre>{@code
084     * @Override
085     * public QueryWrapper query() {
086     *     return QueryWrapper.create().from(ACCOUNT);
087     * }
088     * }</pre>
089     *
090     * @return 默认的 {@link QueryWrapper}
091     */
092    @Override
093    public QueryWrapper query() {
094        Class<?> mapperClass = ClassUtil.getUsefulClass(getMapper().getClass());
095        TableInfo tableInfo = TableInfoFactory.ofMapperClass(mapperClass);
096        return QueryWrapper.create().from(new QueryTable(tableInfo.getSchema(), tableInfo.getTableName()));
097    }
098
099}