lock.md 6.7 KB
Newer Older
高洋's avatar
高洋 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
# 锁机制 

融租易提供两种锁机制, 满足项目上对数据并发修改的需求.

## 1.数据库锁
***
根据适当的参数进行物理锁定(数据库级锁),支持3种数据库:oracle,mysql,sqlserver。提供 API, 自动执行 sql
> 
   mysql,orcale 执行 select * from xxx where ... for update 

>  sqlserver 执行 select * from xxx with (ROWLOCK) where ...

>  都是数据库原生的锁机制



使用方式:
### 单数据源
在Java代码中,注入`DatabaseLockProvider`类,

```java

public class XXXServiceImpl {

  @Autowired
  private DatabaseLockProvider databaseLockProvider;
   
  public int update (XXX dto, ...){

    // 传入锁定对象,锁定数据库相关行
    databaseLockProvider.lock(dto);

    //...
  }
}

```
### 多数据源

在Java代码中,`自己创建DatabaseLockProvider类`,指定`dataSource`

```java

public class XXXServiceImpl {

  @Autowired
  @Qualifier("xxxDataSource")
  private DataSource dataSource;

  private DatabaseLockProvider databaseLockProvider;
  
  @Transactional(propagation = Propagation.REQUIRED)
  public int update (XXX dto, ...){
   
    databaseLockProvider = new DatabaseLockProvider(dataSource)
    // 传入锁定对象,锁定数据库相关行
    databaseLockProvider.lock(dto);
    //...
  }
}

```

> 事务提交以后,锁会自动释放

DatabaseLockProvider提供的接口

```java

//根据传入对象,自动加锁。
//确保bean上有@Table 注解,能自动解析出对应的表。 默认根据有@ID注解的字段进行加锁,确保id有值
public void lock(Object dto) 

//根据传入对象和自定义的where条件,自动加锁。
//传入类似 "name = ? and age = ?" 的条件语句,根据whereCondition,依次对应传入属性对应的值。
public void lock(Object dto, String whereCondition, Object... whereParameter)

// 可以自定义表名,不必传入dto
public void lock(String tableName, String whereCondition, Object... whereParameter)


```

## 2.分布式锁

 基于`redis`的锁,实现跨平台, 分布式锁

使用方式:
 
 1.根据实际配置的redis,修改配置文件`config.properties`
```properties
redisson.server.url=127.0.0.1:6379
#redissson.server.password=
```
> 支持`多节点`配置,按照如下规范配置
 
>redisson.server.url=\

>    127.0.0.1:6379,\

>    10.211.103.142:6379

>内部使用redisson提供的`RedLock`进行加锁

 2.在java代码中注入DistributedLockProvider

```java
public class XXXServiceImpl {

 @Autowired
 @Qualifier("distributeLockTemplate")
 private DistributedLockProvider distributedLockProvider;

 public int update (XXX dto, ...){
   
     //使用回调方式,执行自己的业务逻辑
     distributedLockProvider.lock(dto,new DistributedLockCallback<Object>() {
                @Override
                public Object process() {
                   //doSomething();
                   return null;
                })
     }
}
```

> 回调函数执行以后,锁都会自动释放

DistributedLockProvider提供的接口:
```java
    /**
     * 使用分布式锁,使用锁默认超时时间。
     *
     * @param lockKey
     *            加锁对象,确保有@ID属性,建议BaseDto
     * @param callback
     * @return    回调函数返回的内容
     */
    <T> T lock(Object lockKey, DistributedLockCallback<T> callback);

    /**
     * 使用分布式锁,使用锁默认超时时间。
     *
     * @param lockKey
     *            确保唯一
     * @param callback
     * @return    回调函数返回的内容
     */
    <T> T lock(String lockKey, DistributedLockCallback<T> callback);

    /**
     * 使用分布式锁。自定义锁的超时时间
     *
     * @param lockKey
     *            加锁对象,确保有@ID属性,建议BaseDto
     * @param callback
     * @param leaseTime
     *            锁超时时间。超时后自动释放锁。
     * @param timeUnit
     * @return    回调函数返回的内容
     */
    <T> T lock(Object lockKey, DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit);

    /**
     * 使用分布式锁。自定义锁的超时时间
     *
     * @param lockKey
     *            确保唯一
     * @param callback
     * @param leaseTime
     *            锁超时时间。超时后自动释放锁。
     * @param timeUnit
     * @return    回调函数返回的内容
     */
    <T> T lock(String lockKey, DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit);

    /**
     * 使用分布式锁,使用锁默认超时时间。
     *
     * @param lockKey
     *            确保唯一
     * @param callback
     * @return    回调函数返回的内容
     *
     * @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
     */
    <T> T tryLock(String lockKey, DistributedLockCallback<T> callback) throws Exception;

    /**
     * 使用分布式锁,使用锁默认超时时间。默认等待时间1秒
     *
     * @param lockKey
     *            加锁对象,确保有@ID属性,建议BaseDto
     * @param callback
     * @return    回调函数返回的内容
     *
     * @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
     */
    <T> T tryLock(Object lockKey, DistributedLockCallback<T> callback) throws Exception;

    /**
     * 使用分布式锁。自定义锁的超时时间
     *
     * @param lockKey
     *            加锁对象,确保有@ID属性,建议BaseDto
     * @param callback
     * @param waitTime
     *            获取锁等待时间,超过设置时间未获得锁则抛出异常
     * @param leaseTime
     *            锁超时时间。超时后自动释放锁。
     * @param timeUnit
     *            waitTime,leaseTime 时间单位
     * @return    回调函数返回的内容
     *
     * @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
     */
    <T> T tryLock(Object lockKey, DistributedLockCallback<T> callback, long waitTime, long leaseTime, TimeUnit timeUnit)
            throws Exception;

    /**
     * 使用分布式锁。自定义锁的超时时间
     *
     * @param lockKey
     *            确保唯一
     * @param callback
     * @param waitTime
     *            获取锁等待时间,超过设置时间未获得锁则抛出异常
     * @param leaseTime
     *            锁超时时间。超时后自动释放锁。
     * @param timeUnit
     *            waitTime,leaseTime 的时间单位
     * @return    回调函数返回的内容
     *
     * @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
     */
    <T> T tryLock(String lockKey, DistributedLockCallback<T> callback, long waitTime, long leaseTime, TimeUnit timeUnit)
            throws Exception;
    

```