衡量在JTA应用程序上完成的事务数量

时间:2013-05-20 19:55:41

标签: java jpa ejb postgresql-9.1 jta

我有一个在Jboss AS 7容器中运行的网络软件,它通过JPA将我们的数据保存在PostgreSQL 9.1数据库中,JPA将其配置委托给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方法作为“无交易”运行吗?

2 个答案:

答案 0 :(得分: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的日志跟踪:

    这需要使用不同的方法或您的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,但不会记录事务start / commit / rollback。

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

  3.   

    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将暂时取消JTA事务与当前线程的关联。然后该方法将在没有事务上下文的情况下运行

    您的后续JPA查询将在JTA事务之外运行 - 因为JTA事务无法使用它。

    1. 如果您已使用 Transaction-Scoped EntityManager

      在无状态会话Bean中,您有EntityManager注释 @PersistenceContext(type=PersistenceContextType.TRANSACTION),或 没有@PersistenceContext属性的注释type(因为 TRANSACTION是默认值):

      • 然后EM将在NOT_SUPPORTED方法中丢失它的持久性上下文,因为PC与当前事务相关联,不再可访问
      • 所以你不能在方法中使用这样的EM(例如运行查询或查找缓存的对象)
      • 因此您必须在NOT_SUPPORTED方法中使用其他应用程序管理的EM
      • 您必须在没有JTA事务处于活动状态的地方(例如,在NOT_SUPPORTED方法中)从EntityManagerFactory创建应用程序管理的EM,因为应用程序管理的EM会在创建期间自动将其自身与当前线程的JTA事务关联< / LI>
      • 新应用程序管理的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(带事务)中运行修改。 Transaction-Scoped EntityManaged不起作用(它会从一开始就尝试进行事务处理,并且在NOT_SUPPORTED方法中没有PC)。

    4. 干杯:)

答案 1 :(得分:1)

您可能需要考虑使用EclipseLink数据分区在JPA中进行分区,

http://java-persistence-performance.blogspot.com/2011/05/data-partitioning-scaling-database.html