用Java实现MySQL分布式锁

一.前期准备工作

  1. 我们需要连接MySQL数据库,我们需要连接数据库的jar包和数据源,这里我用的是c3p0数据源。
  2. 持久层我们使用mybatis框架。
  3. 我们在spring配置文件里配置好数据源以及mybatis相关的配置。
 <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="initialSize" value="30"></property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"></property>
        <!--配置mapper接口的具体位置-->
        <property name="basePackage" value="demo"></property>
    </bean>

    <!--配置sessionFactoryBean,-->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--配置mapper.xml的具体位置-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="mapperLocations" value="demo/*.xml"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>
  1. 数据库里面建好相应的锁表,表的信息如下
    在这里插入图片描述

二.代码编写阶段

我们模仿创建订单的场景,编写对应的OrderMapper.xml

	<insert id="insertOrder" parameterType="Integer">
        update method_lock set method_name='createOrder' where id=#{id}
    </insert>
	
	**注意此处的 for update 是锁住表的关键**
    <select id="queryLock" parameterType="Integer" resultType="String">
        select method_name from method_lock where id=#{id} for update
    </select>

    <delete id="deleteLock" parameterType="Integer">
        update method_lock set method_name='' where id =#{id}
    </delete>

    <update id="incLockCount" parameterType="Integer">
        update lock_count set lockcount=lockcount+1 where id=#{id}
    </update>

对应的OrderMapper接口

	void insertOrder(@Param("id") Integer id);

    void deleteLock(@Param("id") Integer id);

    String queryLock(@Param("id") Integer id);

创建对应的消费者ConsumerService,lock方法是消费者去获取锁,delete方法是消费者去删除使用过的锁

	@Transactional
    public boolean lock(){
        String method_name=orderMapper.queryLock(1);
        if(method_name==null||"".equals(method_name)){
            orderMapper.insertOrder(1);
            return true;
        }
        return false;
    }

    @Transactional
    public void deleteLock(){
        orderMapper.deleteLock(1);
    }

创建对应的消费者Consumer去创建订单

public void createOrder(){
        long endtime = System.currentTimeMillis()+3000;
        while(System.currentTimeMillis()<endtime){
            if(consumerService.lock()){
            	//这里可以写你想要做的事。
                consumerService.deleteLock();
                break;
            }
            //如果没有获取到锁,等待100毫秒再去获取
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

测试阶段,创建100个消费者同时去创建订单

public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring-config.xml");
        for(int i=0;i<100;i++){
            new Thread(new Consumer("consumer:"+i)).start();
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以利用MySQL的行锁和事务特性来实现分布式锁。以下是一种基于MySQL实现分布式锁的方案: 1. 创建一个名为`distributed_locks`的表,包含两个字段:`key`和`value`。其中`key`表示锁的名称,`value`表示锁的状态(0表示未锁定,1表示已锁定)。 2. 在Java中,创建一个`DistributedLock`类,该类包含以下方法: ``` public class DistributedLock { private static final String LOCK_KEY = "lock_name"; private static final String LOCK_VALUE = "1"; private Connection connection; public DistributedLock(Connection connection) { this.connection = connection; } public boolean lock() throws SQLException { boolean locked = false; connection.setAutoCommit(false); PreparedStatement stmt = connection.prepareStatement("SELECT * FROM distributed_locks WHERE `key` = ? FOR UPDATE"); stmt.setString(1, LOCK_KEY); ResultSet rs = stmt.executeQuery(); if (rs.next()) { int value = rs.getInt("value"); if (value == 0) { PreparedStatement updateStmt = connection.prepareStatement("UPDATE distributed_locks SET `value` = ? WHERE `key` = ?"); updateStmt.setString(1, LOCK_VALUE); updateStmt.setString(2, LOCK_KEY); int updated = updateStmt.executeUpdate(); if (updated == 1) { locked = true; } } } else { PreparedStatement insertStmt = connection.prepareStatement("INSERT INTO distributed_locks (`key`, `value`) VALUES (?, ?)"); insertStmt.setString(1, LOCK_KEY); insertStmt.setString(2, LOCK_VALUE); int inserted = insertStmt.executeUpdate(); if (inserted == 1) { locked = true; } } connection.commit(); connection.setAutoCommit(true); return locked; } public void unlock() throws SQLException { connection.setAutoCommit(false); PreparedStatement stmt = connection.prepareStatement("UPDATE distributed_locks SET `value` = ? WHERE `key` = ?"); stmt.setString(1, "0"); stmt.setString(2, LOCK_KEY); stmt.executeUpdate(); connection.commit(); connection.setAutoCommit(true); } } ``` 3. 以上代码中的`lock()`方法实现了获取分布式锁的逻辑。该方法会在`distributed_locks`表中查询指定锁的状态,如果该锁未被占用,则将其状态更新为已占用,并返回`true`表示获取锁成功。否则,返回`false`表示获取锁失败。 4. 上述代码中的`unlock()`方法实现了释放分布式锁的逻辑。该方法会将指定锁的状态更新为未占用。 5. 在业务代码中,可以使用以下方式来获取和释放分布式锁: ``` Connection conn = ...; // 获取数据库连接 DistributedLock lock = new DistributedLock(conn); try { if (lock.lock()) { // 获取锁成功,执行业务逻辑 } else { // 获取锁失败,执行其他逻辑 } } finally { lock.unlock(); conn.close(); } ``` 需要注意的是,以上代码仅提供了一种基于MySQL实现分布式锁的思路,并不是最佳实践。在实际应用中,需要考虑更多的因素,例如锁超时、死锁等问题。因此,建议在使用分布式锁时,结合具体场景和实际需求,选择适合自己的方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值