Home > Database > Mysql Tutorial > body text

What are the knowledge points related to Java and Mysql locks?

王林
Release: 2023-05-27 10:18:17
forward
1075 people have browsed it

    Definition of lock

    In computer programs, locks are used to exclusive resources. Only when the lock is obtained can the corresponding resources be operated.

    Implementation of lock

    The implementation of lock at the bottom of the computer relies on the CAS instructions (compare and swsp) provided by the CPU. For a memory address, the original value and the value attempted to be modified will be compared. , indicating whether the lock has been seized by whether the value is modified successfully.

    Locks in JVM

    In jvm, there are 2 commonly used locks

    synchronized

    synchronized is a keyword lock provided by java, which can lock objects , class, method.
    After JDK1.6, synchronized has been optimized, and biased locks and lightweight lock modes have been added. Now the operating logic of synchronized locks is as follows:

    • When initially locking , will increase the bias lock, that is, " is biased towards the thread that last acquired the lock ". Under the bias lock, the lock will be acquired directly by CAS. This mode greatly improves the throughput of a single thread repeatedly acquiring the same lock. According to Java officials, most lock contentions occur on the same thread.

    • If the bias lock CAS acquisition fails, it means that the current thread is different from the thread biased by the bias lock, and the bias lock will be upgraded to a lightweight lock, a lightweight lock The characteristic is to obtain the lock through spin CAS.

    • If the spin acquisition fails, the lock will be upgraded to a weight lock, and all threads waiting for the lock will be suspended by the JVM. After the lock is released, they will be awakened by a unified notification from the JVM. Try the CAS lock again. If it fails, continue to hang.

    Obviously, the purpose of the biased lock design is "from the official Java perspective, most contention for the same lock occurs on the same thread."
    The purpose of lightweight lock design is "in the short term, lock contention can be obtained through spin CAS, and the CPU spin consumption in a short period of time is less than the consumption of thread suspension and wake-up."
    The weight lock is the synchronized logic before the initial optimization.

    ReentrantLock

    Speaking of ReentrantLock, we have to talk about AQS in JUC.
    The full name of AQS is AbstractQueueSynchronizer. Almost all tool classes in JUC rely on AQS for implementation.
    AQS is an abstract class in java, but it is essentially the implementation of an idea in java.
    The implementation logic of AQS is as follows:

    • Construct a queue

    • Maintain threads that need to wait for locks in the queue

    • The head node is always the node that holds the lock (or holds the resource), and the waiting nodes are connected in sequence after the head node.

    • After the head node releases the lock, it will wake up the waiting nodes in order, and then those nodes will try to acquire the lock again.

    After the synchronized lock optimization, the essence of AQS is not much different from synchronized, and the performance of the two is not much different, so the current characteristics of AQS are:

    • is a lock implemented at the java api level, so various concurrent tool classes can be implemented, and the operation is more flexible

    • Because it provides a timeout, etc. The mechanism is flexible in operation, so it is not easy to deadlock. If a deadlock occurs, it will be more difficult to troubleshoot because jstack will not show a deadlock indicator.

    • Fair locks can be achieved, but synchronized must be unfair locks.

    • Because it is a lock implemented by the JavaApi layer, it can respond to interrupts.

    You will find here that ReentrantLock can actually be said to be the implementation of synchronized in the JavaApi layer.

    Mysql lock

    Shared lock (S) and exclusive lock (X)

    Scope

    Both of these locks include row-level locks and Table level lock.
    When acquiring a shared lock, if the data is locked by the exclusive lock of another transaction, it cannot be acquired and needs to wait for the exclusive lock to be released.

    Intention lock

    Scope

    The intention lock is a table lock. Before acquiring the table lock, the intention lock will be checked.

    The intent locking protocol is as follows:

    Before a transaction obtains a shared lock on a row in the table, it must first obtain an IS lock or a stronger lock on the table.

    Before a transaction can obtain an exclusive lock on a row in the table, it must first obtain an IX lock on the table.

    Before acquiring a shared lock or exclusive lock on any table lock, the shared lock on the table must be checked.

    The mutual exclusion rules for table locks and intention locks are as follows:
    X IX S IS
    X Conflict Conflict Conflict Conflict
    IX Conflict Compatible Conflict Compatible
    S Conflict Conflict Compatible Compatible
    IS Conflict Compatible Compatible Compatible

    The purpose of the intention lock is: when acquiring a table lock, you can use the intention lock to quickly determine whether it can be acquired.

    Because when acquiring a row-level lock, the corresponding intention lock will be acquired first, so that other transactions can quickly judge through the intention lock when acquiring table locks, without scanning each row.

    It is important to note that intention locks can be superimposed, that is, there will be multiple ones. For example, the T1 transaction acquires the intention lock IX1 and the row-level lock X1, and the T2 transaction can still acquire the intention lock IX2 and the row-level lock. X2, so intent locks are checked only before table-level locks are acquired.

    Блокировка записи

    Блокировка записи вступает в силу в индексе, чтобы защитить данные строки от изменения другими транзакциями, когда SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE.

    Блокировки записей по-прежнему будут действовать при отсутствии индекса, поскольку innodb создаст скрытый индекс для каждой таблицы.

    Блокировка записи — это самая простая блокировка строки.

    Gap lock

    Gap lock действует на индекс и используется для блокировки строки после значения индекса, чтобы предотвратить вставку. Она вступит в силу при выборе из таблицы, где index=? для обновления , например index= 1, строки, относящиеся к узлу индекса с index=1, будут заблокированы для предотвращения вставки данных другими транзакциями.

    Но это не помешает оператору обновления, даже если обновленные данные не существуют.

    Блокировки следующих клавиш

    Эта блокировка представляет собой комбинацию блокировки записи и блокировки пробела. Короче говоря, при выборе из таблицы, где индекс =? для обновления, будет пробел Блокировка предотвращает вставку, а также имеется блокировка записи в индексе, предотвращающая обновление и удаление этого фрагмента данных. Эта клавиша Next является просто обобщением этих двух блокировок, поскольку эти две блокировки обычно появляются вместе при выборе обновления.

    Вставка блокировки намерения

    Вставка блокировки намерения, аналогично блокировке намерения. Это специальная блокировка пробела, которая не возникает при выборе для обновления, но возникает, когда вставка происходит одновременно.Например, когда две транзакции вставляют диапазон индексов [4,7] одновременно, они получают намерение блокировка диапазона одновременно.Это Когда транзакция заблокирована, например, A: Insert-5, B: Insert-7, две транзакции не будут заблокированы в это время.

    Блокировка намерения вставки представляет собой специальную блокировку промежутка, которая предназначена для предотвращения частой блокировки вставки в случае нормального интервала блокировки блокировки промежутка, например A: вставка-5, B: вставка-7, если не вставлять блокировку намерения, то и 5, и 7 попытаются получить блокировку промежутка. В это время вторая транзакция будет заблокирована. Однако при вставке блокировки намерения вторая транзакция не будет заблокирована, а только вставленная строки действительно будут конфликтовать. , будут заблокированы.

    Блокировки AUTO-INC

    Блокировка с автоматическим приращением. Эта блокировка, очевидно, является блокировкой вставки на уровне таблицы, чтобы гарантировать сохранение первичного ключа таблицы с первичным ключом с автоинкрементом. атомный автоинкремент.

    Что касается замков, каждый должен больше понимать принципы и модели различных конструкций и операций замков, чтобы после углубления их понимания они могли использовать их более глубоко и тщательно.

    Общие сценарии использования и использования блокировок

    двойная проверка

    Как мы все знаем, транзакции MySQL бесполезны для предотвращения повторных вставок, а уникальные индексы имеют много недостатков. Лучше не использовать его, поэтому, вообще говоря, общий способ предотвратить повторную вставку — это использовать распределенные блокировки.Это более распространенный способ записи.

    final WeekendNoticeReadCountDO weekendNoticeReadCountDO = weekendNoticeReadRepositoryService.selectByNoticeId(noticeRequestDTO.getNoticeId());
    if (weekendNoticeReadCountDO == null) {
        final String lockKey = RedisConstant.LOCK_WEEKEND_READ_COUNT_INSERT + ":" + noticeRequestDTO.getNoticeId();
        ClusterLock lock = clusterLockFactory.getClusterLockRedis(
            RedisConstant.REDIS_KEY_PREFIX,
            lockKey
        );
        if (lock.acquire(RedisConstant.REDIS_LOCK_DEFAULT_TIMEOUT)) {
            //double check
            final WeekendNoticeReadCountDO weekendNoticeReadCountDO = weekendNoticeReadRepositoryService.selectByNoticeId(noticeRequestDTO.getNoticeId());
            if (weekendNoticeReadCountDO == null) {
                try {
                    lock.execute(() -> {
                        WeekendNoticeReadCountDO readCountDO = new WeekendNoticeReadCountDO();
                        readCountDO.setNoticeId(noticeRequestDTO.getNoticeId());
                        readCountDO.setReadCount(1L);
                        readCountDO.setCreateTime(new Date());
                        readCountDO.setUpdateTime(new Date());
                        weekendNoticeReadRepositoryService.insert(readCountDO);
                        return true;
                    });
                } catch (ApiException err) {
                    throw err;
                } catch (Exception e) {
                    log.error("插入", e);
                    throw new ApiException(ErrorEnum.SERVER_ERROR.getCode(), "服务端出错");
                }
            } else {
                weekendNoticeReadRepositoryService.noticeCountAdd(weekendNoticeReadCountDO);
            }
        } else {
            log.warn("redis锁获取超时,key:{}", lockKey);
            throw new ApiException(ErrorEnum.SERVER_ERROR.getCode(), "服务器繁忙,请稍后重试");
        }
    }
    Copy after login

    После получения блокировки, блокировка может быть получена после ожидания. В это время предыдущий поток, снявший блокировку, возможно, вставил данные, поэтому внутри блокировки данные все равно необходимо проверить еще раз. существует ли оно.
    Этот метод записи подходит для большинства сценариев написания, требующих уникальности.

    Избежание взаимоблокировки

    Как избежать взаимоблокировки? Самый простой и эффективный метод: **Не вставляйте замок внутрь замка.Короче, лучше всего использовать замок отдельно, а не как матрешку.
    Также обратите внимание на некоторые неявные блокировки, например, для баз данных.
    Транзакция A:

    • Вставьте [5,7] и вставьте блокировку намерения.

    • выберите для обновления обновление [100,150], блокировка пробела.
      Транзакция B:

    • select для обновления обновления [90,120], блокировка пробела.

    • Вставьте [4,6] и вставьте блокировку намерения.

    В это время в параллельном сценарии может случиться так, что A удерживает блокировку промежутка [5,7] и ожидает блокировки блокировки транзакции B[90,120]. Транзакция B тоже такая же, она зашла в тупик.
    **

    Кстати, давайте поговорим о распространенных проблемах в сценариях параллелизма

    Замешательство при чтении и записи

    При написании бизнес-кода и определении некоторых классов инструментов или кеша классов. Легко проявить неосторожность и вызвать подобные проблемы.
    Например, при построении статического кэша такие методы, как putIfAbsent в ConcurrentHashMap, не используются, и для его создания не используется блокировка. В результате поток ниже удаляется, как только поток выше его помещает, или кэш создается дважды.

    Redis или некоторые параллельные операции освобождают блокировки или ресурсы, не проверяя, удерживает ли их текущий поток.

    Это также упоминается в примере кода блокировки Redis.
    Поток A получает блокировку. В это время B и C ждут. Затем время выполнения A слишком велико, что приводит к автоматическому снятию блокировки из-за таймаута. В это время B получает блокировку и успешно выполняется. Затем, после того как A завершает выполнение, при снятии блокировки не оценивалось, удерживается ли она сама по себе, в результате чего блокировка, удерживаемая B, была удалена. В это время C снова получил блокировку, и в то же время был выполнен BC. время.

    The above is the detailed content of What are the knowledge points related to Java and Mysql locks?. For more information, please follow other related articles on the PHP Chinese website!

    Related labels:
    source:yisu.com
    Statement of this Website
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
    Popular Tutorials
    More>
    Latest Downloads
    More>
    Web Effects
    Website Source Code
    Website Materials
    Front End Template