我有一个在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.
两个问题:
答案 0 :(得分:1)
如何找出在显式事务中运行的SELECT查询?
打开SQL和连接的pgpool2日志记录:
将以下语句放入pgpool.conf(可以通过cp $prefix/etc/pgpool.conf.sample $prefix/etc/pgpool.conf
设置):
log_per_node_statement
log_connections
或者,打开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。
此外,将您自己的调试日志代码放入启动和启动的方法中。结束事务,以便您可以查看事务何时启动/提交/回滚。
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事务无法使用它。
如果您已使用 Transaction-Scoped EntityManager
在无状态会话Bean中,您有EntityManager
注释
@PersistenceContext(type=PersistenceContextType.TRANSACTION)
,或
没有@PersistenceContext
属性的注释type
(因为
TRANSACTION
是默认值):
如果您已使用扩展范围的EntityManager
在您的有状态会话Bean中,您有EntityManager
注释@PersistenceContext(type=PersistenceContextType.EXTENDED)
。
实施例
@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)。
干杯:)
答案 1 :(得分:1)
您可能需要考虑使用EclipseLink数据分区在JPA中进行分区,
http://java-persistence-performance.blogspot.com/2011/05/data-partitioning-scaling-database.html