Spring MyBatis初始化解析及sql执行流程

Spring容器启动初始化

启动类上添加了@MapperScan注解,指定了Mapper文件所在包,容器会扫描到对应的包,并创建对应mapper的代理类。

MapperScan

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class) // 导入注册配置类
@Repeatable(MapperScans.class)
public @interface MapperScan {
	...
}

MapperScannerRegistrar实现了Spring的ImportBeanDefinitionRegistrar接口,容器初始化时会调用registerBeanDefinitions方法

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes
                .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        if (mapperScanAttrs != null) {
            // 注册BD
            registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
        }
    }

    void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
        builder.addPropertyValue("processPropertyPlaceHolders", true);

		// 解析各种配置 并注册到BeanDefinition
        Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
        ...
        registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

    }
	// beanName生成规则
    private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
        return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
    }
}

MapperScannerConfigurer

public class MapperScannerConfigurer 
		implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            processPropertyPlaceHolders();
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        if (StringUtils.hasText(lazyInitialization)) {
            scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
        }
        scanner.registerFilters();
        // 扫描对应bean
        scanner.scan(
                StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }
}

ClassPathBeanDefinitionScanner

执行doScan方法时,由于上边方法new的是ClassPathMapperScanner对象,所以执行ClassPathMapperScanner.doScan(),ClassPathMapperScanner是ClassPathBeanDefinitionScanner的子类

public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    this.doScan(basePackages);
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }
    return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}

ClassPathMapperScanner

processBeanDefinitions方法设置了Mapper的BeanClass为MapperFactoryBean,为FactoryBean,当容器创建对应bean时,会调用对应的getObject方法,将获取的对象放入容器中。

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    // 扫描指定目录并注册BD
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
    if (beanDefinitions.isEmpty()) {
        LOGGER.warn(() -> {
            return "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.";
        });
    } else {
        // 完成之后调用此方法
        this.processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
}

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (Iterator var3 = beanDefinitions.iterator(); var3.hasNext(); definition.setLazyInit(this.lazyInitialization)) {
        BeanDefinitionHolder holder = (BeanDefinitionHolder) var3.next();
        definition = (GenericBeanDefinition) holder.getBeanDefinition();
        String beanClassName = definition.getBeanClassName();
        LOGGER.debug(() -> {
            return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface";
        });
        
        // 设置构造方法参数为当前mapper的全类名传给MapperFactoryBean形成关联,用于生成代理对象
		// public MapperFactoryBean(Class<T> mapperInterface) {
		//	  this.mapperInterface = mapperInterface;
		// }
        definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
        // 此处重点 将BD的beanClass属性设置成了MapperFactoryBean
        // private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
        definition.setBeanClass(this.mapperFactoryBeanClass);
        
        definition.getPropertyValues().add("addToConfig", this.addToConfig);
        boolean explicitFactoryUsed = false;
        if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
            definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
            explicitFactoryUsed = true;
        } else if (this.sqlSessionFactory != null) {
            definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
            explicitFactoryUsed = true;
        }
        ...
    }
}

Bean初始化时会调用getObject方法

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    private Class<T> mapperInterface;
    private boolean addToConfig = true;

    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
    }
}

SqlSessionTemplate

public <T> T getMapper(Class<T> type) {
    return this.getConfiguration().getMapper(type, this);
}

MybatisConfiguration

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return this.mybatisMapperRegistry.getMapper(type, sqlSession);
}

MybatisMapperRegistry

创建了代理类MybatisMapperProxy对象

public T newInstance(SqlSession sqlSession) {
    MybatisMapperProxy<T> mapperProxy = new MybatisMapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
}

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory) this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

数据操作执行

当执行数据操作时,会调用代理类的invoke方法,然后查询数据,并返回相应的结果。

MybatisMapperProxy

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try{
        return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }
}

// MybatisMapperProxy.PlainMethodInvoker
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
    return this.mapperMethod.execute(sqlSession, args);
}

SqlSessionTemplate

使用了代理SqlSessionInterceptor

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    Assert.notNull(executorType, "Property 'executorType' is required");
    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor()); // 创建代理对象
}

由于设置了拦截器,所以会执行代理类中的方法
在Spring容器下 mybatis一级缓存是没有效果的 因为每次执行完 sqlSession都会被关闭

private class SqlSessionInterceptor implements InvocationHandler {
    private SqlSessionInterceptor() {
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);

        Object unwrapped;
        try {
            Object result = method.invoke(sqlSession, args);
            if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                sqlSession.commit(true); // 此处比较重要 二级缓存在commit之后会有一些相关操作 稍后分析
            }
            unwrapped = result;
        } catch (Throwable var11) {
            ...
        } finally {
       		// 此处说明了一个情况 在Spring容器下 mybatis一级缓存是没有效果的 因为每次执行完 sqlSession都会被关闭
       		// 但是此处有一个特殊情况, 就是Spring事务下, 使用ThreadLocal保证了多次数据操作使用同一个session
            if (sqlSession != null) {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }
        }
        return unwrapped;
    }
}

invoke方法会调用DefaultSqlSession中的查询方法

MybatisMapperMethod

public Object execute(SqlSession sqlSession, Object[] args) {
    // 针对CRUD执行不同操作
    Object result;
    Object param;
    switch (this.command.getType()) {
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;
        case UPDATE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
            break;
        case DELETE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
            break;
        case SELECT:
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else if (this.method.returnsCursor()) {
                result = this.executeForCursor(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                if (IPage.class.isAssignableFrom(this.method.getReturnType())) {
                    result = this.executeForIPage(sqlSession, args);
                } else {
                    result = sqlSession.selectOne(this.command.getName(), param);
                    if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                        result = Optional.ofNullable(result);
                    }
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + this.command.getName());
    }

    if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
        throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
    } else {
        return result;
    }
}

列表查询

private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    Object param = this.method.convertArgsToSqlCommandParam(args);
    List result;
    if (this.method.hasRowBounds()) {
        RowBounds rowBounds = this.method.extractRowBounds(args);
        result = sqlSession.selectList(this.command.getName(), param, rowBounds);
    } else {
        result = sqlSession.selectList(this.command.getName(), param);
    }

    if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
        return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
    } else {
        return result;
    }
}

SqlSessionTemplate


public <E> List<E> selectList(String statement, Object parameter) {
    return this.sqlSessionProxy.selectList(statement, parameter); // 使用固定的代理对象执行查询
}

sqlSession执行查询会先调用代理类的invoke方法

DefaultSqlSession

public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    List var5;
    try {
        MappedStatement ms = this.configuration.getMappedStatement(statement);
        var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception var9) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
    } finally {
        ErrorContext.instance().reset();
    }
    return var5;
}

CachingExecutor

当有二级缓存时,会先创建缓存key

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}


public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    Cache cache = ms.getCache(); // 获取命名空间内的缓存 二级缓存
    // 设置了二级缓存
    if (cache != null) { 
        this.flushCacheIfRequired(ms);
        if (ms.isUseCache() && resultHandler == null) { // 判断命名空间是否使用缓存
            this.ensureNoOutParams(ms, boundSql);
			// 获取对应的缓存结果
            List<E> list = (List)this.tcm.getObject(cache, key); // 从二级缓存获取数据
            if (list == null) {
            	// 如果为空 则执行一次缓存
                list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                // 将结果存入二级缓存 底层是一个HashMap
                this.tcm.putObject(cache, key, list);
            }
            return list;
        }
    }
	// 没有缓存 则直接查询并返回
    return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

BaseExecutor

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (this.closed) {
        throw new ExecutorException("Executor was closed.");
    } else {
        if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
            this.clearLocalCache();
        }

        List list;
        try {
            ++this.queryStack;
            list = resultHandler == null ? (List)this.localCache.getObject(key) : null; // 从session缓存中获取
            if (list != null) {
                this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
            } else {
            	// 从数据库中查询
                list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
            }
        } finally {
            --this.queryStack;
        }

        if (this.queryStack == 0) {
            Iterator i$ = this.deferredLoads.iterator();

            while(i$.hasNext()) {
                BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)i$.next();
                deferredLoad.load();
            }

            this.deferredLoads.clear();
            if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                this.clearLocalCache();
            }
        }
        return list;
    }
}

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

	// 执行查询 先清理然后再添加缓存
    List list;
    try {
        list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        this.localCache.removeObject(key);
    }

    this.localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
        this.localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}

SimpleExecutor

采用预处理方式,执行sql,并将执行结果返回

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;

    List var9;
    try {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        stmt = this.prepareStatement(handler, ms.getStatementLog());
        var9 = handler.query(stmt, resultHandler);
    } finally {
        this.closeStatement(stmt);
    }

    return var9;
}

更新操作

insert、delete操作本质调用的是update操作

DefaultSqlSession

public int insert(String statement, Object parameter) {
    return this.update(statement, parameter);
}

public int delete(String statement, Object parameter) {
    return this.update(statement, parameter);
}

CachingExecutor

在执行增删改操作时,如果使用的缓存,会先清理整个命名空间的缓存。

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    this.flushCacheIfRequired(ms);
    return this.delegate.update(ms, parameterObject);
}

private void flushCacheIfRequired(MappedStatement ms) {
    Cache cache = ms.getCache();
    if (cache != null && ms.isFlushCacheRequired()) {
        this.tcm.clear(cache);
    }
}

BaseExecutor

public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (this.closed) {
        throw new ExecutorException("Executor was closed.");
    } else {
    	// 清理session缓存
        this.clearLocalCache();
        return this.doUpdate(ms, parameter);
    }
}

SimpleExecutor

采用预处理方式执行sql

 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;

    int var6;
    try {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        stmt = this.prepareStatement(handler, ms.getStatementLog());
        var6 = handler.update(stmt);
    } finally {
        this.closeStatement(stmt);
    }
    return var6;
}

PreparedStatementHandler

执行sql语句 并返回影响行数

public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement)statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = this.boundSql.getParameterObject();
    KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
    return rows;
}

当数据库操作完成后,执行commit或rollback操作,如果使用了缓存,会进入CachingExecutor类中的相关方法


public class CachingExecutor implements Executor {

    public void commit(boolean required) throws SQLException {
        this.delegate.commit(required);
        this.tcm.commit();
    }

    public void rollback(boolean required) throws SQLException {
        try {
            this.delegate.rollback(required);
        } finally {
            if (required) {
                this.tcm.rollback();
            }

        }
    }
}

Commit

在执行commit操作时,会先清除本地HashMap中的缓存,然后将结果存入到二级缓存中,这样操作的意义在于,如果事务没有提交,会导致二级缓存出现脏数据

// org.apache.ibatis.cache.decorators.TransactionalCache#commit
public void commit() {
	// 调用Cache接口清除缓存
    if (this.clearOnCommit) {
        this.delegate.clear(); // 清除二级缓存
    }
	// 将结果保存至二级缓存中
    this.flushPendingEntries();
    // 清除本地数据
    this.reset();
}

// org.apache.ibatis.cache.decorators.TransactionalCache#flushPendingEntries
private void flushPendingEntries() {
    Iterator var1 = this.entriesToAddOnCommit.entrySet().iterator();
    while(var1.hasNext()) {
        Entry<Object, Object> entry = (Entry)var1.next();
        this.delegate.putObject(entry.getKey(), entry.getValue()); // 最终调用Cache接口中的方法
    }
    var1 = this.entriesMissedInCache.iterator();
    while(var1.hasNext()) {
        Object entry = var1.next();
        if (!this.entriesToAddOnCommit.containsKey(entry)) {
            this.delegate.putObject(entry, (Object)null); // 最终调用Cache接口中的方法
        }
    }
}

Rollback

// org.apache.ibatis.cache.TransactionalCacheManager#rollback
public void rollback() {
    Iterator var1 = this.transactionalCaches.values().iterator();
    while(var1.hasNext()) {
        TransactionalCache txCache = (TransactionalCache)var1.next();
        txCache.rollback();
    }
}

// org.apache.ibatis.cache.decorators.TransactionalCache#rollback
public void rollback() {
    this.unlockMissedEntries();
    this.reset();
}

 private void unlockMissedEntries() {
   Iterator var1 = this.entriesMissedInCache.iterator();
    while(var1.hasNext()) {
        Object entry = var1.next();
        try {
            this.delegate.removeObject(entry); // 调用Cache接口中的方法
        } catch (Exception var4) {
            log.warn("Unexpected exception while notifiying a rollback to the cache adapter.Consider upgrading your cache adapter to the latest version.  Cause: " + var4);
        }
    }
}

RedisCache

一般情况下,二级缓存使用分布式Redis缓存,实现了Cache接口,对数据进行Redis持久化操作,底层使用hash存储

public final class RedisCache implements Cache {
    private final ReadWriteLock readWriteLock = new DummyReadWriteLock();
    private String id;
    private static JedisPool pool;

    public RedisCache(String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        } else {
            this.id = id;
            RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();
            pool = new JedisPool(redisConfig, redisConfig.getHost(), redisConfig.getPort(), redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getPassword(), redisConfig.getDatabase(), redisConfig.getClientName());
        }
    }

    private Object execute(RedisCallback callback) {
        Jedis jedis = pool.getResource();

        Object var3;
        try {
            var3 = callback.doWithRedis(jedis);
        } finally {
            jedis.close();
        }

        return var3;
    }

    public String getId() {
        return this.id;
    }

    public int getSize() {
        return (Integer)this.execute(new RedisCallback() {
            public Object doWithRedis(Jedis jedis) {
                Map<byte[], byte[]> result = jedis.hgetAll(RedisCache.this.id.toString().getBytes());
                return result.size();
            }
        });
    }

    public void putObject(final Object key, final Object value) {
        this.execute(new RedisCallback() {
            public Object doWithRedis(Jedis jedis) {
                jedis.hset(RedisCache.this.id.toString().getBytes(), key.toString().getBytes(), SerializeUtil.serialize(value));
                return null;
            }
        });
    }

    public Object getObject(final Object key) {
        return this.execute(new RedisCallback() {
            public Object doWithRedis(Jedis jedis) {
                return SerializeUtil.unserialize(jedis.hget(RedisCache.this.id.toString().getBytes(), key.toString().getBytes()));
            }
        });
    }

    public Object removeObject(final Object key) {
        return this.execute(new RedisCallback() {
            public Object doWithRedis(Jedis jedis) {
                return jedis.hdel(RedisCache.this.id.toString(), new String[]{key.toString()});
            }
        });
    }

    public void clear() {
        this.execute(new RedisCallback() {
            public Object doWithRedis(Jedis jedis) {
                jedis.del(RedisCache.this.id.toString());
                return null;
            }
        });
    }

    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }

    public String toString() {
        return "Redis {" + this.id + "}";
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值