• 实体引擎的数据操纵机制


    实体引擎的一个主要目标是尽可能提供一种通用的代码结构,来消除各模块中事务处理过程中的相近或相似的代码。这种抽象在于数据库数据操作逻辑的提取。它可以大大减少应用系统的开发费用和潜在的事务处理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")

  • 相关阅读:
    manjaro 安装mysql
    Ubuntu安装Redis
    Ubuntu安装docker
    VirtualBox 安装 Ubuntu虚拟机 显卡驱动
    ubuntu 卸载软件
    Linux下环境变量设置的三种方法:
    error: open of glibc-devel-2.12-1.132.el6.i686.rpm failed: 没有那个文件或目录
    ip地址0.0.0.0与127.0.0.1的区别(转载)
    cmake的安装和卸载
    qmake 提示 Failure to open file:****
  • 原文地址:https://www.cnblogs.com/jevo/p/2958505.html
Copyright © 2020-2023  润新知