冗余行显示在数据库中:
mysql>
mysql>
mysql> USE usenet;SHOW TABLES;DESCRIBE ARTICLE;DESCRIBE NEWSGROUP;SELECT * FROM NEWSGROUP;
Database changed
+------------------+
| Tables_in_usenet |
+------------------+
| ARTICLE |
| NEWSGROUP |
+------------------+
2 rows in set (0.00 sec)
+---------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+----------------+
| ID | bigint(20) | NO | PRI | NULL | auto_increment |
| MESSAGENUMBER | int(11) | YES | | NULL | |
| NEWSGROUP_ID | bigint(20) | YES | MUL | NULL | |
+---------------+------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| ID | bigint(20) | NO | PRI | NULL | auto_increment |
| NEWSGROUP | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
+----+-------------------------------+
| ID | NEWSGROUP |
+----+-------------------------------+
| 1 | gwene.com.androidcentral |
| 2 | gwene.com.androidcentral |
| 3 | gwene.com.blogspot.emacsworld |
| 4 | gwene.com.blogspot.googlecode |
| 5 | gwene.com.blogspot.googlecode |
| 6 | gwene.com.economist |
| 7 | gwene.com.economist |
+----+-------------------------------+
7 rows in set (0.00 sec)
mysql>
NEWSGROUP.newsgroup
应具有唯一值。我有理由确定我需要在Article
构造函数中锁定数据库:
public Article(Message message, Folder folder) {
messageNumber = message.getMessageNumber();
EntityManagerFactory emf;
EntityManager em;
emf = Persistence.createEntityManagerFactory("USENETPU");
em = emf.createEntityManager();
String fullNewsgroupName = folder.getFullName();
TypedQuery<Newsgroup> query = em.createQuery("SELECT n FROM Newsgroup n WHERE n.newsgroup = :newsGroupParam", Newsgroup.class);
query.setParameter("newsGroupParam", fullNewsgroupName);
em.lock(query, LockModeType.PESSIMISTIC_WRITE);
try {
newsgroup = query.getSingleResult();
LOG.info("found " + query.getSingleResult()); //ok
} catch (javax.persistence.NoResultException e) {
newsgroup = new Newsgroup(folder);
LOG.info(e + "\ncould not find " + fullNewsgroupName); //ok
} catch (NonUniqueResultException e) {
LOG.info(e + "\nshould never happen\t" + fullNewsgroupName); //not ok
}
}
但是,该锁定导致:
run:
DEBUG: nntp: newsrc loading /home/thufir/.newsrc
DEBUG: nntp: newsrc load: 5 groups in 35ms
[EL Info]: 2012-08-03 15:35:28.386--ServerSession(17944810)--EclipseLink, version: Eclipse Persistence Services - 2.3.0.v20110604-r9504
[EL Info]: 2012-08-03 15:35:29.526--ServerSession(17944810)--file:/home/thufir/NetBeansProjects/USENET/build/classes/_USENETPU login successful
Aug 03, 2012 3:35:30 PM net.bounceme.dur.usenet.driver.FetchBean <init>
INFO: [gwene.com.androidcentral, gwene.com.blogspot.emacsworld, gwene.com.blogspot.googlecode, gwene.com.blogspot.googlereader, gwene.com.economist]
Aug 03, 2012 3:35:31 PM net.bounceme.dur.usenet.driver.FetchBean main
SEVERE: null
javax.persistence.TransactionRequiredException:
Exception Description: No transaction is currently active
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.throwCheckTransactionFailedException(EntityTransactionWrapper.java:113)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.checkForTransaction(EntityTransactionWrapper.java:50)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:1776)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.lock(EntityManagerImpl.java:1617)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.lock(EntityManagerImpl.java:1593)
at net.bounceme.dur.usenet.model.Article.<init>(Article.java:34)
at net.bounceme.dur.usenet.driver.FetchBean.<init>(FetchBean.java:41)
at net.bounceme.dur.usenet.driver.FetchBean.main(FetchBean.java:21)
BUILD SUCCESSFUL (total time: 16 seconds)
而评论它给出了正常的运行:
run:
DEBUG: nntp: newsrc loading /home/thufir/.newsrc
DEBUG: nntp: newsrc load: 5 groups in 14ms
[EL Info]: 2012-08-03 15:36:28.103--ServerSession(17944810)--EclipseLink, version: Eclipse Persistence Services - 2.3.0.v20110604-r9504
[EL Info]: 2012-08-03 15:36:29.186--ServerSession(17944810)--file:/home/thufir/NetBeansProjects/USENET/build/classes/_USENETPU login successful
Aug 03, 2012 3:36:29 PM net.bounceme.dur.usenet.driver.FetchBean <init>
INFO: [gwene.com.androidcentral, gwene.com.blogspot.emacsworld, gwene.com.blogspot.googlecode, gwene.com.blogspot.googlereader, gwene.com.economist]
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: found gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.androidcentral
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.emacsworld
Aug 03, 2012 3:36:31 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: found gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.blogspot.googlecode
Aug 03, 2012 3:36:32 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: found gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.model.Article <init>
INFO: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
should never happen gwene.com.economist
Aug 03, 2012 3:36:33 PM net.bounceme.dur.usenet.driver.FetchBean <init>
INFO: **************************done
BUILD SUCCESSFUL (total time: 16 seconds)
只有Article
构造函数才会实例化Newsgroup
实体;目前,表格生成策略为drop and create
。
如何在此方案中获取锁定以防止重复?
答案 0 :(得分:1)
您需要在执行锁定查询之前启动事务。您只能在数据库事务的上下文中锁定某些内容。
答案 1 :(得分:0)
就我而言,我使用jpa存储库和查询提示来获得乐观悲观的写锁。通常,我将在服务层上使用@transactional
批注,但不适用于以下存储库设置。因此,在使用存储库之前,我必须显式启动事务。也许这对您有帮助。
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
/**
* "The lock acquisition request skips the already locked rows.
* It uses a SELECT … FOR UPDATE SKIP LOCKED in Oracle and PostgreSQL 9.5,
* or SELECT … with (rowlock, updlock, readpast) in SQL Server."
*/
String UPGRADE_SKIPLOCKED = "-2";
@Lock(value = LockModeType.PESSIMISTIC_WRITE) // adds 'FOR UPDATE' statement
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = UPGRADE_SKIPLOCKED)})
Book findFirst();
}
和服务:
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class BookService {
private final PlatformTransactionManager transactionManager;
private final BookRepository bookRepository;
public BookService(PlatformTransactionManager transactionManager, BookRepository bookRepository) {
this.transactionManager = transactionManager;
this.bookRepository = bookRepository;
}
public void doSomethingWithBook() {
final DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
Book book = bookRepository.findFirst();
// ....
bookRepository.save(book);
transactionManager.commit(transaction);
}
}