← 返回首页
SpringBoot基础教程(二十六)
发表时间:2020-11-03 12:08:07
JPA+Mybatisplus双数据源

采用SpringDataJPA+Mybatisplus双数据源配置,既保留的JPA的纯正的OOP思想,同时也兼顾了Mybatis的灵活性。

项目结构图如下:

实现步骤如下:

1.配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.oracle</groupId>
    <artifactId>mybatisparent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mybatisparent</name>
    <description>Demo project for Spring Boot</description>
    <packaging>pom</packaging>

    <modules>
        <module>cruddemo</module>
        <module>primarykeydemo</module>
        <module>relationshipdemo</module>
        <module>pagerdemo</module>
        <module>wrapperdemo</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <junit.version>4.12</junit.version>
        <druid.version>1.1.10</druid.version>
        <lombok.version>1.18.8</lombok.version>
        <hutool.version>5.4.4</hutool.version>
        <swagger.version>2.9.2</swagger.version>
        <mybatis.version>3.4.0</mybatis.version>
    </properties>

    <dependencies>

        <!--以下是springboot的相关依赖开始-->
        <!--springboot jpa依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--springboot的 web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--支持热部署的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--springboot的测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--springboot解析配置类的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--以下是springboot的相关依赖结束-->

        <!--mysql驱动依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>${lombok.version}</version>
        </dependency>
        <!--alibaba数据连接池中间-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!--junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!--添加糊涂工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

        <!--添加mybatisplus依赖-->
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.配置application.yml

#yml格式配置文档范例
#服务器配置
server:
  #端口配置
  port: 8080
  #上下文
  servlet:
    context-path: /springbootdemo
#spring配置
spring:
  #显示自定义banner的配置
  output:
    ansi:
      enabled: always
  #数据源配置
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    #使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    maxActive: 500
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
  #JPA配置
  jpa:
    #控制台显示SQL脚本
    show-sql: true
    properties:
      hibernate:
        #配置使用支持事务的数据库方言
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        #格式化SQL代码
        format_sql: true
        #配置懒加载策略
        enable_lazy_load_no_trans: true
        #自动更新表结构
        hbm2ddl:
          auto: update
#自定义属性
usersystem:
  upload:
    path: \temp\upload
#logback配置
logging:
  #logback配置文档位置
  config: classpath:logback-spring.xml
  #日志输出级别
  level:
    com.oracle.service: trace
#mybatisplus配置
mybatis-plus:
  global-config:
    db-config:
      #配置mybatisplus的逻辑删除功能
      logic-delete-value: true  #默认删除的值
      logic-not-delete-value: false #默认未删除的值
      logic-delete-field: flag
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #在控制台输出调试信息

3.在启动类上添加@MapperScan扫描mybatis的mapper包。

@SpringBootApplication
@MapperScan("com.oracle.mapper")
public class SpringBootMybtisplusApplication {
    public static void main(String[] args) {
        AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
        new SpringApplicationBuilder(SpringBootMybtisplusApplication.class)//
                .main(SpringVersion.class) // 这个是为了可以加载 Spring 版本
                .bannerMode(Banner.Mode.CONSOLE)// 控制台打印
                .run(args);
    }

}

4.在config包下创建MybatisConfig配置类


@EnableTransactionManagement  //使乐观锁生效的一个注解
@Configuration
public class MybatisConfig {
    @Bean
    public MybatisPlusInterceptor optimisticLockerInnerInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

5.设所有实体类的基类

package com.oracle.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BaseEntity {

    @Version  //表示乐观锁字段
    @TableField(fill = FieldFill.INSERT)
    protected Integer version = 0; //乐观锁

    @TableField(fill = FieldFill.INSERT)
    @Column(length = 32)
    protected String createTime; //表示该记录的创建时间

    @TableField(fill = FieldFill.INSERT_UPDATE)
    @Column(length = 32)
    protected String modifyTime; //表示该记录的最后一次修改时间

    @TableLogic //表示是逻辑删除字段
    @TableField(fill = FieldFill.INSERT)
    protected boolean flag; //true,表示记录没有被删除,false表示该记录已经被删除。

}

6.在repository包下创建所有repository层的基类。

package com.oracle.repository;

import com.oracle.entity.BaseEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;

@NoRepositoryBean
public interface BaseRepository<T extends BaseEntity,ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor {

}

7.在service包下创建所有service层的基类

package com.oracle.service;

/*
* BaseService里面,封装了所有服务层的一些公共的操作,CRUD。
*
* */
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.oracle.entity.BaseEntity;
import com.oracle.repository.BaseRepository;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import java.io.Serializable;
import java.util.List;


/**
 *
 * @param <T> 表示具体的类型
 * @param <I> 表示该类型的主键类型
 * @param <R> 表示该类型的Repository层的实现类型。
 */
public interface BaseService<T extends BaseEntity, I extends Serializable, R extends BaseRepository<T, I>, M extends BaseMapper> {


    //1.下面是封装mybatisplus的BaseMapper里的方法,以后以mybatis结尾的都是调用mybatisplus的实现。

    int insertWithMybatis(T obj);

    int deleteByIdWithMybatis(I id);

    int updateByIdWithMybatis(T obj);

    T selectByIdWithMybatis(I id);

    List<T> selectListWithMybatis(Wrapper<T> wrapper);

    //针对所有的服务层都那些公共方法呢。
    //1.查询所有
    List<T> findAll();

    List<T> findAll(Example<T> example);

    //2.根据主键查询单个对象。
    T getOne(I id);

    //根据条件查询单个对象
    T getOne(Specification<T> var1);

    //3.查询分页记录。
    Page<T> findAllByPager(Pageable pageable);

    //4.添加单个对象
    T save(T obj);

    //5.修改单个对象
    T update(T obj);

    //6.根据主键删除单个对象。
    void deleteById(I id);

    //7.批量添加
    List<T> saveList(List<T> list);

    //8.批量删除
    void batchDelete(List<T> list);

}

8.在service.impl包下创建BaseService的实现类BaseServiceImpl.

package com.oracle.service.impl;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.oracle.entity.BaseEntity;
import com.oracle.repository.BaseRepository;
import com.oracle.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Optional;

public class BaseServiceImpl<T extends BaseEntity, I extends Serializable, R extends BaseRepository<T, I>, M extends BaseMapper> implements BaseService<T, I, R, M> {

    @Autowired
    protected R dao;
    @Autowired
    protected M mapper;

    @Transactional
    @Override
    public int insertWithMybatis(T obj) {
        return mapper.insert(obj);
    }

    @Transactional
    @Override
    public int deleteByIdWithMybatis(I id) {
        return mapper.deleteById(id);
    }

    @Transactional
    @Override
    public int updateByIdWithMybatis(T obj) {
        return mapper.updateById(obj);
    }

    @Transactional
    @Override
    public T selectByIdWithMybatis(I id) {
        return (T)mapper.selectById(id);
    }

    @Transactional
    @Override
    public List<T> selectListWithMybatis(Wrapper<T> wrapper) {
        return mapper.selectList(wrapper);
    }

    @Transactional
    @Override
    public List<T> findAll() {
        return dao.findAll();
    }


    @Override
    public List<T> findAll(Example<T> example) {
        return dao.findAll(example);
    }

    @Transactional
    @Override
    public T getOne(I id) {
        return dao.getOne(id);
    }

    @Transactional
    @Override
    public T getOne(Specification<T> var1) {
        Optional<T> option  = dao.findOne(var1);
        if(option.isPresent()){
            return (T)dao.findOne(var1).get();
        }else{
            return null;
        }
    }

    @Transactional
    @Override
    public Page<T> findAllByPager(Pageable pageable) {
        return dao.findAll(pageable);
    }

    @Transactional(rollbackOn = Exception.class)
    @Override
    public T save(T obj) {
        System.out.println("开始执行BaseServiceImpl-->save()");
        Date d = new Date();
        DateTime dt = DateTime.of(d);
        obj.setCreateTime(dt.toString("yyyy-MM-dd HH:mm:ss"));
        System.out.println("createTime is :"+obj.getCreateTime());
        obj.setModifyTime(dt.toString("yyyy-MM-dd HH:mm:ss"));
        obj.setFlag(false);
        return dao.save(obj);

    }

    @Transactional(rollbackOn = Exception.class)
    @Override
    public T update(T obj) {

        Date d = new Date();
        DateTime dt = DateTime.of(d);
        obj.setModifyTime(dt.toString("yyyy-MM-dd HH:mm:ss"));
        obj.setVersion(obj.getVersion()+1);
        return dao.save(obj);

    }

    @Transactional(rollbackOn = Exception.class)
    @Override
    public void deleteById(I id) {
        Optional<T> obj = dao.findById(id);
        T target = obj.get();
        target.setFlag(true);
        this.update(target);
        //dao.deleteById(id); //注意这个deleteById(id)是真正的物理删除。
    }

    @Override
    public List<T> saveList(List<T> list) {
        //设置插入时间
        for(T obj: list){
            Date d = new Date();
            DateTime dt = DateTime.of(d);
            obj.setCreateTime(dt.toString("yyyy-MM-dd HH:mm:ss"));
            obj.setFlag(false);
        }
        return dao.saveAll(list);
    }

    @Override
    public void batchDelete(List<T> list) {
        dao.deleteInBatch(list);
    }
}

这样我们就是实现JPA+Mybatisplus的双数据源整合。具体对某个实体类进行数据库操时,我仅需在repository,mapper,service和service.impl包下创建其对应的接口和实现类即可。

以Users实体类为例。

Users实体类继承自BaseEntity

public class Users extends BaseEntity implements Serializable,Cloneable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @TableId(type = IdType.AUTO) //注意:mybatisplus一定要添加这个注解,才能识别为主键。

    private Long uid; //
    //...省略
}

在mapper包下创建UsersMapper

public interface UsersMapper extends BaseMapper<Users> {

}

在repository包下创建UsersRepository

public interface UsersRepository extends BaseRepository<Users,Long> {

}

在service包下创建UsersService

public interface UsersService extends BaseService<Users,Long, UsersRepository, UsersMapper>{

}

在service.impl包下创建UsersServiceImpl


@Service
public class UsersServiceImpl extends BaseServiceImpl<Users,Long, UsersRepository,UsersMapper> implements UsersService {

}

下来编写测试类测试Users类的CRUD即可。