Spring Boot数据库操作原理及整合druid数据源和mybatis

在Spring Boot中如果需要访问数据库,我需要导入以下两个依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring‐boot‐starter‐jdbc</artifactId>
	</dependency>
	
	<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql‐connector‐java</artifactId>
	<scope>runtime</scope>
</dependency>

之后在配置文件中配置好数据库:

spring:
 datasource:
  username: root
  password: 123456
  url: jdbc:mysql://192.168.15.22:3306/jdbc
  driver‐class‐name: com.mysql.jdbc.Driver

之后直接使用JdbcTemplate来操作数据库即可,默认是用org.apache.tomcat.jdbc.pool.DataSource作为数据源。那么这些是如何完成的呢?可以接着往下看。注意:我使用的是Spring Boot 2.1.7版本,不同版本可能源码有不同。

在Spring Boot的autoconfigure包下有一个叫jdbc的包,其中帮我们做好了数据库的配置,可以查看DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池;可以使用spring.datasource.type指定自定义的数据源类型,如果没有指定的话,就使用org.apache.tomcat.jdbc.pool.DataSource数据源了,默认支持org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource这些数据源。在该文件的最后还有这么一段:

	/**
	 * Generic DataSource configuration.
	 */
	@Configuration
	@ConditionalOnMissingBean(DataSource.class)
	@ConditionalOnProperty(name = "spring.datasource.type")
	static class Generic {

		@Bean
		public DataSource dataSource(DataSourceProperties properties) {
			return properties.initializeDataSourceBuilder().build();
		}

	}

它的意思是,如果我们配置的spring.datasource.type不是上面任意一个数据源,就使用这种方式创建数据源,其原理是使用DataSourceBuilder创建数据源,利用反射创建type指定的数据源,并且绑定相关属性。此外,Spring Boot还可以帮我自动运行建表和数据创建.sql脚本。这又是如何实现的呢?接着往下看。

在jdbc包下还有一个DataSourceInitializerInvoker类,它继承了ApplicationListener,所以它是一个监听器,监听什么呢?这个类的注释中给出了解释:

/**
 * Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
 * {@link InitializingBean#afterPropertiesSet()} and {@literal data-*.sql} SQL scripts on
 * a {@link DataSourceSchemaCreatedEvent}.
 *
 * @author Stephane Nicoll
 * @see DataSourceAutoConfiguration
 */

也就是说,如果InitializingBean#afterPropertiesSet()发生时运行schema-.sql脚本,发生DataSourceSchemaCreatedEvent时运行data-.sql 脚本。所以如果当你需要在程序运行的时候建表,直接在classpate下创建schema-.sql建表文件即可。如果你还需要插入数据,直接在classpate下创建data-.sql插入数据文件即可。不过Spring Boot也支持你直接在数据库中声明schema文件的位置和名称,如:

Spring:
 datasource:
  schema:
   ‐ classpath:department.sql

最后需要注意的是,如果你在classpate下创建了schema-*.sql建表文件,那么每次启动程序都会运行这个脚本,所以当你不需要建表的时候,注意要及时删除。

最后,在JdbcTemplateAutoConfiguration文件还自动帮我创建好了JdbcTemplate,使用的时候直接自动注入即可:

@Bean
@Primary
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate() {
	JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
	JdbcProperties.Template template = this.properties.getTemplate();
	jdbcTemplate.setFetchSize(template.getFetchSize());
	jdbcTemplate.setMaxRows(template.getMaxRows());
	if (template.getQueryTimeout() != null) {
		jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
	}
	return jdbcTemplate;
}

以上就是Spring Boot默认的数据访问时的配置了。

在实际开发的时候,我们很少使用org.apache.tomcat.jdbc.pool.DataSource作为我们的数据源,这里我给出之前提到过的切换数据源的操作,这里我切换到druid数据源,这个数据源有很方便的监控的功能,读者可以作为参照。

首先我们需要在依赖中引入druid数据源:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.8</version>
</dependency>

而后,指定我们的数据源类型,并且进行数据源的配置:

spring:
  datasource:
#   数据源基本配置
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ssm_crud
    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
#   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙  
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true  
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  

这里需要注意的时,这里有很多属性的配置是无法自动配置到DataSourceProperties中的。也就无法被我们的druid数据源使用到,这里我们可以编写我们自己的配置类:

package com.chester.webdemo.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DruidConfig {
	//这个注解引入我们在上面yml文件中配置的参数到DruidDataSource数据源中
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid(){
        return new DruidDataSource();
    }

    //配置Druid监控
    //1.配置一个管理后台的Servlet
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet());
        Map<String, String> initParams = new HashMap<>();

        //设置后台监控的登陆用户名
        initParams.put("loginUsername", "admin");
        //设置后台监控的登陆密码
        initParams.put("loginPassword", "123456");
        //设置允许访问的地址
        initParams.put("allow", "");
        //设置不允许访问的地址
        initParams.put("deny", "192.168.15.21");

        bean.setInitParameters(initParams);
        return bean;
    }

    //2.配置一个web监控Filter
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());
        Map<String, String> initParams = new HashMap<>();
        //设置不拦截的路径
        initParams.put("exclusions", "*.js, *.css, /druid/*");
        bean.setInitParameters(initParams);
        //设置监控的路径
        bean.setUrlPatterns(Arrays.asList("/*"));
        return bean;
    }
}

如果这个数据源被注入到了容器中,上面说的org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource这些数据源就不会继续注入了,因为这些数据源在自动注入容器的时候有@ConditionalOnMissingBean(DataSource.class)这样一个注解。这个时候我们可以访问http://localhost:8081/druid 进入druid的监控界面,填入我们配置好的用户名,密码即可。

最后我们整合mybatis,首先我们需要引入mybatis:

 <dependency>
     <groupId>org.mybatis.spring.boot</groupId>
     <artifactId>mybatis-spring-boot-starter</artifactId>
     <version>1.3.1</version>
 </dependency>

从名字中我们可以知道,这个包并非Spring官方出品,因为Spring的名字更像是这样spring‐boot‐starter‐*。这个包实际上是mybatis出的适配Spring Boot的。接下来的工作就很简单了,因为Spring Boot已经帮我配置好了,这里依旧给出使用mybatis的示例:

1. 首先创建实体类:

package com.chester.springboot.bean;

public class Department {

    private Integer id;
    private String departmentName;

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

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    public Integer getId() {
        return id;
    }

    public String getDepartmentName() {
        return departmentName;
    }
}

2. 创建mapper

package com.chester.springboot.mapper;

import com.chester.springboot.bean.Department;
import org.apache.ibatis.annotations.*;


//指定这是一个操作数据库的mapper
@Mapper
public interface DepartmentMapper {

    @Select("select * from department where id=#{id}")
    public Department getDeptById(Integer id);

    @Delete("delete from department where id=#{id}")
    public int deleteDeptById(Integer id);

	//Options的注解的意思是插入后将生成的id封装到department中,方便我们之后的使用
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into department(department_name) values(#{departmentName})")
    public int insertDept(Department department);

    @Update("update department set department_name=#{departmentName} where id=#{id}")
    public int updateDept(Department department);
}

这里@Mapper也可以转换为直接在主类上写@MapperScan(value = “com.chester.springboot.mapper”)这个注解,这样一来com.chester.springboot.mapper这个包下的接口就会自动转换为mapper。

最后编写cotroller使用即可

package com.chester.springboot.controller;

import com.atguigu.springboot.bean.Department;
import com.atguigu.springboot.bean.Employee;
import com.atguigu.springboot.mapper.DepartmentMapper;
import com.atguigu.springboot.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DeptController {

    @Autowired
    DepartmentMapper departmentMapper;

    @GetMapping("/dept/{id}")
    public Department getDepartment(@PathVariable("id") Integer id){
        return departmentMapper.getDeptById(id);
    }

    @GetMapping("/dept")
    public Department insertDept(Department department){
        departmentMapper.insertDept(department);
        return department;
    }
}

最后如果我们希望可以对MyBatis做一些自定义的配置,我们可以像下面这样写一个自动配置类,这里以开启驼峰命名法为例,或者直接在配置文件中配置:

package com.chester.springboot.config;

import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;

@Configuration
public class MyBatisConfig {

    @Bean
    public ConfigurationCustomizer configurationCustomizer(){
        return new ConfigurationCustomizer(){

            @Override
            public void customize(Configuration configuration) {
                configuration.setMapUnderscoreToCamelCase(true);
            }
        };
    }
}

总结:
在上面的描述中我们讨论了Spring Boot的数据源的自动配置原理,以及自动执行.sql的原理,我们还讲到如何将数据源切换到druid,并做好配置,最后我们还讲述了如何利用注解使用mybatis。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值