采用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即可。