Bootstrap

SpringBoot学习系列(十一)------SpringBoot访问数据库

SpringBoot学习系列(十一)------SpringBoot访问数据库

前言

在项目开发中,数据库的访问是必不可少的,对于数据访问层,无论是SQL还是NoSql,SpringBoot默认采用整合Spring Data的方式进行统一处理,添加了大量的自动配置,屏蔽了很多设置.引入各种Template或Repository来简化我们对数据访问层的操作,对我们来说只需要进行简单的设置即可.

正文

1.使用IDEA构建一个简单的SpringBoot应用

我们先用IDEA创建一个SringBoot应用,引入web组件,jdbc组件

在这里插入图片描述

在这里插入图片描述

2.使用jdbc

在SpringBoot的配置文件中配置好数据源,我们就可以查看默认的数据库连接:

spring.datasource.url = jdbc:mysql://127.0.0.1:3306/tale?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driverClassName = com.mysql.jdbc.Driver

在测试类中测试连接:

    @Autowired
    DataSource dataSource;

    @Test
    public void contextLoads() throws SQLException {
        System.out.println(dataSource.getClass());
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }

可以看到控制台打印:

在这里插入图片描述

可以看到,SpringBoot2.0+使用的默认数据源是:com.zaxxer.hikari.HikariDataSource

它还支持以下数据源:dbcp2,tomcat

我们查看DataSourceConfiguration这个类,可以看到它还支持自定义数据源:

abstract class DataSourceConfiguration {
    DataSourceConfiguration() {
    }

    protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
        return properties.initializeDataSourceBuilder().type(type).build();
    }

    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"}
    )
    static class Generic {
        Generic() {
        }

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

    @ConditionalOnClass({BasicDataSource.class})
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"},
        havingValue = "org.apache.commons.dbcp2.BasicDataSource",
        matchIfMissing = true
    )
    static class Dbcp2 {
        Dbcp2() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.dbcp2"
        )
        public BasicDataSource dataSource(DataSourceProperties properties) {
            return (BasicDataSource)DataSourceConfiguration.createDataSource(properties, BasicDataSource.class);
        }
    }

    @ConditionalOnClass({HikariDataSource.class})
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"},
        havingValue = "com.zaxxer.hikari.HikariDataSource",
        matchIfMissing = true
    )
    static class Hikari {
        Hikari() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.hikari"
        )
        public HikariDataSource dataSource(DataSourceProperties properties) {
            HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }

            return dataSource;
        }
    }

    @ConditionalOnClass({org.apache.tomcat.jdbc.pool.DataSource.class})
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"},
        havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
        matchIfMissing = true
    )
    static class Tomcat {
        Tomcat() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.tomcat"
        )
        public org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
            org.apache.tomcat.jdbc.pool.DataSource dataSource = (org.apache.tomcat.jdbc.pool.DataSource)DataSourceConfiguration.createDataSource(properties, org.apache.tomcat.jdbc.pool.DataSource.class);
            DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
            String validationQuery = databaseDriver.getValidationQuery();
            if (validationQuery != null) {
                dataSource.setTestOnBorrow(true);
                dataSource.setValidationQuery(validationQuery);
            }

            return dataSource;
        }
    }
}

它的自定义数据源是这样定义的:

@ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"}
    )
    static class Generic {
        Generic() {
        }

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

其次,我们可以将建表以及插入数据的sql脚本放在指定的目录,这样项目在启动的时候会自动建表:

  • 默认情况下,将脚本命名为schema.sql或者schema-all.sql,并放在resource目录下就可以

  • 如果要自己指定文件名,需要在配置文件中配置一个属性来指定文件名:

    spring:
      datasource:
        schema: 
          ‐ classpath:department.sql
          //该属性的值是个列表,我们可以指定多个文件
          //在SPringBoot2.0以后,如果要运行sql脚本 还需要加入下面这个配置
        initialization-mode: always  
    

SpringBoot默认整合了JdbcTemplate操作数据库,我们可以直接使用:

@Controller
public class HelloController {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @ResponseBody
    @RequestMapping("/map")
    public Map<String, Object> map() {
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from t_contents");
        for (Map<String, Object> map : maps
             ) {
            System.out.println(map);
        }
        return maps.get(0);
    }

}

页面访问:

在这里插入图片描述

3.整合Druid数据源

在日常的项目开发中,我们一般不会是用原生的JDBC来操作数据库,笔主经常遇到的就是我们阿里的Druid,在这里我们也来这个Druid到SpringBoot项目中.

  1. 引入pom依赖

    首先在项目的pom.xml中引入Druid的坐标依赖,可以直接从maven仓库中搜索到.

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
    
  2. 在application.yml或者properties文件中配置数据源

    使用type属性来指定我们使用的数据源

    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: 123456
        url: jdbc:mysql://127.0.0.1:3306/tale?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
        type: com.alibaba.druid.pool.DruidDataSource
    

    除了这些参数,Druid还提供了很多的属性配置:

        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
    

    当然,如果直接在配置文件中引入这些是不行的,因为默认的属性不会绑定这些参数,我们需要自定定义一个DataSource来绑定参数,可如下操作:

    /**
     * 配置Driud数据源
     */
    @Configuration
    public class DruidConfig {
    
        @Bean
        //下面的注解表示将属性文件中前缀是spring.datasource的属性绑定到当前数据源
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource druid() {
            return new DruidDataSource();
        }
    
        /**
         * druid的强大在于有一套完整的监控配置,我们可以在这里配置一下,配置druid的后台监控需要配置
         * 一个servlet,我们可以直接使用servletRegistrationBean来配置,配置的servlet的名称
         * 是statViewServlet,
         */
        @Bean
        public ServletRegistrationBean statViewServlet() {
            ServletRegistrationBean bean
                    = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
            //可以在这个servlet中设置参数来定义后台的一些参数
            Map<String, String> initParms = new HashMap<>();
            //配置登录用户名
            initParms.put("loginUsername", "admin");
            //配置密码
            initParms.put("loginPassword", "123456");
            //配置访问权限,默认是所有都能访问
            initParms.put("allow", "");
            //配置拒绝访问的ip
            initParms.put("deny", "");
            bean.setInitParameters(initParms);
            return bean;
        }
    
        /**
         * 要使用druid的后台监控功能,还可以配置一个filter,它的名称是webStatFilter
         *
         */
        @Bean
        public FilterRegistrationBean webStatFilter() {
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setFilter(new WebStatFilter());
    
            Map<String, String> initParms = new HashMap<>();
            //不拦截的资源
            initParms.put("exclusions", "*.js,*.css,/druid/*");
            bean.setInitParameters(initParms);
            //要拦截的请求
            bean.setUrlPatterns(Arrays.asList("/*"));
            return bean;
        }
    
    }
    

    启动项目,访问localhost:8080/druid,就可以直接跳转到登录页面,使用我们在servlet中配置的账号登录就可以登录Druid的后台了:

    在这里插入图片描述

4.整合Mybatis
  • 使用注解整合Mybatis

    首先引入mybatis的maven坐标:

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

    创建对应的javeBean和Mapper:

    public class User {
    
    
        private int id;
    
        private String userName;
    	//省略set,get
    }
    
    
    /**
     * 用户表对应的mapper
     */
    @Mapper
    //mapper注解指定这个接口是mybatis的mapper,且将此接口加入容器
    public interface UserMapper {
    
        /**
         *  通过id查询user对象
         * @param id 主键
         * @return user对象
         */
        @Select("select * from user where id=#{id}")
        User queryUserById(int id);
    	
        
        @Options(useGeneratedKeys = true, keyProperty = "id")
      	//options用来定义主键返回,keyProperty指定主键对应的属性
        @Insert("insert into user (userName) values (#{userName})")
        int insert(User user);
    
    }
    

    在controller层定义好对应的映射:

        @GetMapping("/user/{id}")
        @ResponseBody
        public User queryUser(@PathVariable("id") int id) {
            User user = userMapper.queryUserById(id);
            return user;
        }
    
        @GetMapping("/user")
        @ResponseBody
        public User insertUser(User user) {
            userMapper.insert(user);
            return user;
        }
    

    如上做完以后就可以访问页面了,如果需要配置数据库映射的时候使用驼峰命名的规则,可以自定义一个配置规则:

    @org.springframework.context.annotation.Configuration
    public class MyBatisConfig {
        @Bean
        public ConfigurationCustomizer configurationCustomizer(){
            return new ConfigurationCustomizer(){
                @Override
                public void customize(Configuration configuration) {
                    configuration.setMapUnderscoreToCamelCase(true);
                }
            };
        }
    }
    

    如果我们的Mapper文件太多,不想一个个写@Mapper注解,也可以直接在启动类上使用以下方式来扫描包路径下的所有mapper:

    @SpringBootApplication
    @MapperScan(value = "mapper文件所在的包路径, ex:com.xiaojian.mapper")
    public class SpringbootJdbcApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootJdbcApplication.class, args);
        }
    }
    
  • 使用配置文件整合Mybatis

    使用配置文件来整合Mybatis也很简单,只需要将sql定义在xml文件中即可,再写Mybatis的核心配置文件就可以,我们可以在SpringBoot的配置文件中指定Mybatis的配置文件和Mapper映射文件的位置:

    mybatis:
      config‐location: classpath:mybatis/mybatis‐config.xml 指定全局配置文件的位置
      mapper‐locations: classpath:mybatis/mapper/*.xml  指定sql映射文件的位置
    
5.整合JPA

引入jpa相关的pom依赖

  • 编写一个实体类和数据库中的表对应

    //使用JPA注解配置映射关系
    @Entity //告诉JPA这是一个实体类(和数据表映射的类)
    @Table(name = "tbl_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user;
    public class User {
        @Id //这是一个主键
        @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
        private Integer id;
        @Column(name = "last_name",length = 50) //这是和数据表对应的一个列
        private String lastName;
        @Column //省略默认列名就是属性名
        private String email;
    
  • 编写一个xxxRepository接口来操作对应的表

    //继承JpaRepository来完成对数据库的操作,JpaRepository继承了CrudRepository和Page类的功能,既可以进行正常的增删改查,也可以进行分页
    public interface UserRepository extends JpaRepository<User,Integer> {
    }
    
  • 还需要在配置文件中配置:

    spring: 
     	jpa:
        	hibernate:
    #     更新或者创建数据表结构
          	ddl‐auto: update
    #    控制台显示SQL
       	    show‐sql: true
    

完成以上配置以后就可以在controller层写对应的方法来操作数据.

总结

SpringBoot对数据访问的问题就记录这些,在实际的运用中,还有一些高级的功能没有说到,以后会逐渐补充~~

;