/* * Copyright 2009-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.cache.decorators; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import org.apache.ibatis.cache.Cache; /** * The 2nd level cache transactional buffer. * * This class holds all cache entries that are to be added to the 2nd level cache during a Session. * Entries are sent to the cache when commit is called or discarded if the Session is rolled back. * Blocking cache support has been added. Therefore any get() that returns a cache miss * will be followed by a put() so any lock associated with the key can be released. * * @author Clinton Begin * @author Eduardo Macarron */ /** * 事务缓存 * 一次性存入多个缓存,移除多个缓存 * */ public class TransactionalCache implements Cache { private Cache delegate; //commit时要不要清缓存 private boolean clearOnCommit; //commit时要添加的元素 private Map<Object, Object> entriesToAddOnCommit; private Set<Object> entriesMissedInCache; public TransactionalCache(Cache delegate) { this.delegate = delegate; //默认commit时不清缓存 this.clearOnCommit = false; this.entriesToAddOnCommit = new HashMap<Object, Object>(); this.entriesMissedInCache = new HashSet<Object>(); } @Override public String getId() { return delegate.getId(); } @Override public int getSize() { return delegate.getSize(); } @Override public Object getObject(Object key) { // issue #116 Object object = delegate.getObject(key); if (object == null) { entriesMissedInCache.add(key); } // issue #146 if (clearOnCommit) { return null; } else { return object; } } @Override public ReadWriteLock getReadWriteLock() { return null; } @Override public void putObject(Object key, Object object) { entriesToAddOnCommit.put(key, object); } @Override public Object removeObject(Object key) { return null; } @Override public void clear() { clearOnCommit = true; entriesToAddOnCommit.clear(); } //多了commit方法,提供事务功能 public void commit() { if (clearOnCommit) { delegate.clear(); } flushPendingEntries(); reset(); } public void rollback() { unlockMissedEntries(); reset(); } private void reset() { clearOnCommit = false; entriesToAddOnCommit.clear(); entriesMissedInCache.clear(); } private void flushPendingEntries() { for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) { delegate.putObject(entry.getKey(), entry.getValue()); } for (Object entry : entriesMissedInCache) { if (!entriesToAddOnCommit.containsKey(entry)) { delegate.putObject(entry, null); } } } private void unlockMissedEntries() { for (Object entry : entriesMissedInCache) { delegate.putObject(entry, null); } } }