【发布时间】:2014-07-17 03:45:11
【问题描述】:
我正在尝试从表中获取记录。所以我使用以下本机查询(自连接)来获取。我在 Windows、EclipseLink JPA2 和 MySQL 上使用 Eclipse IDE。
select * from mytable as detail join (select max(timestamp) as maxtimestamp from mytable where id=" + theUser.getId() + " group by hnumber order by maxtimestamp limit " + <offset> + "," + <iTotalRecords> + ") as topconv on detail.timestamp=topconv.maxtimestamp order by detail.timestamp
我遇到了多线程带来的死锁问题。我不确定是JPA死锁还是MySQL死锁。
我有以下 pojo 课程
@Entity
@Table(name="mytable")
public class MyTable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Column(name="mytableid")
private long lMyTableId;
@ManyToOne
@JoinColumn(name="id", referencedColumnName="id")
private User user; //this object has id, name and so on fields.
@Column(name="timestamp", length=15, nullable=false)
private String strTimestamp;
@Column(name="hnumber", nullable=true)
private String hNumber;
//Getters and Setters.
}
这是获取记录的方法
public List<MyTable> fetchRecords(User theUser, int iTotalRecords, long offset) throws Exception {
if(null == theUser) {
throw new Exception("Invalid input.");
}
EntityManager entityManager = getEntityManager();
if(false == entityManager.getTransaction().isActive()) {
entityManager.getTransaction().begin();
}
try {
Query query = entityManager.createNativeQuery("select * from mytable as detail join (select max(timestamp) as maxtimestamp from mytable where id=" + theUser.getId() + " group by hnumber order by maxtimestamp limit " + offset + "," + iTotalRecords + ") as topconv on detail.timestamp=topconv.maxtimestamp order by detail.timestamp", MyTable.class);
@SuppressWarnings("unchecked")
List<MyTable> resultList = query.getResultList();
return resultList;
} catch(Throwable th) {
throw new Exception(th.getMessage());
} finally {
closeEntityManager();
}
}
获取和关闭EntityManager
private EntityManagerFactory _entityManagerFactory = Persistence.createEntityManagerFactory("JPATest");
protected EntityManager getEntityManager() {
_entityManager = _entityManagerFactory.createEntityManager();
return _entityManager;
}
protected void closeEntityManager() {
try {
if(null != _entityManager) {
_entityManager.close();
}
} catch(Throwable th){}
}
我的 persistence.xml 如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPATest">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.company.service.db.pojo.User</class>
<class>com.company.service.db.pojo.MyTable</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mydb"></property>
<property name="javax.persistence.jdbc.user" value="root"></property>
<property name="javax.persistence.jdbc.password" value="root"></property>
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.id-validation" value="NULL"></property>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="javax.persistence.lock.timeout" value="1000"/>
<property name="eclipselink.target-database" value="MySQL"/>
</properties>
</persistence-unit>
</persistence>
我的应用程序支持多线程。
为了复制死锁,我运行了 100 个线程,每个线程执行 fetchRecords 方法。每次提取的记录接近200条或更多。
请告诉我如何解决这个问题。任何帮助表示赞赏。
【问题讨论】:
-
症状是什么,是什么让您认为这是“JPA2 死锁”?
-
我怀疑,但不是 100% 确定。
-
你检查了什么?当您怀疑存在死锁时,您可以做的最简单的事情是对 Java 进程进行线程转储,并检查线程在等待什么。这应该会给你一些提示,而不是在没有任何证据的情况下怀疑。
-
@AdrianShum - 从哪里获得 java 进程的线程转储?来自任务管理器?
-
取决于您运行的平台。在 Windows 中,按 Control-Break 应该可以解决问题。在 Unix 环境下,您可以通过
kill -QUIT <pid>或kill -3 <pid>发送 QUIT 信号来实现。在JDK的更高版本中,它还包括一个名为jstack的工具,可以通过jstack <pid>获取进程ID的线程转储。
标签: java mysql multithreading eclipselink jpa-2.0