# 锁机制 

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

## 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;
    

```
