2013-05-20 35 views
0

做我曾在一个JBoss AS运行7容器女巫通过JPA,一个它的配置委托给JTA一个PostgreSQL 9.1数据库保存我们的数据的Web软件。测量许多交易是如何在JTA应用

去年它适应于在AWS EC2云上运行。随着用户需求的增长,我们的数据库使用量也在增长。正如预期的那样,我们的数据库服务器在高峰时间变得繁忙,这影响了我们用户的使用体验。

经过对PostgreSQL的复制研究之后,我们意识到PGPool2对于我们的情况可能是一个不错的复制解决方案:它为SELECT查询提供负载均衡,并为CUD操作提供复制(UPDATE,INSERT和DELETE)。

到目前为止好,但事实证明软件缓慢。如果事实如在PGPool2文档中所阐明的那样,那么SELECT查询如果在明确的BEGIN/END事务中定义,则不会进行负载均衡。

 
For a query to be load balanced, all the following requirements must be met: 
    - PostgreSQL version 7.4 or later 
    - the query must not be in an explicitly declared transaction (i.e. not in a BEGIN ~ END block) 
    - it's not SELECT nextval or SELECT setval 
    - it's not SELECT INTO 
    - it's not SELECT FOR UPDATE nor FOR SHARE 
    - it starts with "SELECT" or one of COPY TO STDOUT, EXPLAIN, EXPLAIN ANALYZE SELECT... 
    - ignore_leading_white_space = true will ignore leading white space. 

两个问题:

  • 我怎么能弄清楚,在明确的交易运行我们的SELECT查询?
  • _javax.ejb.TransactionAttributeType.NOT_SUPPORTED_是否修复事务范围,使我的SELECT方法以“无事务”方式运行?

回答

1

我怎么能弄清楚,在明确的交易运行我们的SELECT查询?

  1. 打开SQL的pgpool2记录和连接:

    将下面的语句为pgpool.conf(您可以通过cp $prefix/etc/pgpool.conf.sample $prefix/etc/pgpool.conf设置):

    log_per_node_statement 
    log_connections 
    
  2. 另外,打开JPA的日志追踪:

    这需要一个differen t方法取决于您的JPA实现(How to view the SQL queries issued by JPA?JPA 2.0 (logging and tracing through) with Glassfish 3.0.1 and NetBeans 6.9.1:)。

    这将记录SQL,但不会记录事务开始/提交/回滚。

    此外,将您自己的调试日志记录代码放入启动&最终事务的方法中,以便您可以查看事务何时启动/提交/回滚。

Does _javax.ejb.TransactionAttributeType.NOT_SUPPORTED_ fix the transaction scopes, granting that my SELECT method will be running as "transaction-free"?

如果您正在使用容器管理事务(注释@TransactionManagement(CONTAINER)@TransactionAttribute),然后NOT_SUPPORTED将暂时从当前线程disassocate JTA事务。然后该方法将运行而没有事务上下文。

你以后的JPA查询将JTA事务外运行 - 因为JTA事务不适用于它用。

  1. 如果您已经使用事务范围的EntityManager

    在您的Stateless Session Bean的你有一个EntityManager注释 @PersistenceContext(type=PersistenceContextType.TRANSACTION),或 注释@PersistenceContext没有type属性(因为 TRANSACTION是默认) :

    • 那么EM将失去它的NOT_SUPPORTED方法,因为PC与当前的交易,而不再访问相关的内部持久化上下文
    • ,所以你不能在该方法使用这样的EM(例如运行查询或查询缓存对象)
    • 所以你必须使用一个额外的应用程序管理的EM的NOT_SUPPORTED方法中
    • 您必须从EntityManagerFactory的在一个地方,没有JTA事务是活动的创建应用程序管理的EM(例如,在NOT_SUPPORTED法),这是因为应用程序管理的EM会自动将其自身与当前线程的JTA事务创建过程中
    • 任何物体从查询通过返回关联的新的应用程序管理的EM将在从原来的EM不同的持久化上下文,所以你需要非常谨慎,以干净地从PC脱离这样的对象(例如appMgdEM.clear()或appMgdEM.close()或appMgdEM.detach(someEntity))如果你是修改/与原EM合并。
  2. 如果您已经使用了扩展作用域的EntityManager

    在有状态会话Bean你有一个EntityManager注释@PersistenceContext(type=PersistenceContextType.EXTENDED)

    • 那么EM仍然有它的持久化上下文的NOT_SUPPORTED方法中,因为PC与有状态会话bean
    • 相关,但EM是使用已经处于一个“活”的中部的连接交易
    • 因此,如果您想要在事务之外运行查询,则不能在方法
    • 中使用此类EM,因此您必须在NOT_SUPPORTED方法中使用额外的应用程序管理的EM(相同点适用于上述)。
  3. @Stateless 
    public class DepartmentManagerBean implements DepartmentManager { 
    
        @PersistenceUnit(unitName="EmployeeService") 
        EntityManager txScopedEM; 
    
        @PersistenceUnit(unitName="EmployeeService") 
        EntityManagerFactory emf; 
    
        @TranactionAttribute(REQUIRED) 
        public void modifyDepartment(int deptId) { 
         Department dept = txScopedEM.find(Department.class, deptId); 
         dept.setName("New Dept Name"); 
         List<Employee> empList = getEmpList(); 
         for(Employee emp : empList) { 
          txScopedEM.merge(emp); 
          dept.addEmployee(emp); 
         } 
         dept.setEmployeeCount(empList.size()); 
        } 
    
        @TranactionAttribute(NOT_SUPPORTED) 
        public void getEmpList() { 
         EntityManager appManagedEM = emf.createEntityManager(); 
         TypedQuery<Employee> empQuery = appManagedEM.createQuery("...", Employee.class); 
         List<Employee> empList = empQuery.getResultList(); 
         // ... 
         appManagedEM.clear(); 
         return empList; 
        } 
    } 
    

    另类/调整方法

    上面有你如何查询一些限制,以及如何使用造成的对象。如果使用无状态会话bean,它需要创建一个“即时”EM,并且还需要调用entityManager.merge()。它可能不适合你。

    一个强有力的选择是重新设计您的应用程序,以便在事务启动之前运行所有查询。那么应该可以使用一个Extended-Scoped EntityManager。使用扩展范围EM在“NOT_SUPPORTED”方法1(无事务)中运行查询。然后使用相同的扩展范围EM在“REQUIRED”方法2(使用事务)中运行修改。事务范围的EntityManaged不起作用(它会尝试从一开始就是事务性的,并且在NOT_SUPPORTED方法中没有PC)。

干杯:)

+0

感谢您的有用的答案。事实上,我已经找到了自己的一些答案,但是解释的一致性让我在选择时感到安全。非常感谢。 – Miere

+0

不客气。 –