在Activiti中集成JPA(解决动态表单生成的大量数据)

标签: activiti 中集 jpa | 发表时间:2014-04-18 15:00 | 作者:
出处:http://www.kafeitu.me/

1. 为何集成JPA

在《 比较Activiti中三种不同的表单及其应用》一文中介绍了不同表单的特点以及表现形式,相信这是每个初学者都会面临表单类型的选择。

如果选择了使用 动态表单那么将面临一个比较“严峻”的问题——大数据量,我们知道动态表单的内容都保存在一张表中( ACT_HI_DETAIL),我们也清楚动态表单中每一个Field都会在该表中插入一条记录,假如一个流程共有20个字段,这个数据量大家可以计算一下,每天多少个流程实例,每个月、每年多少?

日积月累的大数据会影响系统的性能,尤其涉及到关联查询时影响更深,除了性能之外动态表单还有一个弊端那就是数据是以 的形式存储没有任何 数据结构可言,流程运行中生成的数据很难被用于分析、查询,如何破解嘞?

2. 如何集成JPA

Activiti除了核心的Engine之外对企业现有的技术、平台、架构都有所支持,对于业务实体的持久化当然也会有所支持,那就是EJB的标准之一)——JPA,引擎把JPA的API引入到了内部,使用JPA功能的时候只需要把 entityManagerFactory配置到引擎配置对象(参考: 谈谈Activiti的引擎与引擎配置对象)即可。

参考用户手册的JPA章节,介绍了引擎配置对象中的几个jpa有关的属性,如下:

  • jpaPersistenceUnitName: 使用持久化单元的名称(要确保该持久化单元在类路径下是可用的)。根据该规范,默认的路径是/META-INF/persistence.xml)。要么使用 jpaEntityManagerFactory 或者jpaPersistenceUnitName。
  • jpaEntityManagerFactory: 一个实现了javax.persistence.EntityManagerFactory的bean的引用。它将被用来加载实体并且刷新更新。要么使用jpaEntityManagerFactory 或者jpaPersistenceUnitName。
  • jpaHandleTransaction: 在被使用的EntityManager 实例上,该标记表示流程引擎是否需要开始和提交/回滚事物。当使用Java事物API(JTA)时,设置为false。
  • jpaCloseEntityManager: 该标记表示流程引擎是否应该关闭从 EntityManagerFactory获取的 EntityManager的实例。当EntityManager 是由容器管理的时候需要设置为false(例如 当使用并不是单一事物作用域的扩展持久化上下文的时候)。

2.1 配置持久化单元或者EntityManagerFactory

要在引擎中使用JPA需要提供EntityManagerFactory或者提供持久化单元名称(引擎会自动查找最终获取到EntityManagerFactory对象),在使用的时候可以根据自己的实际情况进行选择,在 kft-activiti-demo中使用了 jpaEntityManagerFactory属性注入EntityManagerFactory对象的方式。

2.2 Standalone模式的JPA配置

    
    
    

2.3 Spring(托管)模式的JPA配置

    
    
    

3. 实例分析

在最新版本(1.10)的 kft-activiti-demo中添加了JPA演示,大家可以从 Github上下载源码查看源码。

请假流程-JPA版本

3.1 相关说明

  • 流程定义文件: leave-jpa.bpmn
  • 实体文件: me.kafeitu.demo.activiti.entity.oa.LeaveJpaEntity
  • 实体管理器: me.kafeitu.demo.activiti.service.oa.leave.LeaveEntityManager

3.2 创建实体

在流程定义文件中定义了一个流程的 start类型监听器:


  

这个监听器的触发的时候会执行一个表达式,调用名称为 leaveEntityManager的Spring Bean对象的 newLeave方法,并且把引擎的 Execution对象传递过去,得到一个LeaveJpaEntity对象后设置到引擎的变量中(名称为 leave)。

下面是LeaveEntityManager.java的代码:

@Entity(name = "LEAVE_JPA")
public class LeaveJpaEntity implements Serializable {

    private Long id;
    private String processInstanceId;
    private String userId;
    private Date startTime;
    private Date endTime;
    private Date realityStartTime;
    private Date realityEndTime;
    private Date reportBackDate;
    private Date applyTime;
    private String leaveType;
    private String reason;

    /**
     * 部门领导是否同意
     */
    private String deptLeaderApproved;

    /**
     * HR是否同意
     */
    private String hrApproved;
    
    ...
}
@Service
public class LeaveEntityManager {

    @PersistenceContext
    private EntityManager entityManager;
    
    /* 把流程变量的值赋值给JPA实体对象并保存到数据库 */
    @Transactional
    public LeaveJpaEntity newLeave(DelegateExecution execution) {
        LeaveJpaEntity leave = new LeaveJpaEntity();
        leave.setProcessInstanceId(execution.getProcessInstanceId());
        leave.setUserId(execution.getVariable("applyUserId").toString());
        leave.setStartTime((Date) execution.getVariable("startTime"));
        leave.setEndTime((Date) execution.getVariable("endTime"));
        leave.setLeaveType(execution.getVariable("leaveType").toString());
        leave.setReason(execution.getVariable("reason").toString());
        leave.setApplyTime(new Date());
        entityManager.persist(leave);
        return leave;
    }

    public LeaveJpaEntity getLeave(Long id) {
        return entityManager.find(LeaveJpaEntity.class, id);
    }

}

当启动流程后查看表 LEAVE_JPA中的数据与表单填写的一致。

3.3 在流程中更改实体的值

部门领导或者 人事审批节点完成时需要把审批结果更新到LeaveJpaEntity属性中(即更新表LEAVE_JPA),所以在这两个任务上添加一个 complete类型的监听器,如下所示:


    
        
    



    
        
    

3.4 流程结束后删除表单数据

熟悉Activiti表的应该知道表单数据会保存在表 ACT_HI_DETAIL中,特性是字段 TYPE_字段的值为 FormProperty,我们只要根据流程实例ID过滤删除记录就可以清理掉已经结束流程的表单数据。

在最新版本的Demo中(1.10版本)添加了一个类用来执行SQL:

@Component
public class ActivitiDao {

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 流程完成后清理detail表中的表单类型数据
     * @param processInstanceId
     * @return
     */
    public int deleteFormPropertyByProcessInstanceId(String processInstanceId) {
        int i = entityManager.createNativeQuery("delete from act_hi_detail where proc_inst_id_ = ? and type_ = 'FormProperty' ")
                .setParameter(1, processInstanceId).executeUpdate();
        return i;
    }

}

流程中定义了一个流程级别的结束监听器 me.kafeitu.demo.activiti.service.oa.leave.LeaveProcessEndListener

@Service
@Transactional
public class LeaveProcessEndListener implements ExecutionListener {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    ActivitiDao activitiDao;

    @Override
    public void notify(DelegateExecution execution) throws Exception {
        String processInstanceId = execution.getProcessInstanceId();

        int i = activitiDao.deleteFormPropertyByProcessInstanceId(processInstanceId);
        logger.debug("清理了 {} 条历史表单数据", i);
    }
}

3.5 已知问题(未解决)

由于引擎的Bug导致数据不能完整删除

图中的三条数据因为是在销假任务完成后设置的,不知道是不是引擎的Bug导致插入这三个表单属性比调用流程结束监听器还晚(从引擎的日志中可以分析出来)导致这三条记录不能被删除,因为在删除的时候这三条数据还没有插入到数据库。

这个问题后面会继续跟踪,解决了会在这里更新!!!

转载自:

相关 [activiti 中集 jpa] 推荐:

在Activiti中集成JPA(解决动态表单生成的大量数据)

- - 咖啡兔
在《 比较Activiti中三种不同的表单及其应用》一文中介绍了不同表单的特点以及表现形式,相信这是每个初学者都会面临表单类型的选择. 如果选择了使用 动态表单那么将面临一个比较“严峻”的问题——大数据量,我们知道动态表单的内容都保存在一张表中( ACT_HI_DETAIL),我们也清楚动态表单中每一个Field都会在该表中插入一条记录,假如一个流程共有20个字段,这个数据量大家可以计算一下,每天多少个流程实例,每个月、每年多少.

JPA & Hibernate 注解

- - CSDN博客编程语言推荐文章
必须,name为可选,对应数据库中一的个表 . 可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息 . name:可选,表示表的名称.默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名 . catalog:可选,表示Catalog名称,默认为Catalog(""). .

使用 Spring Data JPA 简化 JPA 开发

- -
Spring Data JPA 让一切近乎完美. 通过前面的分析可以看出,Spring 对 JPA 的支持已经非常强大,开发者只需关心核心业务逻辑的实现代码,无需过多关注 EntityManager 的创建、事务处理等 JPA 相关的处理,这基本上也是作为一个开发框架而言所能做到的极限了. 然而,Spring 开发小组并没有止步,他们再接再厉,于最近推出了 Spring Data JPA 框架,主要针对的就是 Spring 唯一没有简化到的业务逻辑代码,至此,开发者连仅剩的实现持久层业务逻辑的工作都省了,唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成.

Activiti用户指南之Activiti的API

- - ITeye博客
 一、流程引擎的API和服务(services).      引擎的API是影响Activiti最常见的一种方法. 我们一开始最关注的中心是ProcessEngine,像之前描述的那样,流程引擎可以被多种方式创建. 从这个流程引擎里面,你能获得各个包含workflow/BPM方法的服务. 流程引擎和这些获得的服务是线程安全的.

Activiti学习笔记

- - 企业架构 - ITeye博客
第一个Activiti的HelloWorld. 获取核心ProcessEngine对象 2. 根据需求,获取对应的服务实例 3. 使用服务方法,做事情 * * @author Administrator * */ public class HelloWorld {. // 加载核心API ProcessEngine.

Activiti工作流demo

- - CSDN博客综合推荐文章
继上篇《 Activiti工作流的环境配置》.        前几篇对Activiti工作流进行了介绍,并讲解了其环境配置. 本篇将会用一个demo来展示Activiti工作流具体的体现,直接上干货.        以HelloWorld程序为例.       首先说一下业务流程,员工张三提交了一个申请,然后由部门经理李四审核,审核通过后再由总经理王五审核,通过则张三申请成功.

Activiti - 设置会签

- - 企业架构 - ITeye博客
前些天在群里聊工作流和Activiti,群里有人分享了自己的工作流引擎开源项目,大伙纷纷问这问那(比如为什么突然自己搞个process engine、有没有eclipse plugin、能不能绘制流程图等等). 现实生活中的工作流程,我们也经常碰到需要会签的情况,支持会签是很必要的. 正好有两个人问道:支持会签吗.

Spring Data JPA 简单介绍

- tangfl - BlogJava-首页技术区
考虑到公司应用中数据库访问的多样性和复杂性,目前正在开发UDSL(统一数据访问层),开发到一半的时候,偶遇SpringData工程. 于是就花了点时间了解SpringData,可能UDSL II期会基于SpringData做扩展. 介绍:针对关系型数据库,KV数据库,Document数据库,Graph数据库,Map-Reduce等一些主流数据库,采用统一技术进行访问,并且尽可能简化访问手段.

JPA 实现继承关系

- - ITeye博客
JPA支持继承关系,使开发者可以利用继承的思想建模.        有一个实体Person,他是一个抽象实体,他有两个子实体:Man,Woman.        先写Person类:. //@DiscriminatorColumn(name="tableName")可选. 注意,对于抽象父类,必须设置两个注释:.

spring data jpa简单实例

- - 编程语言 - ITeye博客
我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度.   在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA.   通常我们写持久层,都是先写一个接口,再写接口对应的实现类,在实现类中进行持久层的业务逻辑处理.