SpringBoot(八)——数据访问

1. SpringBoot 与数据库连接

  1. 创建一个SpringBoot项目,选择starter的时候,多选两个,jdbc、mysqlql
    在这里插入图片描述
  2. 配置数据库连接信息
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://47.94.231.234:3306/jdbc

  1. 测试能否连接上数据库
@SpringBootTest
class SpringBoot06DataJdbcApplicationTests {
    @Autowired
    HikariDataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        System.out.println(dataSource.getClass());
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }

}

springboot默认是使用com.zaxxer.hikari.HikariDataSource作为数据源,2.0以下是用org.apache.tomcat.jdbc.pool.DataSource作为数据源;

数据源的相关配置都在DataSourceProperties里面;

2. 自动配置原理

jdbc的相关配置都在org.springframework.boot.autoconfigure.jdbc包下

参考DataSourceConfiguration,根据配置创建数据源,默认使用Hikari连接池;可以使用spring.datasource.type指定自定义的数据源类型;

springboot默认支持的连池:

  • org.apache.commons.dbcp2.BasicDataSource
  • com.zaxxer.hikari.HikariDataSource
  • org.apache.tomcat.jdbc.pool.DataSource

自定义数据源类型(在配置文件中指定spring.datasource.type):

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

        @Bean
        DataSource dataSource(DataSourceProperties properties) {
        	//使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
            return properties.initializeDataSourceBuilder().build();
        }
    }

容器中没有DataSource.class的话,会进行注册,就会执行properties.initializeDataSourceBuilder().build();

initializeDataSourceBuilder(),会创建一个DataSourceBuilder对象,并且根据配置文件中指定的属性进行绑定,之后执行build()创建数据源


    public DataSourceBuilder<?> initializeDataSourceBuilder() {
        return DataSourceBuilder.create(this.getClassLoader()).type(this.getType()).driverClassName(this.determineDriverClassName()).url(this.determineUrl()).username(this.determineUsername()).password(this.determinePassword());
    }

DataSourceBuilder:绑定相关属性

public <D extends DataSource> DataSourceBuilder<D> type(Class<D> type) {
        this.type = type;
        return this;
    }

    public DataSourceBuilder<T> url(String url) {
        this.properties.put("url", url);
        return this;
    }

    public DataSourceBuilder<T> driverClassName(String driverClassName) {
        this.properties.put("driverClassName", driverClassName);
        return this;
    }
。。。。

build() : 根据type创建数据源

public T build() {
        Class<? extends DataSource> type = this.getType();
        DataSource result = (DataSource)BeanUtils.instantiateClass(type);
        this.maybeGetDriverClassName();
        this.bind(result);
        return result;
    }

如果没有指定的话,type就是com.zaxxer.hikari.HikariDataSource

getType

private Class<? extends DataSource> getType() {
        Class<? extends DataSource> type = this.type != null ? this.type : findType(this.classLoader);
        if (type != null) {
            return type;
        } else {
            throw new IllegalStateException("No supported DataSource type found");
        }
    }

findType

private static final String[] DATA_SOURCE_TYPE_NAMES = new String[]{"com.zaxxer.hikari.HikariDataSource", "org.apache.tomcat.jdbc.pool.DataSource", "org.apache.commons.dbcp2.BasicDataSource"};

public static Class<? extends DataSource> findType(ClassLoader classLoader) {
        String[] var1 = DATA_SOURCE_TYPE_NAMES;
        int var2 = var1.length;
        int var3 = 0;

        while(var3 < var2) {
            String name = var1[var3];

            try {
                return ClassUtils.forName(name, classLoader);
            } catch (Exception var6) {
                ++var3;
            }
        }

        return null;
    }

启动应用,执行sql

SpringBoot在创建连接池后还会运行预定义的SQL脚本文件,具体参考

org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfiguration配置类,

在该类中注册了dataSourceInitializerPostProcessor

下面是获取schema脚本文件的方法

        List<Resource> scripts = this.getScripts("spring.datasource.data", this.properties.getData(), "data");

在这里插入图片描述

可以看出,如果我们没有在配置文件中配置脚本的具体位置,就会在classpath下找schema-all.sql和schema.sql platform获取的是all,platform可以在配置文件中修改

具体查看createSchema()方法和initSchema()方法

initSchema()方法获取的是data-all.sql,data.sql

我们也可以在配置文件中配置sql文件的位置

spring:
  datasource:
    schema:
      - classpath:department.sql

测试
在类路径下创建schema.sql,运行程序查看数据库是否存在该表

DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `departmentName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

程序启动后发现表并没有被创建,DEBUG查看以下,发现在运行之前会有一个判断
在这里插入图片描述
在这里插入图片描述
上面方法也不知道在干什么,反正就是只要是NEVER和EMBEDDED就为true,而DataSourceInitializationMode枚举类中除了这两个就剩下ALWAYS了,可以在配置文件中配置为ALWAYS

在这里插入图片描述

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://47.94.231.234:3306/jdbc
    initialization-mode: always

一般来说,schema.sql:建表语句,data.sql:插入数据,不这样写也是可以的。

项目每次启动都会执行一次sql

3. 整合druid数据源

选择哪个数据库连接池

  • DBCP2 是 Appache 基金会下的项目,是最早出现的数据库连接池 DBCP 的第二个版本。
  • C3P0 最早出现时是作为 Hibernate 框架的默认数据库连接池而进入市场。
  • Druid 是阿里巴巴公司开源的一款数据库连接池,其特点在于有丰富的附加功能。
  • HikariCP 相较而言比较新,它最近两年才出现,据称是速度最快的数据库连接池。最近更是被 Spring 设置为默认数据库连接池。

不选择 C3P0 的原因:

C3P0 的 Connection 是异步释放。这个特性会导致释放的在某些情况下 Connection 实际上 still in use ,并未真正释放掉,从而导致连接池中的 Connection 耗完,等待状况。
Hibernate 现在对所有数据库连接池一视同仁,官方不再指定『默认』数据库连接池。因此 C3P0 就失去了『官方』光环。

不选择 DBCP2 的原因:

相较于 Druid 和 HikariCP,DBCP2 没有什么特色功能/卖点。基本上属于 能用,没毛病 的情况,地位显得略有尴尬。

  1. 在 Spring Boot 项目中加入druid-spring-boot-starter依赖点击查询最新版本
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.20</version>
</dependency>
  1. 在配置文件中指定数据源类型
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://47.94.231.234:3306/jdbc
    initialization-mode: always
    type: com.alibaba.druid.pool.DruidDataSource
  1. 测试使用的数据源
@SpringBootTest
class SpringBoot06DataJdbcApplicationTests {
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        System.out.println(dataSource.getClass());
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }

  1. 配置参数
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://47.94.231.234:3306/jdbc
    initialization-mode: always
    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,slf4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

@Configuration
public class DruidConfig {

    //注册DruidDataSource,并进行参数绑定
    @ConfigurationProperties(prefix="spring.datasource")
    @Bean
    public DruidDataSource druidDataSource(){
        return new DruidDataSource();
    }
}

后台页面,访问http://localhost:8080/druid/login.html 会显示登陆页面

在这里插入图片描述
输入在配置文件中设置的账号和密码

在这里插入图片描述

4. 整合MyBatis

4.1 引入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!--引入druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <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>
    </dependencies>

依赖关系
在这里插入图片描述

4.2项目构建

  1. 在resources下创建sql目录,在sql目录中创建department.sql和employee.sql,可项目启动时创建表
    department.sql
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `departmentName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

employee.sql

DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `lastName` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `gender` int(2) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

  1. 创建实体类

    • Employee
    • Department
  2. 配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://47.94.231.234:3306/mybatis
    #只有配置这个,才可以在项目启动的时候,执行sql文件
    initialization-mode: always
    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,slf4j
      # 配置web监控的filter,默认配置也和下面相同(除用户名密码,enabled默认false外),其他可以不配
      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions:  "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
      #配置管理后台的servlet
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        login-username: root
        login-password: root
        allow: 127.0.0.1
#    schema:
#     - classpath:sql/department.sql
#     - classpath:sql/employee.sql
  1. MyBatis增删改查(注解版)
@Mapper //指定这是操作数据库的mapper
public interface DepartmentMapper {
    @Select("select * from department where id=#{id}")
    public Department getDeptById(int id);

    @Delete("delete from department where id=#{id}")
    public int deleteDEptById(int id);
	
    @Update("update department set departmentName=#{departmentName} where id=#{id}")
    public int updateDept(Department department);
	
	//返回自增id,并与department的id属性进行绑定
	@Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into department(departmentName) values(#{departmentName})")
    public int insertDept(Department department);
}
  1. 创建Controller
@RestController
public class DeptController {
    @Autowired
    private DepartmentMapper departmentMapper;

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

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

  • 访问:http://localhost:8080/dep?departmentName=PeppaPig添加一条数据

  • 访问:http://localhost:8080/dep/1获取数据

4.3 Mybatis 配置

当表的列名和实体类中的属性名不一样的时候,访问:http://localhost:8080/dep/1获取数据,departmentName 就是null

{"id":2,"departmentName":null}

由于列表和属性名不一致,所以就没有封装进去,我们表中的列名和实体类属性名都是遵循驼峰命名规则的,可以开启mybatis的开启驼峰命名配置

#开启mybatis的驼峰命名配置
mybatis:
  configuration:
    map-underscore-to-camel-case: true

然后重启项目,重新插入数据,再查询就发现可以封装进去了

也可以通过向spring容器中注入org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer的方法设置mybatis参数

@Configuration
public class MyBatisConfig {

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

            @Override
            public void customize(org.apache.ibatis.session.Configuration configuration) {
                configuration.setMapUnderscoreToCamelCase(true);
            }
        };
    }
}

在这里插入图片描述

在这里插入图片描述

4.4 Mapper 扫描

使用@mapper注解的类可以被扫描到容器中,但是每个Mapper都要加上这个注解就是一个繁琐的工作,能不能直接扫描某个包下的所有Mapper接口呢,当然可以,在springboot启动类上加上@MapperScan

//配置包扫描,扫描mapper下的所有接口
@MapperScan(value="com.ewen.springboot.mapper")
@SpringBootApplication
public class SpringBoot06DataMybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot06DataMybatisApplication.class, args);
    }

}

4.5 使用xml配置文件

  1. 创建mybatis全局配置文件mybatis_config.xml,这里是在resource目录下创建mydatis/mybatis_config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <!--配置驼峰命名规则-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--配置别名-->
    <typeAliases>
        <package name="com.ewen.springboot"/>
    </typeAliases>

</configuration>
  1. 创建EmployeeMapper接口
//@Mapper 在启动类中已经使用了@MapperScan
public interface EmployeeMapper {

    public Employee selectById(Integer id);

    public int insert(Employee employee);
}
  1. 创建EmployeeMapper.xml映射文件
<?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.ewen.springboot.mapper.EmployeeMapper">

    <select id="selectById" parameterType="Integer" resultType="com.ewen.springboot.bean.Employee">
        SELECT * FROM employee WHERE id = #{id};
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO employee(lastName, email,gender,d_id) VALUES (#{lastName},#{email},
                    #{gender},#{d_id});
    </insert>
</mapper>
  1. 配置文件(application.yaml)中指定配置文件和映射文件的位置
mybatis:
  config-location: classpath:mybatis/mybatis_config.xml
  mapper-locations: classpath:mybatis/mapper/EmployeeMapper.xml

目录结构如下
在这里插入图片描述

SpringBoot 官方文档

5. 整合SpringData JPA

待续。。。。

如有不足之处,欢迎指正,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于在 Spring Boot 中插入一条数据,我们可以按照以下步骤进行操作: 1. 首先,我们需要在 pom.xml 中引入 Spring Boot 的相关依赖,包括 Spring Boot Starter 和 Spring Boot Starter Data JPA,如下所示: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> </dependencies> ``` 2. 在 application.properties 或 application.yml 配置文件中,配置数据库连接信息,例如: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 3. 创建一个实体类,用于映射数据库中的表结构,例如: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Integer age; // 省略 getter 和 setter 方法 } ``` 4. 创建一个 Repository 接口,用于操作数据库,例如: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { } ``` 5. 在业务逻辑中调用 UserRepository 的 save() 方法即可插入一条数据,例如: ```java @Service public class UserService { @Autowired private UserRepository userRepository; public void addUser() { User user = new User(); user.setName("张三"); user.setAge(20); userRepository.save(user); } } ``` 以上就是在 Spring Boot 中插入一条数据的详细步骤。需要注意的是,在实际开发中,我们需要根据具体的业务需求进行适当的调整,例如增加数据校验、事务管理等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值