Activiti的持久化和缓存最终都是有DbSqlSession处理的,在此主要也是讲这个对象。类图如下。
public class DbSqlSession implements PersistenOperation, Session {
- protected SqlSession sqlSession;
- protected List<PersistentObject> insertedObjects = new ArrayList<PersistentObject>();
- protected Map<Class<?>, Map<String, CachedObject>> cachedObjects = new HashMap<Class<?>, Map<String, CachedObject>>();
- protected List<DeleteOperation> deletedObjects = new ArrayList<DeleteOperation>();
- }
首先是insert,这里它使用了一个List对插入对象进行缓存,在通过flush()方法,flush之后最终会使用sqlSession把数据鎚入数据源,sqlSesion是所有对象最终持久化的唯一入口。
delete的作法基本上和inert一样,deltet做多了一层封装DeleteOperation,使用这个对象,适配id进行删除。
重点是update,这里update要结合select一起使用。在DbSqlSession对象中,没有update方法,update要求先进行select查询对象,更新查询对象,最终flush()的适合,chched容器会检查最终状态是否和查询时的状态一致,如果不一致,才会进行持久化更新。也就是说,用户只需要查询出对象,使用对象的set方法,更新属性,这样子就会默认进行更新了。在实现的适合注意getPersistentState()的实现,也就是说,会使用到属性更新的属性,需要够着一个判断状态更新的对象让cache容器对比。
flush()的时候,cache容器会先清理掉insert对象和delete对象。
我们看看CachedObject对象的设计。
- public static class CachedObject {
- protected PersistentObject persistentObject;
- protected Object persistentObjectState;
- public CachedObject(PersistentObject persistentObject, boolean storeState) {
- this.persistentObject = persistentObject;
- if (storeState) {
- this.persistentObjectState = persistentObject.getPersistentState();
- }
- }
- public PersistentObject getPersistentObject() {
- return persistentObject;
- }
- public Object getPersistentObjectState() {
- return persistentObjectState;
- }
- }
这里可以看明白我们属性设置对比和最终持久。当查询的适合,用storeState = true 构造CachedObject, PersistentState会被保存在对象中。外部API通过select对象的引用更新属性,flush()的适合,会拿最终对象的PersistentState与select出来的对象进行对比,如果不一致,就update数据源记录。代码如下。
- public List<PersistentObject> getUpdatedObjects() {
- List<PersistentObject> updatedObjects = new ArrayList<PersistentObject>();
- for (Class<?> clazz : cachedObjects.keySet()) {
- Map<String, CachedObject> classCache = cachedObjects.get(clazz);
- for (CachedObject cachedObject : classCache.values()) {
- PersistentObject persistentObject = cachedObject.getPersistentObject();
- if (!deletedObjects.contains(persistentObject)) {
- Object originalState = cachedObject.getPersistentObjectState();
- if (!originalState.equals(persistentObject.getPersistentState())) {
- updatedObjects.add(persistentObject);
- } else {
- log.finest("loaded object '" + persistentObject + "' was not updated");
- }
- }
- }
- }
- return updatedObjects;
- }
到这里,我遇到了一个问题,如果我不使用对象属性更新,也想update数据源记录,显然activiti这一套实现机制是不支持的,那怎么办呢?我的解决办法如下。
- /**
- * 更新数据,对源码的扩展。
- * 一般的更新是直接通过Entity对象属性设置。此处暴露出一种直接更新对象的方法。
- *
- * @param persistentObject
- */
- public void update(PersistentObject persistentObject) {
- PersistentObject oldPersistentObject = selectById(persistentObject.getClass(), persistentObject.getId());
- //先put对象进缓存容器,再讲持久状态回滚,这样flush的时候,会检查到对象状态变化,进而更新对象。
- CachedObject cachedObject = cachePut(persistentObject, false);
- cachedObject.persistentObjectState = oldPersistentObject.getPersistentState();
- }
先用select,保证数据源中的记录已经缓存在cache容器中,跟着强制更新PersistentState。保证flush()的时候可以检查状态的一致性。
activiti依赖Mybatis,关于缓存机制,Mybatis还有自身的机制,有自己的一套缓存回收机制。activiti默认是不适用Mybatis的缓存的,activiti自身的缓存机制够简单,如果在自身command机制里面适用,性能很高,如果是比较复杂的业务场景,会在结合外部扩展适用的话,很可能就不够用了。所有个人认为可以考虑结合Mybatis的缓存机制,混合适用。