# LDP本地数据库连接配置及使用

相关配置和使用案例，已经更新到脚手架工程 [**ldp-app-example**](http://gitlab.dev.shxrtech.com/ldp/ldp-app-example) 中。

## 一、数据库操作介绍

LDP框架中，应用通过RPC远程调用基础服务接口，执行数据库操作，也就是应用并不直接连接数据库，数据库所有的操作都是通过基础服务来执行。这样不用每个应用都进行数据库配置，并且数据库操作日志也能比较集中和统一。但是远程DAO调用也有缺点：

1、由于序列化和反序列化要求，所以应用开发在调用前，需要将本地实体类上传到基础服务。

2、应用端开发时，数据库操作日志不够详细。

3、所有的应用只能连接统一个数据库。

为了解决以上问题，所以在LDP中添加了本地DAO，由于不用数据库操作和连接都是本地处理，所以不需要上传实体类到基础服务，应用端开发时，日志也能更加详细，并且应用可以连接自己的数据库。

添加本地DAO后，远程DAO的使用依然不变，只是需要在原本的配置文件中添加ldp.ds.jpascan的配置，本地DAO也需要添加此配置。下面详细的讲解一下如何配置本地数据库连接，以及本地DAO的使用。

## 二、自动生成本地DAO代码

打开mcs管理后台，菜单 **快速开发** => **模型设计**，选中左侧模型树的用户业务模型，修改集成DAO方式为本地方式，点击下载按钮

![本地连接下载](../progress/67本地连接下载.png)

将下载的压缩包解压，并将实体类拷贝到样例工程的example-api模块的localmodel包中，将rest、和service代码拷贝到example-biz模块中

![拷贝代码](../progress/69拷贝代码.png)

拷贝sql文件夹下的example.sql脚本到example-startup模块中，目录是resource/db/mysql(如果是oracle数据库则拷贝到resource/db/oracle)，修改文件名为V1.0.1__example.sql。sql文件命名规范为 **大写字母V+版本号+两个英文下划线+sql文件名** ，此处文件的版本号为上一个版本号加一。

![拷贝sql文件](../progress/71拷贝sql文件.png)

启动脚手架工程后，项目会根据sql文件执行情况自动创建表。

![数据库建表](../progress/70数据库建表.png)

之后就可以直接请求接口进行数据的增删改查了。

## 三、手动配置本地连接(扩展)

### 3.1 添加依赖

这里用脚手架工程举例， 在example-biz模块 pom.xml中添加base-database依赖

```xml
 <dependency>
     <groupId>com.sinra.ldp</groupId>
     <artifactId>base-database</artifactId>
     <version>1.0-SNAPSHOT</version>
</dependency>
```

如果是使用oracle数据库，还需要在example-startup模块pom.xml中添加oracle驱动依赖(需要根据连接的数据库版本)，这里连接的是oracle11g。

```xml
 <dependency>
     <groupId>com.oracle</groupId>
     <artifactId>ojdbc6</artifactId>
     <version>11.2.0.3</version>
</dependency>
```

### 3.2 添加本地连接配置

在spring配置下新增datasource配置项以及jpa配置项，根据数据库类型和信息填上相应配置（mysql配置参考样例工程bootstrap-nacos.yml）：

```yml
  datasource:
    druid:
      username: xrtest
      password: xrtest123456
      url: jdbc:mysql://rm-uf6f7xh7p91q122hipo.mysql.rds.aliyuncs.com:3306/sinra_ldp_local_test?characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&useAffectedRows=true
      driver-class-name: com.mysql.jdbc.Driver
      type: com.alibaba.druid.pool.DruidDataSource
      initialSize: 5
      minIdle: 5
      maxActive: 20
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
  jpa:
    properties:
      hibernate:
        dialect: com.sinra.ldp.database.dialect.MySQL57GBKDialect
        current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
```

oracle数据库连接配置，主要需要修改的是url、driver-class-name、validationQuery、dialect（参照样例工程bootstrap-nacosoracle.yml文件）：

```yml
  datasource:
    druid:
      username: system
      password: 123456
      url: jdbc:oracle:thin:@129.204.125.84:1521/hportal
      driver-class-name: oracle.jdbc.driver.OracleDriver
      type: com.alibaba.druid.pool.DruidDataSource
      initialSize: 5
      minIdle: 5
      maxActive: 20
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: select 'x' from dual
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.Oracle10gDialect
        current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
```



在ldp配置下新增ds配置项，指定本地实体类扫描包名

```yml
  ds:
    jpascan: com.sinra.ldp.localmodel
```

### 3.3 本地DAO的使用

在service层的实现类上继承AbsLocalBaseDao，之后的使用与远程DAO的使用完全一致，参考示例工程的com.sinra.ldp.localdemo.service.impl.LdpAreaServiceImpl类。

```java
@Service
public class LdpAreaServiceImpl extends AbsLocalBaseDao implements LdpAreaService {

    @Override
    @AutoService
    public void add(LdpArea area) {
        genericDaoService.insert(area);
    }

    @Override
    public void add(List<LdpArea> areas) {
        genericDaoService.insertList(areas);
    }

    @Override
    public LdpArea find(String id) {
        return (LdpArea) genericDaoService.findById(LdpArea.class, id);
    }

    @Override
    @AutoService
    public void update(LdpArea area) {
        genericDaoService.dynamicUpdate(area);
    }

    @Override
    public void update(List<LdpArea> areas) {
         genericDaoService.update(areas);
    }

    @Override
    public void update(Class<LdpArea> clazz, Map<String, Object> updateFileds, Map<String, Object> whereParam) {
        genericDaoService.update(clazz, updateFileds, whereParam);
    }

    @Override
    public void delete(LdpArea area) {
        genericDaoService.delete(area);
    }

    @Override
    public void delete(List<LdpArea> list) {

        List<String> idList = list.stream().map(LdpArea::getId).collect(Collectors.toList());
        Map<String, Object> param = new HashMap<>(1);
        param.put("id", idList);
        genericDaoService.deleteList(LdpArea.class, param);


    }

    @Override
    public List<LdpArea> findList(Map<String, Object> paramMap) {
        return genericDaoService.findByHql(LdpArea.class, paramMap);
    }

    @Override
    public Pagination<LdpArea> findPage(Pagination paramPage, Map<String, Object> paramMap) {
        return genericDaoService.findPageByHql(LdpArea.class, paramMap, paramPage.getPageIndex(), paramPage.getPageSize());
    }



    /**
    * 双向，多对一关联实现
    */
    @AutoRelativeComputed(mode = RelativeMode.MTO, source = LdpCity.class,target = LdpArea.class, joinField = "city")
    public void addCityToArea(String id, Serializable entity){
            genericDaoService.dynamicUpdate(entity);
    }
    @AutoRelativeComputed(mode = RelativeMode.MTO, source = LdpCity.class,target = LdpArea.class, joinField = "city")
    public void removeCityFromArea(String id, Serializable entity){
            genericDaoService.delete(entity);
    }


}
```

如果不想使用继承的方式，也可以通过依赖注入将本地DAO引入

```java
//jdbc Dao
@Autowired
public ILocalJdbcDaoService jdbcDaoService;

//hibernate Dao
@Autowired
public ILocalGenericDaoService genericDaoService;
```

如果不清楚远程DAO有哪些接口，以及如何使用，请参考  [**Example样例工程开发文档.md**](Example样例工程开发文档.md))

