Я пытаюсь добавить/получить/обновить код, и я использовал провайдера EclipseLink и JPA2.0. и MySQL.JPA 2.0 Как обрабатывать тупик (Eclipselink JPA2.0 MySQL)
Приведенный ниже код вызывает ошибку при возникновении тупика. Проблема происходит случайным образом. Я хотел знать, как обращаться с тупиком.
Вот сообщение об ошибке:
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: null, message from server: "Deadlock found when trying to get lock; try restarting transaction"
Error Code: 1213
Call: UPDATE activitylog SET timestampdate = ? WHERE (logid = ?)
bind => [2013-11-19 20:10:38.583, 1]
Query: UpdateObjectQuery([email protected])
Вот код, который я пытаюсь:
public class TestMain {
public static void main(String[] args) {
for(int j = 0; j < 10; j ++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
ActivityLogDAO activityLogDAO = new ActivityLogDAO();
try {
ActivityLog theActivityLog = new ActivityLog();
theActivityLog.setTimestampdate(new Date());
theActivityLog.setMyId(i);
activityLogDAO.insert(theActivityLog);
ActivityLog activityLog = activityLogDAO.getActivityLog(theActivityLog);
activityLog.setTimestampdate(new Date());
activityLogDAO.update(activityLog);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
thread.start();
}
}
}
Вот класс Entity
@Entity
@Table(name="activitylog")
public class ActivityLog implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Column(name="logid")
private long logid;
@Column(name="myid")
private long lMyId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="timestampdate", nullable=true)
private Date timestampdate;
public long getMyId() {
return lMyId;
}
public void setMyId(long lMyId) {
this.lMyId = lMyId;
}
public long getLogid() {
return logid;
}
public void setLogid(long logid) {
this.logid = logid;
}
public Date getTimestampdate() {
return timestampdate;
}
public void setTimestampdate(Date timestampdate) {
this.timestampdate = timestampdate;
}
}
здесь мой класс DAO :
public class ActivityLogDAO {
private EntityManagerFactory _entityManagerFactory = null;
private EntityManager _entityManager = null;
public ActivityLogDAO() {
_entityManagerFactory = Persistence.createEntityManagerFactory("MyTestOnLock");
_entityManager = _entityManagerFactory.createEntityManager();
}
protected EntityManager getEntityManager() {
return _entityManager;
}
protected void setEntityManager(EntityManager _entityManager) {
this._entityManager = _entityManager;
}
public ActivityLog insert(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
if(false == getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().begin();
}
System.out.println("inserting");
getEntityManager().persist(theActivityLog);
getEntityManager().getTransaction().commit();
System.out.println("inserted");
return theActivityLog;
}
public ActivityLog getActivityLog(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
if(false == getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().begin();
}
System.out.println("trying to get object");
Query query = getEntityManager().createQuery("SELECT m FROM ActivityLog m WHERE m.lMyId = :lMyId");
query.setParameter("lMyId", theActivityLog.getMyId());
//deadlock happens here.
@SuppressWarnings("unchecked")
List<ActivityLog> resultList = query.getResultList();
System.out.println(resultList.size());
System.out.println("got object");
if(null == resultList || 0 == resultList.size()) {
return null;
} else {
return resultList.get(0);
}
}
public ActivityLog update(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
if(false == getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().begin();
}
System.out.println("trying to update object");
Query query = getEntityManager().createQuery("UPDATE ActivityLog m SET m.timestampdate = :timestampdate WHERE m.lMyId = :lMyId");
query.setParameter("lMyId", theActivityLog.getMyId());
query.setParameter("timestampdate", theActivityLog.getTimestampdate());
int executeUpdate = query.executeUpdate();
getEntityManager().getTransaction().commit();
System.out.println("object updted.");
if(0 == executeUpdate) {
return null;
}
return theActivityLog;
}
}
Вот мой persistance.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="MyTestOnLock">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>test.ActivityLog</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/locktest"></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-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="100"/>
<property name="eclipselink.order-updates" value="true"/>
<property name="eclipselink.connection-pool.sequence" value="max" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.target-database" value="MySQL" />
</properties>
</persistence-unit>
</persistence>
Тупик возникает, когда AcitivityDAO пытается обновить. Есть ли причина для устранения или устранения проблемы взаимоблокировки?
Любая помощь приветствуется!
Я получаю обратно следующее сообщение об ошибке:
javax.persistence.PersistenceException: java.lang.NullPointerException
и
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Deadlock found when trying to get lock; Try restarting transaction, message from server: "Lock wait timeout exceeded; try restarting transaction"
Error Code: 1205
Call: UPDATE activitylog SET timestampdate = ? WHERE (myid = ?)
bind => [2013-11-20 16:54:09.646, 0]
Query: UpdateAllQuery(referenceClass=ActivityLog sql="UPDATE activitylog SET timestampdate = ? WHERE (myid = ?)")
я использовал один и тот же код, указанный Ridal @ Крис.
вот код: В основном я пытался несколько раз запустить класс MainTest.
public class MainTest {
public static void main(String[] args) {
updateActivityLog();
}
private static void updateActivityLog() {
final PersistenceController persistenceController = new PersistenceController(Persistence.createEntityManagerFactory("MyTestOnLock"));
for (int i = 0; i < 100; i++) {
try {
for(int j = 0; j < 200; j++) {
ActivityLog theActivityLog = new ActivityLog();
theActivityLog.setMyId(j);
theActivityLog.setTimestampdate(new Date());
persistenceController.update(theActivityLog);
}
} catch (Exception e) {
e.printStackTrace();
}
}
persistenceController.commitAndClose();
}
}
public class PersistenceController {
private EntityManager manager;
public PersistenceController(EntityManagerFactory factory)
{
/*
* Normally you want to split your work up into separate transactions
* (ie new entity managers), in a logical way which will depend on how
* your application works. This class will do that for you if you keep
* your factory. Note that factory's are expensive to create but entity
* managers are cheap to create.
*/
manager = factory.createEntityManager();
manager.getTransaction().begin();
}
// Call ONCE on an object after creating it, it will stay in sync with the database even when you change it remotely
public void persist(Serializable entityObj)
{
manager.persist(entityObj);
manager.flush();
}
// Call to sync with database (even though you might not actually see the objects in the database until you commit)
public void flush()
{
manager.flush();
}
/*
* Call when you are done with your unit of work to commit the DB changes
*/
public void commitAndClose()
{
manager.getTransaction().commit();
manager.close();
}
public ActivityLog getActivityLog(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
if(false == manager.getTransaction().isActive()) {
manager.getTransaction().begin();
}
System.out.println("trying to get object");
Query query = manager.createQuery("SELECT m FROM ActivityLog m WHERE m.lMyId = :lMyId");
query.setParameter("lMyId", theActivityLog.getMyId());
@SuppressWarnings("unchecked")
List<ActivityLog> resultList = query.getResultList();
System.out.println(resultList.size());
System.out.println("got object");
if(null == resultList || 0 == resultList.size()) {
return null;
} else {
return resultList.get(0);
}
}
public ActivityLog update(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
if(false == manager.getTransaction().isActive()) {
manager.getTransaction().begin();
}
ActivityLog activityLog = getActivityLog(theActivityLog);
activityLog.setTimestampdate(theActivityLog.getTimestampdate());
persist(activityLog);
return theActivityLog;
}
}
Должен ли я получить EntityManager для каждой вставки базы данных или объединять или обновлять или удалять? см. ниже код, с этим я не вижу тупика. Пожалуйста подтвердите.
public class ActivityLogDAO {
private EntityManagerFactory _entityManagerFactory = null;
private EntityManager _entityManager = null;
public ActivityLogDAO() {
_entityManagerFactory = Persistence.createEntityManagerFactory("MyTestOnLock");
}
protected EntityManager getEntityManager() {
return _entityManager;
}
protected void setEntityManager(EntityManager _entityManager) {
this._entityManager = _entityManager;
}
public ActivityLog insert(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
_entityManager = _entityManagerFactory.createEntityManager();
if(false == getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().begin();
}
System.out.println("inserting");
getEntityManager().persist(theActivityLog);
getEntityManager().getTransaction().commit();
System.out.println("inserted");
return theActivityLog;
}
public ActivityLog getActivityLog(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
_entityManager = _entityManagerFactory.createEntityManager();
if(false == getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().begin();
}
System.out.println("trying to get object");
Query query = getEntityManager().createQuery("SELECT m FROM ActivityLog m WHERE m.lMyId = :lMyId");
query.setParameter("lMyId", theActivityLog.getMyId());
//deadlock happens here.
@SuppressWarnings("unchecked")
List<ActivityLog> resultList = query.getResultList();
System.out.println(resultList.size());
System.out.println("got object");
if(null == resultList || 0 == resultList.size()) {
return null;
} else {
return resultList.get(0);
}
}
public ActivityLog update(ActivityLog theActivityLog) throws Exception {
if(null == theActivityLog) {
throw new Exception("Invalid ActivityLog Object");
}
_entityManager = _entityManagerFactory.createEntityManager();
if(false == getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().begin();
}
System.out.println("trying to update object");
Query query = getEntityManager().createQuery("UPDATE ActivityLog m SET m.timestampdate = :timestampdate WHERE m.lMyId = :lMyId");
query.setParameter("lMyId", theActivityLog.getMyId());
query.setParameter("timestampdate", theActivityLog.getTimestampdate());
int executeUpdate = query.executeUpdate();
getEntityManager().getTransaction().commit();
System.out.println("object updted.");
if(0 == executeUpdate) {
return null;
}
return theActivityLog;
}
}
Если вы этого не сделали, возможно, посмотрите на транзакции с использованием jpa и как транзакции помогут избежать взаимоблокировок. Об этом есть хорошая информация. Удостоверьтесь, что вы сосредоточены на том, когда транзакция освобождает блокировку. – user2932397
это не представляется возможным из показанного кода, так как каждый поток будет касаться только строки, создаваемой в каждой итерации. В прогоне, который воспроизводит проблему, проверьте, что еще выдаёт утверждения объекту с помощью logid = 1 (или что когда-либо значение отображается в ошибке). – Chris