1

冗余行显示在数据库中:

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.

在这种情况下,如何获得锁以防止重复?

4

2 回答 2

2

您需要在执行锁定查询之前启动事务。您只能在数据库事务的上下文中锁定某些内容。

于 2012-08-07T13:59:15.477 回答
1

就我而言,我使用 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);
    }
}
于 2019-04-15T13:02:52.767 回答