无状态会话Bean - 停止多个呼叫

0 jpa session-bean ejb-3.1

所以我从BalusC的这篇文章中读到了如何阻止无状态会话bean在被JSF访问时不断地颠簸数据存储(例如DB)(这可能会/将进行多次调用)所以我已经实现了我的代码我想这是符合BalusC所发布的精神(以及我见过的关于这个问题的"最佳实践"的其他论坛帖子).

我的无状态会话bean看起来像这样:

@Stateless
@Named("productsService")
public class ProductService {

    private static boolean changed = true;

    private List<Product> products;

    private long count;

    @PersistenceContext(name = "myPU")
    private EntityManager em;

    @Inject
    private Product product;

    public ProductService() {
    }

    private void productRecordsFromDB() {
        products = em.createNamedQuery("Product.getAll", Product.class).getResultList();
        Object o = em.createNamedQuery("Product.getCount", Product.class).getSingleResult();
        count = ((Long) o).longValue();
    }

    public void addProduct() {
        synchronized (ProductService.class) {
            changed = true;
            em.persist(product);
        }
    }

    public long countProducts() {
        return count;
    }

    public void removeProduct(Product p) {
        synchronized (ProductService.class) {
            changed = true;
            em.remove(em.merge(p));
        }
    }

    public int removeAllProducts() {
        synchronized (ProductService.class) {
            changed = true;
            return em.createNamedQuery("Product.deleteAll").executeUpdate();
        }
    }

    public List<Product> getProducts() {
        synchronized (ProductService.class) {
            if (changed) {
                productRecordsFromDB();
                changed = false;
            }
        return products;
        }
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product p) {
        product = p;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我已经将synchronized块添加到相关部分以确保串行访问,尽管现在开始感觉更像是一个单例.我仍然很想知道其他人如何处理与多个数据存储调用有关的问题.

具体来说,我创建了一个"脏"标志,检查了该标志,如果DB已更新,则脏标志设置为true(通过更新数据库).检测到脏标志后,它将设置为false,因此只能对DB进行一次调用.因此,不会发生数据库颠簸.

我的问题是:我做了什么,这是解决方案的合适"最佳实践",还是有一种我不知道的更聪明的方法?我在考虑旧的"J2EE"蓝图设计模式以及在Java EE 6的上下文中可能缺少的可能注释.

Arj*_*jms 5

这是解决方案的合适"最佳实践"还是有一种我不知道的更聪明的方法?

遗憾的是,构建会话bean的方式不是最佳实践.事实上,正如Mikko解释的那样,它完全反对会话bean应该如何正常工作.所以,尽管你做了明显的努力,但我担心你创造的是一个不好的做法的一个主要例子.它几乎一切应该不是在一个无状态会话bean做.

为了解决BalusC概述的问题,您可以使用视图绑定的单独的辅助bean,而不是让它直接绑定到服务.然后,此支持是在请求期间或视图范围持续时间内缓存结果的bean.

例如

服务:

@Stateless
public class ProductService {

    @PersistenceContext(name = "myPU")
    private EntityManager em;

    public List<Product> getProducts() {
        em.createNamedQuery("Product.getAll", Product.class).getResultList();
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

然后是支持bean (如果使用CDI,通过例如CODI添加@ViewScoped注释):

@ViewScoped
@ManagedBean
public class SomeBacking {

    private List<Product> products;

    @EJB
    ProductService productService;

    @PostConstruct
    public void init() {
        products = productService.getProducts();
    }

    public List<Product> getProducts() {
        return products;
    }
}
Run Code Online (Sandbox Code Playgroud)

我已将调用服务置于@PostConstruct此处,但根据您的具体要求,这当然也可以是动作方法或通过getter中的延迟加载模式.

  • 为什么这么想?这不仅仅是另一个阶级.每个请求或每个视图范围只查询DB一次,每次JSF调用getter时,都会返回缓存的`products`.这是一个非常便宜的电话,不涉及数据库访问.我实际上做的是将这种缓存从全局位置移动到本地位置. (2认同)
  • @CodesNChaos根本不是BalusC的意思.DB是否更新与此无关.问题在于,在单个请求期间,JSF通常会多次咨询房产.如果没有我概述的模式,每次这样的咨询都会导致数据库调用.这不是你想要的.您还不想要的是在生命周期处理期间数据在任意点发生变化.因此,数据实际上*应该*在整个生命周期中保持不变(实际上也是在处理后退时). (2认同)