springboot+mybatis+druid+postgreSql案例

本文介绍了如何使用SpringBoot、MyBatis和Druid搭建数据库应用,强调了MyBatis的sql语句独立性以及Druid的数据库连接池监控功能。文章详细解析了项目的结构、配置文件,并提供了各个层的代码剖析,包括entity、Dao、service、controller以及Druid的配置和启动。

springboot+mybatis+druid+postgreSql/mysql 示例

简介

最近加入一个新的团队,发现团队开发的底层调用时通过jdbctemplate拼凑sql,不能说这个不好,但是对于开发效率来说,肯定没有orm框架使用来的6,jdbctemplate拼凑造轮子的话,大部分时间会花在轮子上,而且,压测的时候,sql的好坏,对业务代码的嵌入太深,综合考虑不划算。
其实,就现在世面主流构建来说,都是mybatis,这个主要是把sql语句独立出来了,做到了对sql语句的可控。
啥也不说,直接看项目结构:
项目结构

结构解析

application.yml:总体springboot的配置参数

spring:
  profiles:
    active: dev


# 服务端口
server:
  port: 9090
  servlet:
    context-path: /mptest


#数据库配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: org.postgresql.Driver
    url: jdbc:postgresql://192.168.100.103:5432/postgres
    username: postgres
    password: postgres
    druid:
      #初始化连接大小
      initial-size: 8
      #最小空闲连接数
      min-idle: 5
      #最大连接数
      max-active: 10
      #查询超时时间
      query-timeout: 6000
      #事务查询超时时间
      transaction-query-timeout: 6000
      #关闭空闲连接超时时间
      remove-abandoned-timeout: 1800
      filters: stat,config

#mybatis
mybatis:
  mapper-locations: classpath:com/examle/mpdemo/dao/*.xml

logback-mptest.xml: 配置日志(开发、测试、生产)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 文件输出格式 -->
    <property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n" />
    <!-- test文件路径 -->
    <property name="TEST_FILE_PATH" value="/logs/tianjun" />
    <!-- pro文件路径 -->
    <property name="PRO_FILE_PATH" value="/logs/tianjun" />

    <!-- 开发环境 -->
    <springProfile name="dev">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${PATTERN}</pattern>
            </encoder>
        </appender>

        <logger name="com.cmcc.tian.canal2kafka.common.ClusterCanal" level="debug"/>
        <logger name="com.cmcc.tian.canal2kafka.common.AbstractCanalClient" level="debug"/>
        <logger name="com.cmcc.tian.canal2kafka.common.CanalKafkaProducer" level="debug"/>

        <root level="info">
            <appender-ref ref="CONSOLE" />
        </root>
    </springProfile>

    <!-- 测试环境 -->
    <springProfile name="test">
        <!-- 每天产生一个文件 -->
        <appender name="TEST-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 文件路径 -->
            <file>${TEST_FILE_PATH}</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 文件名称 -->
                <fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!-- 文件最大保存历史数量 -->
                <MaxHistory>100</MaxHistory>
            </rollingPolicy>

            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
        </appender>

        <root level="info">
            <appender-ref ref="TEST-FILE" />
        </root>
    </springProfile>

    <!-- 生产环境 -->
    <springProfile name="prod">
        <appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${PRO_FILE_PATH}</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
                <MaxHistory>100</MaxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
        </appender>

        <root level="warn">
            <appender-ref ref="PROD_FILE" />
        </root>
    </springProfile>
</configuration>

druid-bean.xml: 开发发测试使用,监控druid,通过界面可以监控数据库连接池

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置_Druid和Spring关联监控配置 -->
    <bean id="druid-stat-interceptor"
        class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor"></bean>

    <!-- 方法名正则匹配拦截配置 -->
    <bean id="druid-stat-pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"
        scope="prototype">
        <property name="patterns">
            <list>
                <value>com.roncoo.education.mapper.*</value>
            </list>
        </property>
    </bean>

    <aop:config proxy-target-class="true">
        <aop:advisor advice-ref="druid-stat-interceptor"
            pointcut-ref="druid-stat-pointcut" />
    </aop:config>

</beans>

m-p-demo\src\main\resources\com\example\mpdemo\dao\UserDao.xml:这是Dao的相关mapper类的映射集合,idea中有个问题,在resources资源文件中,必须更Dao类路径取名一致,以便和Dao类编译在一起(不然会报mapper找不到绑定类的坑)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.mpdemo.dao.UserDao" >
    <insert id="userInsert" parameterType="com.example.mpdemo.entity.User">
        insert into tianjun_test (id,name,age) values (#{user.id},#{user.name},#{user.age})
    </insert>

    <select id="queryById" resultType="com.example.mpdemo.entity.User">
        select * from tianjun_test where id = #{id}
    </select>
</mapper>

代码剖析

还是按照entity-dao-servicej-controller的结构

entity层

package com.example.mpdemo.entity;

/**
 * @Description: 用户实体
 * @Author: tianjun
 * @CreateTime: 2018-04-02 13:22
 * @Editor: tianjun
 * @UpdateTime: 2018-04-02 13:22
 * @Company: netposa
 */
public class User {
    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

Dao层

package com.example.mpdemo.dao;

import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * @Description: 用户相关操作
 * @Author: tianjun
 * @CreateTime: 2018-04-02 13:25
 * @Editor: tianjun
 * @UpdateTime: 2018-04-02 13:25
 * @Company: netposa
 */
@Mapper
public interface UserDao {
    Integer userInsert(@Param("user") User user);

    User queryById(@Param("id") Integer id);
}

service层

IUserService

package com.example.mpdemo.service;

import com.example.mpdemo.entity.User;

/**
 * @Description: 用户业务接口
 * @Author: tianjun
 * @CreateTime: 2018-04-02 13:38
 * @Editor: tianjun
 * @UpdateTime: 2018-04-02 13:38
 * @Company: netposa
 */
public interface IUserService {
    Integer userInsert(User user);

    User queryById(Integer id);
}

UserServcie

package com.example.mpdemo.service.impl;

import com.example.mpdemo.dao.UserDao;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description: 用户业务类
 * @Author: tianjun
 * @CreateTime: 2018-04-02 13:37
 * @Editor: tianjun
 * @UpdateTime: 2018-04-02 13:37
 * @Company: netposa
 */
@Service
public class UserService implements IUserService {
    @Autowired
    private UserDao userDao;

    @Override
    public Integer userInsert(User user) {
        return userDao.userInsert(user);
    }

    @Override
    public User queryById(Integer id) {
        return userDao.queryById(id);
    }
}

controller层

package com.example.mpdemo.controller;

import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.IUserService;
import org.apache.ibatis.annotations.ResultType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description: 用户接口类
 * @Author: tianjun
 * @CreateTime: 2018-04-02 13:42
 * @Editor: tianjun
 * @UpdateTime: 2018-04-02 13:42
 * @Company: netposa
 */
@RestController
@RequestMapping("/tt")
public class UserController {
    @Autowired
    private IUserService userService;

    @PostMapping("/userInsert")
    public Integer userInsert(User user){
        return userService.userInsert(user);
    }

    @PostMapping("/queryById")
    public User queryById(Integer id){
        return userService.queryById(id);
    }
}

协助层

DruidConfiguration: 集成druid

package com.example.mpdemo.utils.configuration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class DruidConfiguration {

    @ConditionalOnClass(DruidDataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = true)
    static class Druid extends DruidConfiguration {
        @Bean
        @ConfigurationProperties("spring.datasource.druid")
        public DruidDataSource dataSource(DataSourceProperties properties) {
            DruidDataSource druidDataSource = (DruidDataSource) properties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
            DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
            String validationQuery = databaseDriver.getValidationQuery();
            if (validationQuery != null) {
                druidDataSource.setValidationQuery(validationQuery);
            }
            return druidDataSource;
        }
    }
}

MyBatisConfig: 集成mybatis

package com.example.mpdemo.utils.configuration;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @Description: springboot集成mybatis的基本入口 1)创建数据源 2)创建SqlSessionFactory
 * @Author: tianjun
 * @CreateTime: 2018-04-02 14:56
 * @Editor: tianjun
 * @UpdateTime: 2018-04-02 14:56
 * @Company: netposa
 */
@Configuration // 该注解类似于spring配置文件
@MapperScan(basePackages = "com.example.mpdemo.dao") // 扫描Dao文件
@EnableTransactionManagement //支持事务注解
public class MyBatisConfig implements TransactionManagementConfigurer {

    @Autowired
    DataSource dataSource;//默认配置文件中的数据源

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(dataSource);// 指定数据源(这个必须有,否则报错)
        return fb.getObject();
    }

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }

}

***DruidWebStatFilter:***druid的接界面配置的过滤器

package com.example.mpdemo.utils.filter;

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

import com.alibaba.druid.support.http.WebStatFilter;

/**
 * @author
 */
@WebFilter(filterName = "druidWebStatFilter", urlPatterns = "/*", initParams = { @WebInitParam(name = "exclusions", value = "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*") })
public class DruidWebStatFilter extends WebStatFilter {

}

***DruidStatViewServlet:***druid界面配置(路径、用户名和密码等)

package com.example.mpdemo.utils.servlet;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.alibaba.druid.support.http.StatViewServlet;

/**
 *
 * @author
 */
@WebServlet(urlPatterns = { "/druid/*" }, initParams = { @WebInitParam(name = "loginUsername", value = "admin"), @WebInitParam(name = "loginPassword", value = "admin") })
public class DruidStatViewServlet extends StatViewServlet {

    private static final long serialVersionUID = 1L;

}

启动

MPDemoApplication:放在最外层,以便能扫描到所有的带有注解的包

package com.example.mpdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ImportResource;
@ServletComponentScan
@SpringBootApplication
@ImportResource(locations = {"classpath:druid-bean.xml"})
public class MPDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MPDemoApplication.class, args);
    }
}
<think>嗯,用户的问题是关于在Spring Boot项目中集成MyBatis-Plus、DruidPostgreSQL来实现多数据源的支持。我需要仔细分析这个问题,确保回答结构清晰,步骤正确,并且符合用户提到的引用内容。 首先,用户提到了MyBatis-Plus和Druid,以及多数据源的整合。根据引用[2],dynamic-datasource启动器是关键,它支持多数据源的切换、分组和事务处理。我需要确认这个库的依赖和配置方式。记得在步骤中提到添加dynamic-datasource-spring-boot-starter依赖,以及如何配置多个数据源,包括主从或者其他分组。 然后,Druid的连接池集成。用户可能希望知道如何将Druid与dynamic-datasource结合使用。引用[2]提到Druid的快速集成,可能需要添加Druid的依赖,并在配置中指定使用Druid作为数据源类型。同时,敏感信息加密部分,比如使用ENC(),但用户的问题里没有提到加密,可能需要作为可选步骤,或者在注意事项里提到。 PostgreSQL的配置部分,需要在每个数据源的配置中指定驱动类(org.postgresql.Driver)和JDBC URL格式。确保用户知道如何正确填写这些信息,尤其是不同的数据库名称或主机端口的情况。 接下来是MyBatis-Plus的集成。用户需要配置@MapperScan注解,指定扫描路径,并且根据引用[1],MyBatis-Plus的分页插件可能需要配置。在dynamic-datasource中,可能需要将分页插件注册为Bean,确保分页功能正常。 多数据源的切换方面,引用[2]提到可以使用@DS注解,在服务层的方法上指定数据源名称或组名。需要说明如何在不同层使用注解,比如在Service方法上加@DS("slave"),或者使用负载均衡策略。 另外,用户可能需要处理事务管理。根据dynamic-datasource的文档,多数据源事务需要使用@DSTransactional注解,这里需要提醒用户注意事务的边界和分布式事务的处理,如果有需求的话,可以集成Seata,如引用[2]中提到的。 在代码示例部分,需要给出具体的配置类,比如数据源配置、MyBatis-Plus的配置类,以及Service层的使用示例。确保代码中的占位符(如${spring.datasource.dynamic.primary})与实际配置对应,并说明每个部分的作用。 可能还需要提到一些常见问题,比如依赖冲突、配置错误、动态增减数据源的方法,以及如何监控Druid的数据源性能。这些都是在实际开发中容易遇到的坑,提前说明可以帮助用户避免。 最后,相关问题部分,要考虑用户可能的后续问题,比如动态增减数据源、主从同步延迟、加密配置等,这些都在引用[2]中有涉及,可以作为相关问题提出,引导用户进一步学习。 总结一下,回答的结构应该是:环境准备、依赖添加、配置文件编写、数据源配置类、MyBatis-Plus配置、使用示例、注意事项,以及相关问题。需要确保每一步都清晰,并引用正确的文档和已有引用内容,比如dynamic-datasource的文档链接和功能点。</think>### Spring Boot整合MyBatis-Plus、DruidPostgreSQL多数据源教程 #### 一、环境准备 1. 创建Spring Boot项目(版本≥2.7.x) 2. PostgreSQL数据库(需提前创建多个数据库实例) #### 二、添加依赖 ```xml <!-- MyBatis-Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <!-- dynamic-datasource多数据源核心 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- PostgreSQL驱动 --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <!-- Druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.16</version> </dependency> ``` #### 三、配置文件(application.yml) ```yaml spring: datasource: dynamic: primary: master # 设置默认数据源 strict: false druid: # 公共连接池配置 initial-size: 5 max-active: 20 datasource: master: url: jdbc:postgresql://localhost:5432/db_master username: postgres password: 123456 driver-class-name: org.postgresql.Driver type: com.alibaba.druid.pool.DruidDataSource slave1: url: jdbc:postgresql://localhost:5432/db_slave1 username: postgres password: 123456 driver-class-name: org.postgresql.Driver type: com.alibaba.druid.pool.DruidDataSource ``` #### 四、数据源配置类 ```java @Configuration @MapperScan(basePackages = "com.example.mapper") public class DataSourceConfig { @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } } ``` #### 五、使用示例 ```java // Service层通过@DS切换数据源 @Service public class UserServiceImpl implements UserService { @DS("master") // 指定主库 public void addUser(User user) { // 数据库操作 } @DS("slave1") // 指定从库 public User getUser(Long id) { // 数据库操作 } } ``` #### 六、注意事项 1. 事务管理需使用`@DSTransactional`注解[^2] 2. 动态增减数据源可通过`DynamicRoutingDataSource`类操作 3. Druid监控页面可通过`http://localhost:8080/druid`访问 4. 多数据源事务建议使用Seata分布式方案[^2] #### 七、验证方法 ```java @SpringBootTest public class DataSourceTest { @Autowired private UserMapper userMapper; @Test @DS("slave1") public void testSlaveQuery() { User user = userMapper.selectById(1L); Assert.notNull(user, "从库查询失败"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值