0

设置是这样的:

前端: GWT用于RequestFactory发送数据对象
后端:
Web 层:
GWT注入 EJB 的服务器端代码
EJB 层:
无状态会话 bean:

数据访问 bean ( DAB)=> 注入EntityManagerJPA操作,提供了实体的合并和检索方法
Facade bean ( FB) => 调用 DAB 的方法,是 EJB 和 web 层的接口

当一个实体对象(比如说MyEntity)在客户端修改后要保存时,流程是这样的:
1. 由客户端发起
2. 运行服务器端GWT代码并​​调用以下方法:
3.find()方法查找MyEntity使用FB.findMyEntity()哪些调用的实例,而DAB.findMyEntity()后者又用于EntityManager进行查找。该find()方法必须作为RequestFactoryflow in的一部分被调用GWT
4.save()导致FB.saveMyEntity()--> DAB.saveMyEntity()-->EntityManager.merge()并且改变的实体对象被持久化。

很明显,每个find()save()方法都在不同的JPA事务中运行,这是无效和糟糕的设计。

关于使用简单的查找和保存方法来保持外观 bean 接口:

  1. 处理这种情况的最佳设计是什么?- 最好在一个JPA事务中同时调用两个方法。
  2. 什么是替代品?有利有弊。

编辑:包括 和 的代码的简化FB示例DAB

门面豆(FB):

            @Stateless
            public class MyFacadeBean implements MyFacade{

                @EJB
                private DataAccessBean dab;

                @Override
                public void saveMyEntity(MyEntity entity) {
                    dab.saveMyEntity(entity);
                }

                @Override
                public void findMyEntity(int id) {
                    dab.saveMyEntity(id);
                }

            }

数据访问 bean ( DAB):

        @Stateless
        public class DataAccesseBean implements DataAccessBeanInterface{

            @PersistenceContext
            private EntityManager entityManager;

            @Override
            public void saveMyEntity(MyEntity entity) {
                entityManager.merge(entity);
            }

            @Override
            public void findMyEntity(int id) {
                entityManager.find(MyEntity.class,id);
            }

        }
4

1 回答 1

1

在您的 Web 层中,您有两个对无状态会话 bean的调用,因此这会导致两个事务。

有三个选项


  • UserTransaction在您的 web 层代码中使用 a :
final InitialContext ic = new InitialContext();
final UserTransaction ut = (UserTransaction) ic.lookup("UserTransaction");
ut.begin();
try {
    // find
    // set new value in entity
    // save
    ut.commit();
    System.out.println("committed");
} catch (Exception ex) {
    ut.rollback();
    System.out.println("rolled back");
}
  1. 通过这种方式,客户端控制事务。
  2. 如果有人忘记使用 a UserTransaction,这将导致多笔交易。
  3. 无需更改 EJB 端。

  • 在代表客户端调用两个DAB 方法的外观中添加一个方法:
public void findAndSave(int id, String newValue, ...) {
  // find
  // set new value in entity
  // save
}
  1. 通过这种方式EJB控制事务。
  2. 外观简化了接口(n调用减少到1
  3. 您可能还必须在 EJB 端提供其他方法。findAndSave靠近数据库。我建议使用与用例相对应的方法/名称,例如updatePersonAddress

  • 将外观转换为有状态会话 bean

来自Enterprise Java Beans,第 2 版的引述:

8.5.1。Bean 管理的事务中的事务传播

使用无状态会话 bean ...使用 UserTransaction 管理的事务必须在同一个方法中启动和完成...换句话说,UserTransaction 事务不能以一种方法启动并以另一种方法结束。
...
但是,对于有状态会话 bean,事务可以在一种方法中开始并在另一种方法中提交,因为有状态会话 bean 仅由一个客户端使用。这允许有状态会话 bean 将自己与跨多个不同客户端调用方法的事务相关联。

  1. 您必须使用有状态会话 bean
  2. 您必须使用bean 管理的事务
  3. 事务控制分布在客户端和 EJB上
  4. begin并且commit采用不同的方法。

经验告诉我,如果性能很重要,第一种方法不起作用。

所以我个人更喜欢第二种方法:对事务持续时间/范围的控制在 EJB 端;这同样适用于命中数据库的 SQL 语句的数量。客户端只调用服务/外观的一个方法(例如,对于单个 HTTP 请求)。

笔记:

  • 我已经使用带有 PostgreSql 的 JBoss 6.1.1 测试了这个设置。
  • 仔细检查事务数量的唯一可靠方法是观察 PostgreSql 日志文件。

有关的:

于 2013-08-10T23:37:45.810 回答