Java開発におけるJPA楽観的ロック例外
この投稿では、JPAテクノロジーとそのJava開発での使用について説明します。 Java開発インドの専門家は、JPAとHibernate、MySqlデータベース、Mavenといったテクノロジーの使用例を説明しています。 この投稿を読んで、彼らが言いたいことを知ってください。
Technology: JPAは、永続性に関するSun MicroSystemsの標準であるJavaPersistenceAPIの略です。 ORMはオブジェクトリレーショナルマッピングの略です。 JPAはORMの標準です。 フレームワークでORMを使用する必要がある場合、JPAによって指定されたすべての仕様を実装する必要があります。 JPAは単なる仕様であり、CRUD操作に永続性を提供する必要があります。 Hibernate、Eclipseリンクなど 永続化プロバイダーの例です。
Technologies: JPAおよびHibernate、Maven、MySqlデータベース
Usecase: JPA、休止状態、Eclipseリンクを使用してJava開発アプリケーションで作業している場合、例外を下回ることがよくあります。
javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect).
問題は、JPA永続プロバイダーが最新バージョンのオブジェクトではないオブジェクトを更新しようとしていることです。 通常、リレーショナルデータベースは、テーブルでレコードが更新されるたびにバージョンを維持します。 テーブル内のレコードを更新する場合は、データベースから最新バージョンのレコードを取得して更新する必要があります。 ORMを使用しているため、最後のバージョンのオブジェクトを取得してマージする必要があります。
したがって、このドキュメントでは、このエラーがいつ発生し、どのように解決するかを確認できます。
1. プロジェクト構造

プロジェクト構造は上のスクリーンショットのようになります。
プロジェクト構造を見ると、それはMavenプロジェクトです。pom.xmlは必須ファイルです。 このMavenファイルでは、JPA、Hibernate、Java、データベースなどの依存関係を構成できます。 データストレージにMySQLデータベースを使用しています。
エンティティ用、ビジネスロジック用、アプリケーションテスト用の3つのパッケージ。 DTOパッケージが1つある場合、多層アプリケーションエンティティで作業している場合、エンティティはクライアント層に直接公開されません。 エンティティは、エンティティにマップされるDTO(データ転送オブジェクト)に変換されます。
2. プロジェクトの依存関係
pom.xml
4.0.0 naveen.examples jpa 0.0.1-SNAPSHOT jar jpa http://maven.apache.org UTF-8 1.8 4.3.6.Final UTF-8 org.hibernate hibernate-entitymanager ${hibernate.version} org.hibernate hibernate-c3p0 ${hibernate.version} mysql mysql-connector-java 5.1.31 junit junit 3.8.1 test
3. JPAの構成
これはHibernateが追加したhibernate依存関係であるため、他のORMであればそれらの依存関係を追加します。
persistence.xml
org.hibernate.jpa.HibernatePersistenceProvider
これはpersistence.xmlです。ここでは、データベースの資格情報、永続性の名前、エンティティマネージャーファクトリが必要とするすべての属性について説明する必要があります。
4. CRUD
これは、データベースに永続化されるエンティティクラスです。
EmployeeBE.java
// Import statements
@NamedQueries({
@NamedQuery(name = EmployeeBE.FIND_ALL, query = "SELECT e FROM EmployeeBE e order by e.name "),
})
@Entity
@Table(name = "T_EMP")
public class EmployeeBE implements Serializable{
private static final long serialVersionUID = 1607726899931733607L;
public static final String FIND_ALL = "naveen.examples.jpa.entity.EmployeeBE.find_all";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "NAME")
private String name;
@Column(name = "version_num")
@Version
private int version;
// Getters and setters
}
EmployeeCrud.java
// Interface for CRUD operations.
package naveen.examples.jpa.business;
import java.util.List;
import naveen.examples.jpa.entity.EmployeeBE;
public interface EmployeeCrud {
List findAllEmployeeBECol();
EmployeeBE saveEmployee(EmployeeBE employeeBE);
EmployeeBE updateEmployee(EmployeeBE employeeBE);
EmployeeBE findById(int id);
}
EmployeeCrudImpl.java
// Implementatino class for CRUD operations
public class EmployeeCrudImpl implements EmployeeCrud{
public EmployeeBE saveEmployee(EmployeeBE employeeBE) {
EntityManager em = EntityManagerUtil.getEntityManager();
em.getTransaction().begin();
em.persist(employeeBE);
em.getTransaction().commit();
return employeeBE;
}
public EmployeeBE updateEmployee(EmployeeBE employeeBE) {
EntityManager em = EntityManagerUtil.getEntityManager();
em.getTransaction().begin();
em.merge(employeeBE);
em.getTransaction().commit();
return employeeBE;
}
@SuppressWarnings("unchecked")
public List findAllEmployeeBECol() {
EntityManager em = EntityManagerUtil.getEntityManager();
Query query = em.createNamedQuery(EmployeeBE.FIND_ALL);
return query.getResultList();
}
public EmployeeBE findById(int id) {
EntityManager em = EntityManagerUtil.getEntityManager();
return em.find(EmployeeBE.class, id);
}
EntityManagerUtil.java
// Entity Manager
public class EntityManagerUtil {
private static EntityManager entityManager;
private EntityManagerUtil() {
}
public static EntityManager getEntityManager() {
if(entityManager==null){
EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("jpa-example");
return emFactory.createEntityManager();
}
return entityManager;
}
}
上記のコードスニペットを見ると、
-
インターフェイス、ビジネスメソッドを定義
-
InterfaceImpl、ビジネスメソッドの実装
-
EntityManagerユーティリティ。entitymanagerオブジェクトを取得します。
EntityManagerUtilクラスでは、persistence.xmlファイルで言及したjpa-exampleパラメーターを渡すので、その永続性ユニットに接続します。
5. DEMO
JPA楽観的ロック例外をヒットする方法を示します。
Application.java
public class Application {
public static void main(String args[]) {
EmployeeCrud employeeCrud = new EmployeeCrudImpl();
List employeeBEs = employeeCrud.findAllEmployeeBECol();
if(!employeeBEs.isEmpty()){
EmployeeBE employeeBE = employeeBEs.get(0);
employeeBE.setName("Updated");
employeeCrud.updateEmployee(employeeBE);
// Here Optimistic lock exception
employeeCrud.updateEmployee(employeeBE);
}else{
EmployeeBE employeeBE = new EmployeeBE();
employeeBE.setName("Naveen");
employeeBE = employeeCrud.saveEmployee(employeeBE);
}
}

アプリを実行する前に、DBにデータがありません

アプリケーションを実行する場合


IDが16でバージョン0のテーブル内のデータがある場合。
デバッグモードでアプリケーションを実行する場合

最初の更新は完了したが、コード内に同じ従業員オブジェクトがある場合、最初の更新メソッドが完了したため、すでにコミットされているため、バージョンは1になります。

スクリーンショットを見ると、バージョンは1になっていますが、オブジェクトはバージョン0を意味する古いものです。 2番目の更新メソッドが古いオブジェクトで実行された場合、オプティミスティックロック例外が発生します。

実行を続行すると、オプティミスティックロック例外が発生します。
6. 溶液
このエラーを解決するには、2つの方法があります。
-
データベースから最新のオブジェクトを取得し、古いオブジェクトの値を新しいオブジェクトに永続化してマージする必要がある場合は、それらの値を設定します。
-
古いオブジェクトの場合、データベースから最新バージョンを設定します。

私は2番目のアプローチに従っています、スクリーンショットが表示されたら、最新のバージョン番号を古いオブジェクトに設定しています

コンソールで実行した後、エラーなし:

これは、2番目の更新メソッド用に生成されたSQLクエリです。 したがって、例外は発生していません。
Java development Indiaの専門家は、JPAテクノロジーとJavaプロジェクトでのその使用に関する最高の知識を共有しています。 If you need more details, you can ask the developers who are already applying this technology in their projects.
結論
これらの2つの方法を使用すると、この非常に迷惑なエラーを解決できます。 これは非常に単純な例であるため、簡単に見つけることができますが、リアルタイムアプリケーションではこれほど単純ではありません。 したがって、この例外が発生した場合は、デバッグモードでアプリケーションを実行し、表示されているおおよそのコードスニペットに移動してからデバッグでF5を押し、エンティティが更新されている他の場所で対応する永続プロバイダーのエンティティマネージャー実装に深く入ります。 次に、要件に応じて、これら2つの手法のeithr4に従います。 データベースのバージョン番号を確認してください。 変更ごとに、永続性プロバイダーの実装に基づいて増加する場合と増加しない場合があります。