多线程并发同一个表问题

现有数据库开发过程当中对事务的控制、事务锁、行锁、表锁的发现缺少必要的方法和手段,经过如下手段能够丰富咱们处理开发过程当中处理锁问题的方法。
For Update和For Update of使用户可以锁定指定表或表的数据行这个功能在实际应用中具备很重要的意义,特别对于多用户多线程处理中如要先获取数据经过判断在去更新数据(这中间不容许数据发生变化)的时候这个SQL功能是惟一最佳的选择。
此外,为了解决由于For Update而引发的死锁问题,Oracle提供了select...[for update [of tab.col]] [nowait]功能,这个功能使得在执行select...for update前先检查所申请的行、表资源是否可用,若是可用则加写锁,不然直接返回Ora-54错误。这个功能也用很好的应用价值,在多线程中判断资源的可用性方面将发挥做用。java

Table For Update For Update of A.Id
A 1.有where条件时,锁定条件中指定的数据行(行级封锁);
2.无where条件是,锁定表A(表级封锁)。 1.有where条件时,锁定条件中指定的数据行(行级封锁);
2.无where条件是,锁定表A(表级封锁)。
A,B 直接封锁A,B表(表级封锁) 1.有where条件时,封锁where条件中知足条件的A表的数据行(行级封锁),B表不锁定;
2.无where条件是,锁定A表(表级锁),B表不锁定。sql

对比发现,发现对于单表来讲For Update和For Update of效果同样,只有在多表查询时产生差别,这个差别在于For Update of使用户可以锁定多表中的指定表或表的数据行。数据库

以代码为例:express

背景:有4台线上任务服务器,处理同一个表中的数据,为了不引发数据读写混乱,采用了for update的方式来加锁服务器

@SuppressWarnings("unchecked")多线程

public List<BizExpressDailyDO> fetchSomeBizExpressDaily(final String serverIp, final int some)
                                                                                              throws DataAccessException {
    return (List<BizExpressDailyDO>) new TransactionTemplate(transactionManager).execute(new TransactionCallback() {

        @SuppressWarnings("rawtypes")
        public Object doInTransaction(TransactionStatus status) {
            // 取得锁的钥匙
            getSqlMapClientTemplate().queryForObject("MS-SELECT-ACTION-LOCK-BY-LOCK-NAME-FOR-UPDATE", "bizexpress");

            List<BizExpressDailyDO> bizexpresses = getSqlMapClientTemplate().queryForList(
                                                                                          "MS-FIND-SOME-BIZ-EXPRESS",
                                                                                          Integer.valueOf(some));

            Map param = new HashMap();
            param.put("serverIp", serverIp);
            param.put("some", Integer.valueOf(some));
            getSqlMapClientTemplate().update("MS-UPDATE-SOME-BIZ-EXPRESS", param);

            return bizexpresses;
        }
    });
}

上面中的MS-SELECT-ACTION-LOCK-BY-LOCK-NAME-FOR-UPDATE,
<!-- 锁定某个ACTION的纪录 -->并发

<select id="MS-SELECT-ACTION-LOCK-BY-LOCK-NAME-FOR-UPDATE" parameterClass="java.lang.String">
    <![CDATA[
        SELECT * FROM ACTION_LOCK WHERE LOCK_NAME = #value# FOR UPDATE
    ]]>
</select>

通这这段代码对表加锁,这样其它线程当执行到此处时会处于等待状态,直到表锁释放,这样能够限制其它线程访问biz_express_daily表执行下面sql语句fetch

<!-- 挑选出一些纪录等待更新 -->线程

<select id="MS-FIND-SOME-BIZ-EXPRESS" resultMap="RM-BIZ-EXPRESS-DAILY">
    <![CDATA[
        SELECT * FROM BIZ_EXPRESS_DAILY WHERE SERVER_IP = '0.0.0.0' AND ROWNUM < #some#
    ]]>
</select>

<!-- 更新一些纪录的server_ip -->code

<update id="MS-UPDATE-SOME-BIZ-EXPRESS">
    <![CDATA[
        UPDATE BIZ_EXPRESS_DAILY SET SERVER_IP = #serverIp#, GMT_MODIFIED = SYSDATE WHERE SERVER_IP = '0.0.0.0' AND ROWNUM < #some#
    ]]>
</update>

从而有效的解决了多线程并发数据库表的问题。

相关文章
相关标签/搜索