数据持久化
activiti 使用了一种稍显特别的方式来持久化数据。
本文基于activiti 5.22.0
架构
activiti 采用了充血模型,大部分业务逻辑放在了对应的实体类 entity 中,但是也许是觉得实体类责任过重,所有实体类都有一个对应的管理类 manager 类持有和数据库交互的方法包括新增、删除和查询(没有修改,这个问题后面说)。因为相比查询和删除来说新增需要更多的业务逻辑,所以有些实体类自身仍持有新增方法。
manager 类
manager 类架构比较简单,所有的 manager 类继承了抽象类 AbstractManager,AbstractManager 实现了接口 Session,作为 Session 架构的一部分。
AbstractManager 定义了实例对象的新增删除和获取 DbSqlSession 等方法。
entity 类
所有实体类的顶级接口 PersistentObject 是数据持久化尤其是更新操作的关键。
public interface PersistentObject {
//activiti中所有实体表均为单主键
String getId();
//当实体类保存时,若无主键,则会调用id生成器创建一个
void setId(String id);
//获取实体状态,后文详解
Object getPersistentState();
}
除 PersistentObject 外,还有几个和持久化相关的接口。
HasRevision
public interface HasRevision {
void setRevision(int revision);
int getRevision();
int getRevisionNext();
}
乐观锁,提供给需要修改的表。
BulkDeleteable
标记用接口,标识该实体是否可以批量删除。
SessionFactory 架构
SessionFactory 为顶级接口,其中定义了 openSession 和 getSessionType 方法。
public interface SessionFactory {
//获取其管理的Session的class
Class<?> getSessionType();
//获取其管理的Session实例
Session openSession();
}
- DefaultHistoryManagerSessionFactory:管理 DefaultHistoryManager 默认历史管理类,之所以单独管理是为了方便自定义历史管理类并交给 DefaultHistoryManagerSessionFactory 管理。
- SpringEntityManagerSessionFactory、EntityManagerSessionFactory 管理 JPA 实体
- UserEntityManagerFactory、GroupEntityManagerFactory、MembershipEntityManagerFactory 分别管理用户管理类、组管理类、用户-组管理类,之所以分别管理也是为了方便拓展和自定义实现。
- GenericManagerFactory 管理除用户相关的管理类之外的管理类
- DbSqlSessionFactory 管理 DbSqlSession,非常重要的管理类。负责根据数据库不同选择不同的执行 SQL。
初始化
protected void init() {
...
initSessionFactories();
...
}
初始化操作同样是在 ProcessEngineConfigurationImpl 的 init 方法中(EntityManagerSessionFactory 在 jpa 初始化方法中初始化的)
protected void initSessionFactories() {
//开关属性
if (sessionFactories==null) {
sessionFactories = new HashMap<Class<?>, SessionFactory>();
//初始化DbSqlSessionFactory
if (dbSqlSessionFactory == null) {
dbSqlSessionFactory = new DbSqlSessionFactory();
}
dbSqlSessionFactory.setDatabaseType(databaseType);
dbSqlSessionFactory.setIdGenerator(idGenerator);
dbSqlSessionFactory.setSqlSessionFactory(sqlSessionFactory);
dbSqlSessionFactory.setDbIdentityUsed(isDbIdentityUsed);
dbSqlSessionFactory.setDbHistoryUsed(isDbHistoryUsed);
dbSqlSessionFactory.setDatabaseTablePrefix(databaseTablePrefix);
dbSqlSessionFactory.setTablePrefixIsSchema(tablePrefixIsSchema);
dbSqlSessionFactory.setDatabaseCatalog(databaseCatalog);
dbSqlSessionFactory.setDatabaseSchema(databaseSchema);
dbSqlSessionFactory.setBulkInsertEnabled(isBulkInsertEnabled, databaseType);
dbSqlSessionFactory.setMaxNrOfStatementsInBulkInsert(maxNrOfStatementsInBulkInsert);
addSessionFactory(dbSqlSessionFactory);
//初始化GenericManagerFactory,可以看到除了人员和历史之外的管理类都由GenericManagerFactory管理
addSessionFactory(new GenericManagerFactory(AttachmentEntityManager.class));
addSessionFactory(new GenericManagerFactory(CommentEntityManager.class));
addSessionFactory(new GenericManagerFactory(DeploymentEntityManager.class));
addSessionFactory(new GenericManagerFactory(ModelEntityManager.class));
addSessionFactory(new GenericManagerFactory(ExecutionEntityManager.class));
addSessionFactory(new GenericManagerFactory(HistoricActivityInstanceEntityManager.class));
addSessionFactory(new GenericManagerFactory(HistoricDetailEntityManager.class));
addSessionFactory(new GenericManagerFactory(HistoricProcessInstanceEntityManager.class));
addSessionFactory(new GenericManagerFactory(HistoricVariableInstanceEntityManager.class));
addSessionFactory(new GenericManagerFactory(HistoricTaskInstanceEntityManager.class));
addSessionFactory(new GenericManagerFactory(HistoricIdentityLinkEntityManager.class));
addSessionFactory(new GenericManagerFactory(IdentityInfoEntityManager.class));
addSessionFactory(new GenericManagerFactory(IdentityLinkEntityManager.class));
addSessionFactory(new GenericManagerFactory(JobEntityManager.class));
addSessionFactory(new GenericManagerFactory(ProcessDefinitionEntityManager.class));
addSessionFactory(new GenericManagerFactory(ProcessDefinitionInfoEntityManager.class));
addSessionFactory(new GenericManagerFactory(PropertyEntityManager.class));
addSessionFactory(new GenericManagerFactory(ResourceEntityManager.class));
addSessionFactory(new GenericManagerFactory(ByteArrayEntityManager.class));
addSessionFactory(new GenericManagerFactory(TableDataManager.class));
addSessionFactory(new GenericManagerFactory(TaskEntityManager.class));
addSessionFactory(new GenericManagerFactory(VariableInstanceEntityManager.class));
addSessionFactory(new GenericManagerFactory(EventSubscriptionEntityManager.class));
addSessionFactory(new GenericManagerFactory(EventLogEntryEntityManager.class));
//初始化DefaultHistoryManagerSessionFactory
addSessionFactory(new DefaultHistoryManagerSessionFactory());
//初始化人员管理相关的SessionFactory
addSessionFactory(new UserEntityManagerFactory());
addSessionFactory(new GroupEntityManagerFactory());
addSessionFactory(new MembershipEntityManagerFactory());
}
//若有,则初始化自定义的SessionFactory
if (customSessionFactories!=null) {
for (SessionFactory sessionFactory: customSessionFactories) {
addSessionFactory(sessionFactory);
}
}
}
默认初始化操作除了 DbSqlSessionFactory 外均只是创建了对应的类并添加到 sessionFactories 属性中,而 DbSqlSessionFactory 初始化时设置的属性有
//数据库类型
dbSqlSessionFactory.setDatabaseType(databaseType);
//id生成器
dbSqlSessionFactory.setIdGenerator(idGenerator);
//SqlSessionFactory
dbSqlSessionFactory.setSqlSessionFactory(sqlSessionFactory);
//是否使用群组和用户表
dbSqlSessionFactory.setDbIdentityUsed(isDbIdentityUsed);
//是否使用历史表
dbSqlSessionFactory.setDbHistoryUsed(isDbHistoryUsed);
//表名前缀
dbSqlSessionFactory.setDatabaseTablePrefix(databaseTablePrefix);
//表名前缀是否为模式名
dbSqlSessionFactory.setTablePrefixIsSchema(tablePrefixIsSchema);
//数据库目录
dbSqlSessionFactory.setDatabaseCatalog(databaseCatalog);
//数据库模式
dbSqlSessionFactory.setDatabaseSchema(databaseSchema);
//能否批量插入
dbSqlSessionFactory.setBulkInsertEnabled(isBulkInsertEnabled, databaseType);
//单次插入的最大数量
dbSqlSessionFactory.setMaxNrOfStatementsInBulkInsert(maxNrOfStatementsInBulkInsert);
这个地方的 表名前缀、表名前缀是否为模式名、数据库目录、数据库模式 均只用于更新创建删除数据库表结构,真正用于执行 sql 时的配置是在 sqlSessionFactory 初始化时配置的
具体实现
GenericManagerFactory 初始化时属性中存储了对应 Session 的 Class,openSession 时使用反射的方式获取对应的管理类实例。
其他除了 DbsqlSessionFactory 和 EntityManagerSessionFactory 外均直接使用 new 关键字创建对应 session 实例。EntityManagerSessionFactory 涉及 jpa 此处不做介绍,DbsqlSessionFactory 在后面详细介绍。
Session 架构
Session 均由对应的 SessionFactory 创建出来,且均实现了 Session 接口。
Session 接口中定义了 flush 和 close 两个方法
public interface Session {
void flush();
void close();
}
除了 DbsqlSession 和 EntityManagerSessionImpl 外其他 Session 的 flush 和 close 是空实现的
命令模式及责任链
此处不会详细讲,只会介绍一下涉及数据持久化的信息。
acticiti 中所有获取 Session 均会通过 CommandContext(具体命令类与命令实现者解耦),因此 CommandContext 中存储了该次操作中所有涉及到的 Session,而数据库交互只会通过 Session 来交互。
@SuppressWarnings({"unchecked"})
//所有获取session均会使用命令上下文的getSession方法
public <T> T getSession(Class<T> sessionClass) {
//若该Session曾经获得过,则直接使用,否则获取Session
Session session = sessions.get(sessionClass);
if (session == null) {
SessionFactory sessionFactory = sessionFactories.get(sessionClass);
if (sessionFactory==null) {
throw new ActivitiException("no session factory configured for "+sessionClass.getName());
}
//获取Session
session = sessionFactory.openSession();
//将其存入属性中
sessions.put(sessionClass, session);
}
return (T) session;
}
在命令上下文拦截器中在调用结束时,若命令上下文为非重用的,则会关闭命令上下文。
public <T> T execute(CommandConfig config, Command<T> command) {
CommandContext context = Context.getCommandContext();
//是否重用命令上下文
boolean contextReused = false;
// We need to check the exception, because the transaction can be in a rollback state,
// and some other command is being fired to compensate (eg. decrementing job retries)
//若无命令上下文或...则创建新命令上下文
if (!config.isContextReusePossible() || context == null || context.getException() != null) {
context = commandContextFactory.createCommandContext(command);
}
else {
//将该拦截器标为重用命令上下文
log.debug("Valid context found. Reusing it for the current command '{}'", command.getClass().getCanonicalName());
contextReused = true;
}
try {
// Push on stack
Context.setCommandContext(context);
Context.setProcessEngineConfiguration(processEngineConfiguration);
return next.execute(config, command);
} catch (Exception e) {
context.exception(e);
} finally {
try {
//若命令上下文非被重用,关闭命令上下文
if (!contextReused) {
context.close();
}
} finally {
// Pop from stack
Context.removeCommandContext();
Context.removeProcessEngineConfiguration();
Context.removeBpmnOverrideContext();
}
}
return null;
}
关闭命令上下文的实现为:
public void close() {
...
try {
...
//若无异常
if (exception == null) {
flushSessions();
}
...
} catch (Throwable exception) {
...
} finally {
closeSessions();
}
...
}
在一次请求正常结束后,CommandContext 会调用所有涉及到的 Session 的 flush 方法。
无论该次请求是否正常结束,CommandContext 会调用所有涉及到的 Session 的 close 方法。
DbSqlSessionFactory 与 DbSqlSession
DbSqlSessionFactory 除了负责创建 DbSqlSession 外,还负责屏蔽不同数据库之间的语法差异。其持有 SqlSessionFactory 以及所有数据库相关的配置项。
DbSqlSessionFactory 初始化
SqlSessionFactory 在 Factory 初始化时被 set 到了 DbSqlSessionFactory 中,而 SqlSessionFactory 的初始化在方法 initSqlSessionFactory 中。
protected void initSqlSessionFactory() {
//开关属性
if (sqlSessionFactory==null) {
InputStream inputStream = null;
try {
inputStream = getMyBatisXmlConfigurationSteam();
// update the jdbc parameters to the configured ones...
Environment environment = new Environment("default", transactionFactory, dataSource);
Reader reader = new InputStreamReader(inputStream);
Properties properties = new Properties();
//指定数据库表名前缀
properties.put("prefix", databaseTablePrefix);
String wildcardEscapeClause = "";
//指定转义符
if ((databaseWildcardEscapeCharacter != null) && (databaseWildcardEscapeCharacter.length() != 0)) {
wildcardEscapeClause = " escape '" + databaseWildcardEscapeCharacter + "'";
}
properties.put("wildcardEscapeClause", wildcardEscapeClause);
//根据数据库类型不同,设置不同sql方言
if(databaseType != null) {
properties.put("limitBefore" , DbSqlSessionFactory.databaseSpecificLimitBeforeStatements.get(databaseType));
properties.put("limitAfter" , DbSqlSessionFactory.databaseSpecificLimitAfterStatements.get(databaseType));
properties.put("limitBetween" , DbSqlSessionFactory.databaseSpecificLimitBetweenStatements.get(databaseType));
properties.put("limitOuterJoinBetween" , DbSqlSessionFactory.databaseOuterJoinLimitBetweenStatements.get(databaseType));
properties.put("orderBy" , DbSqlSessionFactory.databaseSpecificOrderByStatements.get(databaseType));
properties.put("limitBeforeNativeQuery" , ObjectUtils.toString(DbSqlSessionFactory.databaseSpecificLimitBeforeNativeQueryStatements.get(databaseType)));
}
Configuration configuration = initMybatisConfiguration(environment, reader, properties);
sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
} catch (Exception e) {
throw new ActivitiException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e);
} finally {
IoUtil.closeSilently(inputStream);
}
}
}
这里有个非常关键的操作就是 根据数据库类型不同,为某些操作拼接不同sql,这里是屏蔽数据库差异的关键之一。此外我们也可以看到数据库表名前缀是怎么起作用的。
DbSqlSession 创建
不同于其他 Session,DbSqlSession 需要获取 DbSqlSessionFactory 中的众多配置项,此外还需要创建出 SqlSession。
public DbSqlSession(DbSqlSessionFactory dbSqlSessionFactory) {
this.dbSqlSessionFactory = dbSqlSessionFactory;
this.sqlSession = dbSqlSessionFactory
.getSqlSessionFactory()
.openSession();
}
在 DbSqlSession 创建时,它持有了 DbSqlSessionFactory 方便获取其中的配置项,同时使用 DbSqlSessionFactory 中的 SqlSessionFactory 创建出 SqlSession。
这里说明一下 DbSqlSessionFactory、DbSqlSession、SqlSessionFactory、SqlSession 之间的关系
DbSqlSessionFactory、DbSqlSession 是 activiti 的类。SqlSessionFactory、SqlSession是属于 mybatis 的类,activiti 对其作了一层包装方便实现包括数据库差异屏蔽及实体类操作。SqlSession 由 SqlSessionFactory 创建。DbSqlSession 由 DbSqlSessionFactory 创建且持有 DbSqlSessionFactory 的引用,同时持有 SqlSession 用于数据库交互。DbSqlSessionFactory 持有 SqlSessionFactory 用于创建 SqlSession 。
屏蔽数据库差异
activiti 通过两种方式来屏蔽数据库之间的差异,第一种为插入部分方言 sql 语法,第二种为使用专用方言sql。
插入部分方言 sql 语法
//分页查询前
public static final Map<String, String> databaseSpecificLimitBeforeStatements = new HashMap<String, String>();
//分页查询后
public static final Map<String, String> databaseSpecificLimitAfterStatements = new HashMap<String, String>();
//分页查询间
public static final Map<String, String> databaseSpecificLimitBetweenStatements = new HashMap<String, String>();
//排序
public static final Map<String, String> databaseSpecificOrderByStatements = new HashMap<String, String>();
//分页外连接字段间
public static final Map<String, String> databaseOuterJoinLimitBetweenStatements = new HashMap<String, String>();
//原生查询分页查询前
public static final Map<String, String> databaseSpecificLimitBeforeNativeQueryStatements = new HashMap<String, String>();
在 DbSqlSessionFactory 静态代码块中初始化了这六个特殊语法的 Map,其中每个 Map 的 key 为数据库类型,value 为 sql 方言片段。
在 SqlSession 初始化时,对应数据库的方言片段会被设置到 SqlSession 中作为变量。
以 mysql 分页查询为例
在静态代码块中 mysql 的方言片段被初始化到 databaseSpecificLimitAfterStatements中
... databaseSpecificLimitAfterStatements.put("mysql", "LIMIT #{maxResults} OFFSET #{firstResult}"); ...
在 SqlSession 初始化时,mysql 对应的的分页查询 sql 片段会被设置到 SqlSession 中作为变量。
... properties.put("limitAfter",DbSqlSessionFactory.databaseSpecificLimitAfterStatements.get(databaseType)); Configuration configuration = initMybatisConfiguration(environment, reader, properties); sqlSessionFactory = new DefaultSqlSessionFactory(configuration); ...
执行 sql 时,对应SQL中的${}字段会被替换为对应值
<select id="selectTaskByQueryCriteria" parameterType="org.activiti.engine.impl.TaskQueryImpl" resultMap="taskResultMap"> ${limitBefore} select distinct RES.* ${limitBetween} <include refid="selectTaskByQueryCriteriaSql"/> ${orderBy} ${limitAfter} </select>
使用专用方言 sql
当使用第一种方案仍无法满足要求时,会使用该数据库的专用 sql。
protected static final Map<String, Map<String, String>> databaseSpecificStatements = new HashMap<String, Map<String,String>>();
在 DbSqlSessionFactory 静态代码块中初始化了专用 sql 的 map,其为两层 map 结构,外层 key 为数据库类型,内层 key 为通用 sql 的 id,value 为专用 sql 的 id。
public void setDatabaseType(String databaseType) {
this.databaseType = databaseType;
this.statementMappings = databaseSpecificStatements.get(databaseType);
}
DbSqlSessionFactory 设置数据库类型时会根据数据库类型取出该数据库的专用 sql 的映射关系存入 statementMappings 属性中。
public String mapStatement(String statement) {
if (statementMappings==null) {
return statement;
}
String mappedStatement = statementMappings.get(statement);
return (mappedStatement!=null ? mappedStatement : statement);
}
每次指定 sql 前都会调用 mapStatement 方法使用通用 sql 的 id 获取专用 sql 的 id,若有,则调用专用 sql。
数据的增删改
如果在 activiti 内打断点就会发现 manage 类的新增和删除操作执行后数据库内字段值并未发生变化,且会发现并没有修改方法,这是因为 activiti 实现了一套比较特殊的持久化方式。在 DbSqlSession 中缓存了在该次提交中新增、删除及可能更新的实体,并在执行 flush 方法时进行数据库交互。(在 close 方法为关闭 SqlSession)
public void flush() {
List<DeleteOperation> removedOperations = removeUnnecessaryOperations();
flushDeserializedObjects();
List<PersistentObject> updatedObjects = getUpdatedObjects();
...日志
flushInserts();
flushUpdates(updatedObjects);
flushDeletes(removedOperations);
}
DbSqlSession 中有这三个属性是持久化的关键。
//所有insert方法放入的对象
protected Map<Class<? extends PersistentObject>, List<PersistentObject>> insertedObjects = new HashMap<Class<? extends PersistentObject>, List<PersistentObject>>();
//缓存的实体
protected Map<Class<?>, Map<String, CachedObject>> cachedObjects = new HashMap<Class<?>, Map<String,CachedObject>>();
//将要执行的删除操作
protected List<DeleteOperation> deleteOperations = new ArrayList<DeleteOperation>();
insertedObjects 的新增
public void insert(PersistentObject persistentObject) {
//若未设置id,使用配置的id生成器生成一个id
if (persistentObject.getId()==null) {
String id = dbSqlSessionFactory.getIdGenerator().getNextId();
persistentObject.setId(id);
}
//将该实体放到insertedObjects中
Class<? extends PersistentObject> clazz = persistentObject.getClass();
if (!insertedObjects.containsKey(clazz)) {
insertedObjects.put(clazz, new ArrayList<PersistentObject>());
}
insertedObjects.get(clazz).add(persistentObject);
//置入缓存
cachePut(persistentObject, false);
}
所有的实体类及管理类的新增方法并不会真正的操作数据库,而是维护了DbSqlSession 中的 insertedObjects 属性,其中 insertedObjects 的 key 为实体的 Class,value 为实体本身。
deleteOperations 的新增
deleteOperations 内存放的是一个内部类,其实现的接口为 DeleteOperation
public interface DeleteOperation {
/**
* @return The persistent object class that is being deleted.
* Null in case there are multiple objects of different types!
*/
// 返回被删除的实体的类型,若为多个不同类型的实体,则返回 null
Class<? extends PersistentObject> getPersistentObjectClass();
//要删除删除的实体和 other 是否为同一实体,只有 CheckedDeleteOperation 中有具体实现
boolean sameIdentity(PersistentObject other);
//清除缓存,只有 CheckedDeleteOperation 中有具体实现
void clearCache();
void execute();
}
具体实现有三个,但只有 BulkDeleteOperation 和 CheckedDeleteOperation 有用。
其中按照 id 删除会使用 CheckedDeleteOperation,按条件删除会调用 BulkDeleteOperation。
public void delete(String statement, Object parameter) {
deleteOperations.add(new BulkDeleteOperation(statement, parameter));
}
public void delete(PersistentObject persistentObject) {
//若重复删除
for (DeleteOperation deleteOperation: deleteOperations) {
if (deleteOperation.sameIdentity(persistentObject)) {
log.debug("skipping redundant delete: {}", persistentObject);
return; // Skip this delete. It was already added.
}
}
deleteOperations.add(new CheckedDeleteOperation(persistentObject));
}
cachedObjects 的维护
protected CachedObject cachePut(PersistentObject persistentObject, boolean storeState) {
Map<String, CachedObject> classCache = cachedObjects.get(persistentObject.getClass());
if (classCache==null) {
classCache = new HashMap<String, CachedObject>();
cachedObjects.put(persistentObject.getClass(), classCache);
}
CachedObject cachedObject = new CachedObject(persistentObject, storeState);
classCache.put(persistentObject.getId(), cachedObject);
return cachedObject;
}
通过 cachePut 方法新增,所有的新增、修改、查询的实体均会存入缓存。
其中新增和修改的 storeState 为 false,查询为 true;
public CachedObject(PersistentObject persistentObject, boolean storeState) {
//实体本身
this.persistentObject = persistentObject;
if (storeState) {
//实体查询出来的时候的状态
this.persistentObjectState = persistentObject.getPersistentState();
}
}
也就是说若为查询出的实体,会将实体查询出时的状态存入缓存中。
具体查询过程在查询处介绍。
移除多余操作
removeUnnecessaryOperations 方法
因为此处缓存的实体用于判断该实体是否被更新,因此新增和删除的实体要在缓存中删除。
/**
* Clears all deleted and inserted objects from the cache,
* and removes inserts and deletes that cancel each other.
*/
//这个方法的返回值中只有在本次提交中新增且删除的删除动作,用来触发删除事件,虽然最后好像也没有触发什么事件
protected List<DeleteOperation> removeUnnecessaryOperations() {
List<DeleteOperation> removedDeleteOperations = new ArrayList<DeleteOperation>();
//遍历被删除的对象
for (Iterator<DeleteOperation> deleteIterator = deleteOperations.iterator(); deleteIterator.hasNext();) {
DeleteOperation deleteOperation = deleteIterator.next();
Class<? extends PersistentObject> deletedPersistentObjectClass = deleteOperation.getPersistentObjectClass();
List<PersistentObject> insertedObjectsOfSameClass = insertedObjects.get(deletedPersistentObjectClass);
if (insertedObjectsOfSameClass != null && insertedObjectsOfSameClass.size() > 0) {
for (Iterator<PersistentObject> insertIterator = insertedObjectsOfSameClass.iterator(); insertIterator.hasNext();) {
PersistentObject insertedObject = insertIterator.next();
// 如果被删除的实体是本次提交中新增的
if (deleteOperation.sameIdentity(insertedObject)) {
// remove the insert and the delete, they cancel each other
// 将其在新增和删除中都移除,因为这两个操作互相抵消了
insertIterator.remove();
deleteIterator.remove();
// add removed operations to be able to fire events
// 添加删除动作用于触发事件
removedDeleteOperations.add( deleteOperation);
}
}
// 如果该实体的新增全部被移除,将其在新增中移除
if (insertedObjects.get(deletedPersistentObjectClass).size() == 0) {
insertedObjects.remove(deletedPersistentObjectClass);
}
}
// in any case, remove the deleted object from the cache
// 将被删除的实体在缓存中删除
deleteOperation.clearCache();
}
for (Class<? extends PersistentObject> persistentObjectClass : insertedObjects.keySet()) {
for (PersistentObject insertedObject : insertedObjects.get(persistentObjectClass)) {
// 将新增的实体在缓存中删除
cacheRemove(insertedObject.getClass(), insertedObject.getId());
}
}
return removedDeleteOperations;
}
获取在本次提交中发生更新的实体
getUpdatedObjects 方法
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 (!isPersistentObjectDeleted(persistentObject)) {
//获取实体初始状态,若为新增和修改,此处为空,否则为查询出时的状态
Object originalState = cachedObject.getPersistentObjectState();
//若实体与查询出来的时候的状态不同,则说明该实体被修改
if (persistentObject.getPersistentState() != null &&
!persistentObject.getPersistentState().equals(originalState)) {
updatedObjects.add(persistentObject);
} else {
log.trace("loaded object '{}' was not updated", persistentObject);
}
}
}
}
return updatedObjects;
}