SpringBoot+TkMybatis+Druid单数据源与多数据源配置

SpringBoot+TkMybatis+Druid单数据源与多数据源配置

环境与工具

开发工具:Intellij Idea
包管理工具:maven
JDK版本:1.8.0_201
SpringBoot版本:2.1.0.RELEASE
Druid版本:1.1.12
TkMybatis版本:1.0.5

第一步:使用idea创建springboot项目

使用spring initializr创建spring boot 项目
下一步
下一步
完成
项目结构

第二步:先配置下pom,添加所有用到的依赖




 org.apache.logging.log4j
 log4j
 2.11.2


 org.apache.logging.log4j
 log4j-to-slf4j
 2.10.0
 compile


 org.slf4j
 slf4j-log4j12
 1.7.25



 mysql
 mysql-connector-java



 com.alibaba
 druid
 1.1.12



 tk.mybatis
 mapper-spring-boot-starter
 2.0.4



 com.github.pagehelper
 pagehelper-spring-boot-starter
 1.2.10

第三步:先配置下log4j日志(^_−)☆

resource文件夹下创建log4j.properties

#日志文件路径
log.path.base=/data/log/demo
#log4j.rootLogger=等级,[appender名称],[appender名称]...
log4j.rootLogger=DALI_ROLLING_FILE,CONSOLE
#控制台输出日志:ConsoleAppender
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%l][%t]: %m%n
#文件按日回滚日志:DailyRollingFileAppender
log4j.appender.DALI_ROLLING_FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DALI_ROLLING_FILE.Threshold=DEBUG
log4j.appender.DALI_ROLLING_FILE.ImmediateFlush=true
log4j.appender.DALI_ROLLING_FILE.Append=true
log4j.appender.DALI_ROLLING_FILE.File=${log.path.base}/log.log
log4j.appender.DALI_ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.DALI_ROLLING_FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%l][%t]: %m%n

第四步:TkMybatis+Druid单数据源配置

1.修改resource/application.properties,添加数据源配置信息

demo.datasource.type=com.alibaba.druid.pool.DruidDataSource
demo.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
demo.datasource.url=jdbc:mysql://localhost:3306/demo
demo.datasource.username=root
demo.datasource.password=root
demo.datasource.maxActive:20
demo.datasource.initialSize:1
demo.datasource.maxWait:60000
demo.datasource.minIdle:1
demo.datasource.timeBetweenEvictionRunsMillis:60000
demo.datasource.minEvictableIdleTimeMillis:300000
demo.datasource.validationQuery:select 'x'
demo.datasource.testWhileIdle:true
demo.datasource.testOnBorrow:false
demo.datasource.testOnReturn:false
#如果是oracle 则可以设置为true  如果是mysql则设置false 分库分表较多的数据库,建议配置为false。
demo.datasource.poolPreparedStatements:false
demo.datasource.maxOpenPreparedStatements:20

2.新建config/datasource包,并创建DemoDataSourceConfig

package com.superychen.demo.config.datasource;
​
import com.alibaba.druid.pool.DruidDataSource;
​
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
​
import lombok.extern.slf4j.Slf4j;
import tk.mybatis.spring.annotation.MapperScan;
​
@Slf4j
@Configuration
//配置mapper扫描的包路径,注意MapperScan来源 tk.mybatis.spring.annotation.MapperScan
@MapperScan(basePackages = DemoDataSourceConfig.MAPPER_PACKAGE, sqlSessionFactoryRef = DemoDataSourceConfig.SESSION_FACTORY)
public class DemoDataSourceConfig {
​
 static final String SESSION_FACTORY = "demoSqlSessionFactory";
 private static final String DATASOURCE_NAME = "demoDataSource";
​
 //mapper类的包路径
 static final String MAPPER_PACKAGE = "com.superychen.demo.mybatis.mapper.demo";
 //自定义mapper的xml文件路径
 private static final String MAPPER_XML_PATH = "classpath:/mapper_diy/DemoMapper.xml";
 //数据源配置的前缀,必须与application.properties中配置的对应数据源的前缀一致
 private static final String DATASOURCE_PREFIX = "demo.datasource";
​
 @Primary
 @Bean(name = DATASOURCE_NAME)
 @ConfigurationProperties(prefix = DATASOURCE_PREFIX)
 public DruidDataSource druidDataSource() {
 return new DruidDataSource();
 }
​
 @Primary
 @Bean(name = SESSION_FACTORY)
 public SqlSessionFactory sqlSessionFactory() {
 final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
 sessionFactoryBean.setDataSource(druidDataSource());
 try {
 PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
 //自定义mapper的xml文件地址,当通用mapper提供的默认功能无法满足我们的需求时,可以自己添加实现,与mybatis写mapper一样
 sessionFactoryBean.setMapperLocations(resolver.getResources(MAPPER_XML_PATH));
 return sessionFactoryBean.getObject();
 } catch (Exception e) {
 log.error("配置demo的SqlSessionFactory失败,error:{}", e.getMessage());
 throw new RuntimeException(e.getMessage());
 }
 }
}

3.在resource文件夹下创建mapper_diy文件夹,用于存放自定义*Mapper.xml文件,创建DemoMapper.xml文件,同时在mybatis.mapper.demo包下创建DemoMapper

DemoMapper.xml

路径与DemoDataSourceConfig中MAPPER_XML_PATH的值要一致




 

DemoMapper.java

所在包与DemoDataSourceConfig中MAPPER_PACKAGE的值要一致

所在位置与DemoMapper.xml中mapper的namespace值一致

package com.superychen.demo.mybatis.mapper.demo;
​
import org.springframework.stereotype.Component;
​
@Component
public interface DemoMapper {
 //自定义方法在这里添加,与普通mybatis书写方式完全一样
}

到这里,其实已经可以使用了,在本地创建demo数据库,并添加user表如下

-- 创建数据库
CREATE DATABASE IF NOT EXISTS `demo`;
-- 创建user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(30) DEFAULT NULL,
 `age` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 

src/test/java/com/superychen/demo下创建如下测试类

package com.superychen.demo;

import com.superychen.demo.mybatis.mapper.demo.DemoMapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Test1 {

    @Autowired
    private DemoMapper demoMapper;

    @Test
    public void contextLoads() {
        demoMapper.insert();
        assert "superychen".equals(demoMapper.select());
    }

}

执行测试,测试通过

测试结果1

查看数据库

数据库1

4. 实际使用

使用TkMybatis的最主要目的是简化我们书写mapper的流程,我们只需要定义数据库表对应的实体类,并定义一个*Mapper接口继承其提供的Mapper接口,将实体类作为泛型类型,即可使用通用的Mapper操作数据库表方法,如增删改查等

以前一步创建的user表为例,在com.superychen.demo.mybatis.entity.demo包下创建User

package com.superychen.demo.mybatis.entity.demo;

import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Data
@Table(name = "user")
public class User {

    @Id
    private Integer id;
    private String name;
    private Integer age;

}

com.superychen.demo.mybatis.mapper.demo包下创建UserMapper接口

package com.superychen.demo.mybatis.mapper.demo;

import com.superychen.demo.mybatis.entity.demo.User;

import org.springframework.stereotype.Repository;

import tk.mybatis.mapper.common.Mapper;

@Repository
public interface UserMapper extends Mapper {
}

查看UserMapper的结构,发现有以下方法,具体方法使用请参考官网

UserMapper方法

src/test/java/com/superychen/demo下创建如下测试类

package com.superychen.demo;

import com.superychen.demo.mybatis.entity.demo.User;
import com.superychen.demo.mybatis.mapper.demo.UserMapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void contextLoads() {
        //所有
        List users = userMapper.selectAll();
        assert 1 == users.size();
        //插入
        User user = new User();
        user.setName("test2");
        user.setAge(18);
        userMapper.insert(user);
        //数量
        int count = userMapper.selectCountByExample(null);
        assert 2 == count;
        //删除
        userMapper.delete(user);
        //数量
        count = userMapper.selectCountByExample(null);
        assert 1 == count;
    }

}

执行测试,测试通过

UserMapper测试结果

该数据库下所有表都可以按UserMapper的方式进行配置与使用

如果需要在插入后获取自增的主键id,只需在id字段上添加@GeneratedValue(strategy = GenerationType.IDENTITY)注解,如下

package com.superychen.demo.mybatis.entity.demo;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Data
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;

}

src/test/java/com/superychen/demo下创建如下测试类

package com.superychen.demo;

import com.superychen.demo.mybatis.entity.demo.User;
import com.superychen.demo.mybatis.mapper.demo.UserMapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperAutoGenerateIdTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void contextLoads() {
        //插入
        User user = new User();
        user.setName("test2");
        user.setAge(18);
        userMapper.insert(user);
        assert 2 == user.getId();
    }

}

执行测试,测试通过

返回自增id测试结果

查看数据库

数据库数据

第五步:多数据源配置

多数据源配置只需仿照第一个数据源的方式同样配置即可,此处以新增Second数据库的数据源为例

1.修改resource/application.propertie,添加数据源配置信息

second.datasource.type=com.alibaba.druid.pool.DruidDataSource
second.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
second.datasource.url=jdbc:mysql://localhost:3306/second
second.datasource.username=root
second.datasource.password=root
second.datasource.maxActive:20
second.datasource.initialSize:1
second.datasource.maxWait:60000
second.datasource.minIdle:1
second.datasource.timeBetweenEvictionRunsMillis:60000
second.datasource.minEvictableIdleTimeMillis:300000
second.datasource.validationQuery:select 'x'
second.datasource.testWhileIdle:true
second.datasource.testOnBorrow:false
second.datasource.testOnReturn:false
#如果是oracle 则可以设置为true  如果是mysql则设置false 分库分表较多的数据库,建议配置为false。
second.datasource.poolPreparedStatements:false
second.datasource.maxOpenPreparedStatements:20

2.在config/datasource包下创建SecondDataSourceConfig

去掉druidDataSourcesqlSessionFactory上的@Primary注解

package com.superychen.demo.config.datasource;

import com.alibaba.druid.pool.DruidDataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import lombok.extern.slf4j.Slf4j;
import tk.mybatis.spring.annotation.MapperScan;

@Slf4j
@Configuration
@MapperScan(basePackages = SecondDataSourceConfig.MAPPER_PACKAGE, sqlSessionFactoryRef = SecondDataSourceConfig.SESSION_FACTORY)
public class SecondDataSourceConfig {

    static final String SESSION_FACTORY = "secondSqlSessionFactory";
    private static final String DATASOURCE_NAME = "secondDataSource";

    //mapper类的包路径
    static final String MAPPER_PACKAGE = "com.superychen.demo.mybatis.mapper.second";
    //自定义mapper的xml文件路径
    private static final String MAPPER_XML_PATH = "classpath:/mapper_diy/SecondMapper.xml";
    //数据源配置的前缀,必须与application.properties中配置的对应数据源的前缀一致
    private static final String DATASOURCE_PREFIX = "second.datasource";

    @Bean(name = DATASOURCE_NAME)
    @ConfigurationProperties(prefix = DATASOURCE_PREFIX)
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Bean(name = SESSION_FACTORY)
    public SqlSessionFactory sqlSessionFactory() {
        final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(druidDataSource());
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            //自定义mapper的xml文件地址,当通用mapper提供的默认功能无法满足我们的需求时,可以自己添加实现,与mybatis写mapper一样
            sessionFactoryBean.setMapperLocations(resolver.getResources(MAPPER_XML_PATH));
            return sessionFactoryBean.getObject();
        } catch (Exception e) {
            log.error("配置second的SqlSessionFactory失败,error:{}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

}

3.在resource/mapper_diy文件夹下创建SecondMapper.xml文件,同时在mybatis.mapper.second包下创建SecondMapper

SecondMapper.xml





SecondMapper

package com.superychen.demo.mybatis.mapper.second;

import org.springframework.stereotype.Component;

@Component
public interface SecondMapper {

    @Insert("INSERT INTO test(name,age) VALUES('superychen',22)")
    int insert();

    @Select("SELECT name FROM test LIMIT 1")
    String select();

}

4.测试

创建second数据库,并创建test

-- 创建数据库
CREATE DATABASE IF NOT EXISTS `second`;
-- 创建user表
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;     

src/test/java/com/superychen/demo下创建如下测试类

package com.superychen.demo;

import com.superychen.demo.mybatis.mapper.demo.DemoMapper;
import com.superychen.demo.mybatis.mapper.second.SecondMapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Test2 {

    @Autowired
    private SecondMapper secondMapper;

    @Test
    public void contextLoads() {
        secondMapper.insert();
        assert "superychen".equals(secondMapper.select());
    }

}

执行测试,测试通过

测试结果2

查看数据库

数据库数据

第六步:配置分布式事务支持

1.修改pom.xml文件,引入maven依赖


    org.springframework.data
    spring-data-commons
    2.1.2.RELEASE

2.在数据源配置类中添加如下代码

//DataSourceTransactionManager的名称,建议按照数据库的名称+TransactionManager驼峰命名的方式赋值
//如demo数据库,命名如下
private static final String TRANSACTION_MANAGER_NAME = "demoTransactionManager";

//主数据源添加@Primary注解,其它数据源不能添加
@Primary
@Bean(name = TRANSACTION_MANAGER_NAME)
public DataSourceTransactionManager transactionManager() {
    return new DataSourceTransactionManager(druidDataSource());
}

3.在config/datasource包下创建DataSourcesAutoConfiguration

package com.superychen.demo.config.datasource;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.annotation.Resource;

/**
 * 配置分布式事务管理
 */
@Configuration
@EnableTransactionManagement
@ConditionalOnBean({
        DemoDataSourceConfig.class,
        SecondDataSourceConfig.class,
        //新增数据源在这里添加
        //XxxDataSourceConfig.class
})
public class DataSourcesAutoConfiguration implements TransactionManagementConfigurer {

    @Resource
    private DemoDataSourceConfig demoDataSourceConfig;
    @Resource
    private SecondDataSourceConfig secondDataSourceConfig;
    //新增数据源在这里添加
    //@Resource
    //private XxxDataSourceConfig xxxDataSourceConfig;

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new ChainedTransactionManager(
                demoDataSourceConfig.transactionManager(),
                secondDataSourceConfig.transactionManager()
                //新增数据源在这里添加
                //xxxDataSourceConfig.xxxTransactionManager()
        );
    }

}

第七步:集成PageHelper

PageHelper的集成十分简单,示例代码

1.在数据库表(demo.user)中插入几条测试数据

INSERT INTO `user`(name,age) VALUES ('test3', '20');
INSERT INTO `user`(name,age) VALUES ('test4', '22');
INSERT INTO `user`(name,age) VALUES ('test5', '31');
INSERT INTO `user`(name,age) VALUES ('test6', '12');
INSERT INTO `user`(name,age) VALUES ('test7', '18');
INSERT INTO `user`(name,age) VALUES ('test8', '21');
INSERT INTO `user`(name,age) VALUES ('test9', '29');
INSERT INTO `user`(name,age) VALUES ('test10', '20');
INSERT INTO `user`(name,age) VALUES ('test11', '18');

数据库表中当前数据如下

数据库数据

2.在src/test/java/com/superychen/demo下创建如下测试类

package com.superychen.demo;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.superychen.demo.mybatis.entity.demo.User;
import com.superychen.demo.mybatis.mapper.demo.UserMapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PageHelperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void contextLoads() {

        PageHelper.startPage(1, 10);
        Page users = (Page) userMapper.selectAll();
        assert 11 == users.getTotal();
        assert 1 == users.getPageNum();
        assert 10 == users.getPageSize();
        assert 2 == users.getPages();
        assert 10 == users.getResult().size();

        PageHelper.startPage(2, 10);
        Page users2 = (Page) userMapper.selectAll();
        assert 11 == users2.getTotal();
        assert 2 == users2.getPageNum();
        assert 10 == users2.getPageSize();
        assert 2 == users2.getPages();
        assert 1 == users2.getResult().size();
    }

}

3.执行测试,测试通过

分页测试结果

总结

本篇文章所有代码见Github

你可能感兴趣的:(SpringBoot+TkMybatis+Druid单数据源与多数据源配置)