实体引擎的数据操纵机制

实体引擎的一个主要目标是尽可能提供一种通用的代码结构,来消除各模块中事务处理过程中的相近或相似的代码。这种抽象在于数据库数据操作逻辑的提取。它可以大大减少应用系统的开发费用和潜在的事务处理bug。
在Ofbiz的实体引擎中,将存储实体属性值的类结构设计成通用的数据结构,使用一个MAP对象来作为数据载体来存取实体的所有属性值。实体引擎和应用系统之间的接口体现在实体结构定义文件和SQL字段类型与Java数据类型映射关系定义中(以XML文件方式进行描述)。基于这个抽象层,使用实体引擎提供的API来处理实体持久化操作。

取代编写特定的代码,实体的定义是在entitymodel*.XML文件中完成的,并由实体引擎强制规定应用系统和数据源之间的访问规则。在实体文件entitymodel*.XML中定义了实体和实体的关系,包含一个相关联的数据库表和关系类型(one or many),以及关系的关键字值对。关系可以定义一个标识来区别实体关系中的其他关系。

SQL语句执行引擎

实体引擎中的一个重要组成部分就是SQL语句的执行引擎。在Ofbiz中,SQL语句执行引擎的中心是SQLProcessor类,每一个GenericDAO执行一个Add/Update/Delete操作时,都会创建一个SQLProcessor执行器,SQLProcessor执行器会从ConnectionFactory中取得一个数据库连接。

在上图中,SqlJDBCUtil描述了数据库类型与Java类型间的映射关系,以及建立表间关系或View的方法。TransactionUtil则提供了一系列事务管理的静态方法。

数据库连接是由一个数据库连接池来进行管理,如下图:

 

 

接口定义

我的理解,Ofbiz中的数据模型应是充血模型,在Domain Object中包含了业务逻辑和持久化,GenericDAO仅作为基础设施层,实现对业务对象的持久化的作用。

数据模型定义如下:

 

GenericPK类是模型的描述,它联系entitymodel.xml文件中所描述的模型转为应用中的类型定义。entitymodel.xml中的模型描述信息装载在ModelEntity类中。GenericValue则是模型对象的一个实例。

GenericHelperDAO是GenericHelper接口的一个实现,实现了DAO层功能。具体应用GenericDAO类来执行SQL。在GenericDAO类中引用了一个SQLPrococessor类来完成与DB的交互。

Delegator则是一个服务层代表。

实体引擎的过滤功能实现:由三个部分组成:EntityConditionValue、EntityOperator、EntityCondition。这些过滤类将在GenericDAO中被转化为相应的SQL语句执行。

主键生成策略

主键是通过SequenceUtil来生成的,它仅在GenericDelegator中被使用。实现机制是在内存中保存表的当前序列号,当创建新的ID时,依据当前序列通过计算得到下一条序列。当出现错误时,强制重新从表中查询出当前序列号保存在内存中,作为下一次计算的依据。  

算法如下:

private synchronized Long getNextSeqId(long staggerMax) {

            long stagger = 1;

            if (staggerMax > 1) {

                stagger = Math.round(Math.random() * staggerMax);

                if (stagger == 0) stagger = 1;

            }

 

            if ((curSeqId + stagger) <= maxSeqId) {

                Long retSeqId = Long.valueOf(curSeqId);

                curSeqId += stagger;

                return retSeqId;

            } else {

                fillBank(stagger);

                if ((curSeqId + stagger) <= maxSeqId) {

                    Long retSeqId = Long.valueOf(curSeqId);

                    curSeqId += stagger;

                    return retSeqId;

                } else {

                    Debug.logError("[SequenceUtil.SequenceBank.getNextSeqId] Fill bank failed, returning null", module);

                    return null;

                }

            }

        }

 

流程

实体引擎动作示意图:

 

每个特定的GenericHelper的配置信息都在entityengine.xml文件的datsource元素指定。

GenericDelegator是实体引擎服务中最主要的访问接入点。每个服务请求被分派到和实体对应的帮助类,服务被请求用来和这个实体的实体组通信。OFBiz实体模型默认的实体组XML文件可以在ofbiz/mmonapp/entitydef/entitygroup.xml.中找到。

GenericDelegator通过一个使用一个包含delegator名称的String类型的参数的工厂类方法产生(DelegatorFactory)。delegator名称用来在entityengine.xml文件中查找delegator标签,其中包含相应的数据源信息。每个delegator使用一个实体模型和一个实体模型加载器(entitymodelreader)和一个实体组加载器(entitygroupreader),来加载相关的实体信息。

 实体引擎的事务

最有用处的事务工厂类是org.ofbiz.core.entity.transaction.JNDIFactory类。这个类使用entityengine.xml中附加元素来定位JNDI中的UserTransaction和TransactionManager对象。
user-transaction-jndi和transaction-manager-jndi标签用来指定对象在JNDI中的名称以及要使用JNDI服务的名称。两个标签都有两个必须的属性:jndi-server-name和jndi-name。一个例子:UserTransaction对象的jndi-name值为java:comp/UserTransaction,TransactionManager对象的jndi-name值为java:comp/TransactionManager。

另一个事务工厂类是GeronimoTransactionFactory,它使用apache.geronimo的事务管理来实现。同时提供了一个TransactionFactory的工厂类来得到已存在的事务管理器和数据库连接。

事务的应用是放在TransactionUtil中来应用的(TransactionUtil中提供一系统的静态方法来实现事务管理)。在实体引擎中,TransactionUtil会被GenericDelegator中应用,它同时会被其他地方显示使用。

在TransactionUtil中使用ThreadLocal实现线程安全,并通过编程方式实现了事务管理能力。主要代码结构如下:

public static synchronized boolean begin(int timeout) throws GenericTransactionException { //事务开始

        UserTransaction ut = TransactionFactory.getUserTransaction(); //根据不同的实现得到不同的UserTransaction接口,这里有两个实现:GeronimoTransactionFactory和JNDIFactory两个。

        if (ut != null) {

            try {

                //检查当前线程是否绑定了事务

                int currentStatus = ut.getStatus();

                if (currentStatus == Status.STATUS_ACTIVE) {

                    Debug.logVerbose("[TransactionUtil.begin] active transaction in place, so no transaction begun", module);

                    return false;

                } else if (currentStatus == Status.STATUS_MARKED_ROLLBACK) {

                    Exception e = getTransactionBeginStack();

                    if (e != null) {

                        Debug.logWarning(e, "[TransactionUtil.begin] active transaction marked for rollback in place, so no transaction begun; this stack trace shows when the exception began: ", module);

                    } else {

                        Debug.logWarning("[TransactionUtil.begin] active transaction marked for rollback in place, so no transaction begun", module);

                    }

 

                    RollbackOnlyCause roc = getSetRollbackOnlyCause();

                    // do we have a cause? if so, throw special exception

                    if (roc != null && !roc.isEmpty()) {

                        throw new GenericTransactionException("The current transaction is marked for rollback, not beginning a new transaction and aborting current operation; the rollbackOnly was caused by: " + roc.getCauseMessage(), roc.getCauseThrowable());

                    } else {

                        return false;

                    }

                }

 

                // set the timeout for THIS transaction

                if (timeout > 0) {

                    ut.setTransactionTimeout(timeout);

                    Debug.logVerbose("[TransactionUtil.begin] set transaction timeout to : " + timeout + " seconds", module);

                }

 

                // begin the transaction开始事务

                ut.begin();

 

                // reset the timeout to the default

                if (timeout > 0) {

                    ut.setTransactionTimeout(0);

                }

                 …..

                 return true;

            } catch (NotSupportedException e) {

                 throw new GenericTransactionException("Not Supported error, could not begin transaction (probably a nesting problem)", e);

            } catch (SystemException e) {

                 throw new GenericTransactionException("System error, could not begin transaction", e);

            }

        } else {

            return false;

        }

    }

 

 

public static void commit() throws GenericTransactionException { //事务提交

        UserTransaction ut = TransactionFactory.getUserTransaction();

        if (ut != null) {

            try {

                int status = ut.getStatus();

                if (status != STATUS_NO_TRANSACTION && status != STATUS_COMMITTING && status != STATUS_COMMITTED && status != STATUS_ROLLING_BACK && status != STATUS_ROLLEDBACK) {

                    ut.commit();

                    ……

                } else {

                    Debug.logWarning("[TransactionUtil.commit] Not committing transaction, status is " + getStatusString(), module);

                }

            } catch (RollbackException e) {

                ….

            } catch (IllegalStateException e) {

                ….

            } catch (HeuristicMixedException e) {

                ….

            } catch (HeuristicRollbackException e) {

                ….

            } catch (SystemException e) {

                ….

            }

        } else {

            Debug.logInfo("[TransactionUtil.commit] UserTransaction is null, not commiting", module);

        }

    }

 

 

public static void rollback(Throwable causeThrowable) throws GenericTransactionException {  //事务回滚

        UserTransaction ut = TransactionFactory.getUserTransaction();

        if (ut != null) {

            try {

                int status = ut.getStatus();

                if (status != STATUS_NO_TRANSACTION) { //这是唯一的一个方法确定上下文中没有事务。

                    if (causeThrowable == null && Debug.infoOn()) {

                        Exception newE = new Exception("Stack Trace");

                    }

                     ……….

                    ut.rollback();

                } else {

                }

            } catch (IllegalStateException e) {

                     ……….

            } catch (SystemException e) {

                     ……….

            }

        } else {

            Debug.logInfo("[TransactionUtil.rollback] No UserTransaction, transaction not rolled back", module);

        }

    }

 

public static Transaction suspend() throws GenericTransactionException {   //事务挂起

        try {

            if (TransactionUtil.getStatus() != STATUS_NO_TRANSACTION) {

                TransactionManager txMgr = TransactionFactory.getTransactionManager();

                if (txMgr != null) {

                    pushTransactionBeginStackSave(clearTransactionBeginStack());

                    pushSetRollbackOnlyCauseSave(clearSetRollbackOnlyCause());

                    Transaction trans = txMgr.suspend();

                    pushSuspendedTransaction(trans);

                    return trans;

                } else {

                    return null;

                }

            } else {

                return null;

            }

        } catch (SystemException e) {

            throw new GenericTransactionException("System error, could not suspend transaction", e);

        }

    }

 

    public static void resume(Transaction parentTx) throws GenericTransactionException {  //事务恢复

        if (parentTx == null) return;

        try {

            TransactionManager txMgr = TransactionFactory.getTransactionManager();

            if (txMgr != null) {

                setTransactionBeginStack(popTransactionBeginStackSave());

                setSetRollbackOnlyCause(popSetRollbackOnlyCauseSave());

                txMgr.resume(parentTx);

                removeSuspendedTransaction(parentTx);

            }

        } catch (InvalidTransactionException e) {

            /* NOTE: uncomment this for Weblogic Application Server

            // this is a work-around for non-standard Weblogic functionality; for more information see: http://www.onjava.com/pub/a/onjava/2005/07/20/transactions.html?page=3

            if (parentTx instanceof weblogic.transaction.ClientTransactionManager) {

                // WebLogic 8 and above

                ((weblogic.transaction.ClientTransactionManager) parentTx).forceResume(transaction);

            } else if (parentTx instanceof weblogic.transaction.TransactionManager) {

                // WebLogic 7

                ((weblogic.transaction.TransactionManager) parentTx).forceResume(transaction);

            } else {

                throw new GenericTransactionException("System error, could not resume transaction", e);

            }

            */

            throw new GenericTransactionException("System error, could not resume transaction", e);

        } catch (SystemException e) {

            throw new GenericTransactionException("System error, could not resume transaction", e);

        }

    }

 

[注] Mysql事务隔离级别:

•   未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

•   提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别

•   可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读

•   串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

事务隔离定义可参见:java.sql.Connection中的定义

事务界定选择的考虑:
    1.    使用 JDBC API 进行事务界定:
       >  事务界定代码应嵌入在 DAO 类中
       >  DAO类调用者不能界定事务。
       >  事务范围局限于单个 JDBC 连接。
    2.    使用JTA进行事务界定
       >  事务用 JTA 界定,事务界定代码从 DAO 中分离出来。
       >  DAO类调用者负责界定事务。
       >  DAO 加入一个全局事务。
JDBC 事务并不总是适合复杂的企业应用程序,如果事务需要跨越多个 DAO 或者多个数据库,那么应该选择使用JTA界定。

实体引擎的访问

ofbiz中对实体的访问(数据库)是通过delegate对象来进行的,而delegate对象是GenericDelegator类的一个实例,包含有关实体操作的方法和属性。

    •  在JSP中使用

          <jsp:useBeanid="delegator"type="org.ofbiz.core.entity.GenericDelegator"scope="request"/>

    •   在severlet或event中使用

          GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");

    •   通过一个已知的数值对象获取delegator,方法为

          GenericDelegator delegator = entity.getDelegator();

    •   手工建立

          GenericDelegator delegator = GenericDelegator.getGenericDelegator("default")

 

转载于:https://www.cnblogs.com/jevo/archive/2013/03/13/2958505.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值