从jdbc到spring-boot-starter-jdbc
从jdbc到spring-boot-starter-jdbc
jdbc 是什么
JDBC是一种用于执行SQL语句的API,可以为多种关系数据库提供统一访问,它是由一组用Java语言编写的类和接口。是Java访问数据库的标准规范。
JDBC是Java提供的一种标准规范,具体的实现由各个数据库厂商去实现。对开发者来说屏蔽了不同数据库之间的区别,可以使用相同的方式(Java API)去操作不同的数据库。两个设备之间要进行通信需要驱动,不同数据库厂商对JDBC的实现类就是去连接数据库的驱动。如mysql-connector-java
连接mysql
数据库的驱动。
使用JDBC连接数据库的步骤
- 注册驱动,这里的执行 就需要驱动jar包
// mysql 数据库:“com.mysql.jdbc.Driver”
Class.forName(driver);
- 建立数据库连接 Connection
Connection conn=DriverManager.getConnection(url,userName,password);
- 创建Statement对象 用来执行SQL语句
Statement statement =conn.createStatement();
- 执行SQL语句
ResultSet rs =statement.executeQuery(sql);
- 处理结果
- 释放资源
数据库连接池
在使用JDBC进行数据库操作过程中,每次使用就要创建连接,同时使用完毕还必须得关闭连接,操作繁琐容易出错,并且Connection的取得和释放是代价比较高的操作。解决这个问题的方法就是连接池。连接池就是事先取得一定数量的Connection,程序执行处理的时候不是新建Connection,而是取得预先准备好的Connection。
DataSource
提供连接池机能的技术叫做DataSource。DataSource是JDK提供一个标准接口在javax.sql.DataSource
包下。常见的DBCP、C3P0、druid等。
spring-boot-starter-jdbc
spring-boot-starter-jdbc
主要提供了三个功能,第一个就是对数据源的装配,第二个就是提供一个JdbcTemplate简化使用,第三个就是事务
数据源相关使用
查看数据源和连接信息
package com.lucky.spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@SpringBootApplication
public class Application implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
DataSource dataSource;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println(">>>>>>>>>>>>>>>>>服务启动执行");
showConnection();
}
private void showConnection() throws SQLException {
logger.info("dataSource:{}", dataSource.getClass().getName());
Connection connection = dataSource.getConnection();
logger.info("connection:{}", connection.toString());
}
}
代码逻辑如下:
- 通过CommandLineRunner监听服务的启动,在启动后调用showConnection方法
- 在showConnection方法里打印出当前的DataSource实现类,获取一个连接并打印该连接的基本信息
打印结果如下
>>>>>>>>>>>>>>>>>服务启动执行
2020-07-12 07:38:42.076 INFO 8144 --- [ main] com.lucky.spring.Application : dataSource:com.zaxxer.hikari.HikariDataSource
2020-07-12 07:38:42.077 INFO 8144 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-07-12 07:38:42.274 INFO 8144 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-07-12 07:38:42.277 INFO 8144 --- [ main] com.lucky.spring.Application : connection:HikariProxyConnection@1366499339 wrapping com.mysql.jdbc.JDBC4Connection@25c5e994
可以看到
- dataSource使用的是:com.zaxxer.hikari.HikariDataSource
- connection信息是:HikariProxyConnection@1366499339 wrapping com.mysql.jdbc.JDBC4Connection@25c5e994
当前的pom文件中仅仅配置了spring-boot-starter-jdbc和mysql数据库驱动
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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>
</dependencies>
Springboot支持的数据源
在DataSourceAutoConfiguration
类的内部类PooledDataSourceConfiguration
标识了默认支持的数据源。
@Configuration
@Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
@Import({Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class})
protected static class PooledDataSourceConfiguration {
protected PooledDataSourceConfiguration() {
}
}
默认支持Hikari、Tomcat、Dbcp2、Generic、DataSourceJmxConfiguration这五种数据源。从上面的数据源和连接信息的打印可以知道默认情况下Springboot装配的是Hikari数据源。
自动装配Tomcat数据源
在DataSourceConfiguration
中Tomcat
数据源的实现如下
@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;
}
}
让Springboot自动装配选择Tomcat的方式有两种
第一种
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--默认配置 start-->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-jdbc</artifactId>-->
<!--</dependency>-->
<!--默认配置 end-->
<!--使用tomcat数据源 方式 start-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
<!--使用tomcat数据源 方式 end-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
- 加入tomcat-jdbc数据源的依赖
- 排除Hikari的数据源依赖
打印信息如下:
>>>>>>>>>>>>>>>>>服务启动执行
2020-07-12 08:11:49.761 INFO 8469 --- [ main] com.lucky.spring.Application : dataSource:org.apache.tomcat.jdbc.pool.DataSource
2020-07-12 08:11:50.058 INFO 8469 --- [ main] com.lucky.spring.Application : connection:ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@4d6f197e]]
第二种
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--默认配置 start-->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-jdbc</artifactId>-->
<!--</dependency>-->
<!--默认配置 end-->
<!--使用tomcat数据源 方式 start-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
<!--使用tomcat数据源 方式 end-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
spring:
datasource:
url: jdbc:mysql://localhost:3306/readinglist?characterEncoding=utf8&useSSL=false
username: root
password: 12345678
type: org.apache.tomcat.jdbc.pool.DataSource
- pom文件中添加tomcat-jdbc依赖
- 在application.yml文件中指定数据源为org.apache.tomcat.jdbc.pool.DataSource
打印结果如下:
>>>>>>>>>>>>>>>>>服务启动执行
2020-07-12 08:15:51.746 INFO 8525 --- [ main] com.lucky.spring.Application : dataSource:org.apache.tomcat.jdbc.pool.DataSource
2020-07-12 08:15:52.152 INFO 8525 --- [ main] com.lucky.spring.Application : connection:ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5173200b]]
使用druid数据源
对于Springboot默认支持的五种数据源,可以通过上面两种方式(一、排除默认数据源,添加使用的数据源;二、添加使用的数据源,使用配置文件指定使用的数据源) 进行选择使用数据源。如果是其他开源的数据源呢?比如阿里的druid数据源。也是有两种方式。
第一种
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
spring:
datasource:
url: jdbc:mysql://localhost:3306/readinglist?characterEncoding=utf8&useSSL=false
username: root
password: 12345678
type: com.alibaba.druid.pool.DruidDataSource
- 添加druid数据源依赖
- 在application.yml文件中指定数据源为com.alibaba.druid.pool.DruidDataSource
打印结果如下:
>>>>>>>>>>>>>>>>>服务启动执行
2020-07-12 08:27:52.523 INFO 8813 --- [ main] com.lucky.spring.Application : dataSource:com.alibaba.druid.pool.DruidDataSource
2020-07-12 08:27:52.562 INFO 8813 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
2020-07-12 08:27:52.883 INFO 8813 --- [ main] com.lucky.spring.Application : connection:com.mysql.jdbc.JDBC4Connection@3b0ca5e1
第二种
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
package com.lucky.spring;
import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@SpringBootApplication
public class Application implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
DataSource dataSource;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println(">>>>>>>>>>>>>>>>>服务启动执行");
showConnection();
}
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/readinglist?characterEncoding=utf8&useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("12345678");
return dataSource;
}
private void showConnection() throws SQLException {
logger.info("dataSource:{}", dataSource.getClass().getName());
Connection connection = dataSource.getConnection();
logger.info("connection:{}", connection.toString());
}
}
- 添加druid依赖
- 创建DataSource的bean,进行相关配置后,返回DruidDataSource
打印结果如下:
>>>>>>>>>>>>>>>>>服务启动执行
2020-07-12 08:37:09.898 INFO 9140 --- [ main] com.lucky.spring.Application : dataSource:com.alibaba.druid.pool.DruidDataSource
2020-07-12 08:37:09.951 INFO 9140 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
2020-07-12 08:37:10.314 INFO 9140 --- [ main] com.lucky.spring.Application : connection:com.mysql.jdbc.JDBC4Connection@d400943
JdbcTemplate相关使用
JdbcTemplate 是什么
Spring对数据库的操作在jdbc上面做了深层次的封装。使用Spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
JdbcTemplate主要提供了一下五类方法
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句
- query方法及queryForXXX方法:用于执行查询相关语句
- call方法:用于执行存储过程、函数相关语句
事务的相关使用
Springboot中在需要使用事务的方法上面添加@Transactional
,需要注意的是,默认只会对运行时异常进行事务回滚,非运行时异常不会回滚事务。
Controller层定义了两个接口
@RestController
public class DataOperationController {
@Autowired
DataOpeService service;
@GetMapping("/api/queryData")
public String queryData() {
return service.queryData();
}
@PostMapping("/api/addData")
public String addData() {
try {
service.addData();
return "add data success";
} catch (Exception e) {
e.printStackTrace();
return "add data fail";
}
}
}
Service通过JdbcTemplate执行sql
@Service
public class DataOpeServiceImpl implements DataOpeService {
private Logger logger = LoggerFactory.getLogger(DataOpeServiceImpl.class);
@Autowired
private JdbcTemplate template;
@Override
public String queryData() {
String sql = "select * from t where id=1";
RowMapper<T> data = new BeanPropertyRowMapper<>(T.class);
T t = template.queryForObject(sql, data);
return t.toString();
}
@Override
public String addData() {
List<T> data = new ArrayList<>();
for (int i = 0; i < 2; i++) {
T item = new T();
item.setA(i);
item.setB(i);
data.add(item);
}
for (int i = 0; i < data.size(); i++) {
String sql = "insert into t(a,b) values (" + data.get(i).getA() + "," + data.get(i).getB() + ")";
logger.info("sql:{}", sql);
template.execute(sql);
}
return null;
}
}
运行时异常
修改代码,人为在添加第二条记录时抛出异常。
@Transactional
@Override
public String addData() {
List<T> data = new ArrayList<>();
for (int i = 0; i < 2; i++) {
T item = new T();
item.setA(i);
item.setB(i);
data.add(item);
}
for (int i = 0; i < data.size(); i++) {
String sql = "insert into t(a,b) values (" + data.get(i).getA() + "," + data.get(i).getB() + ")";
logger.info("sql:{}", sql);
if (data.get(i).getA() == 1) {
throw new NullPointerException("人为抛出运行时异常异常");
}
template.execute(sql);
}
return null;
}
调用接口,发现事务生效,即发生运行时异常进行了代码回滚。
非运行时异常
重新修改代码,人为抛出非运行时异常。
@Transactional
@Override
public String addData() throws Exception{
List<T> data = new ArrayList<>();
for (int i = 0; i < 2; i++) {
T item = new T();
item.setA(i);
item.setB(i);
data.add(item);
}
for (int i = 0; i < data.size(); i++) {
String sql = "insert into t(a,b) values (" + data.get(i).getA() + "," + data.get(i).getB() + ")";
logger.info("sql:{}", sql);
if (data.get(i).getA() == 1) {
// throw new NullPointerException("人为抛出运行时异常异常");
throw new FileNotFoundException("人为抛出非运行时异常");
}
template.execute(sql);
}
return null;
}
调用接口,发现事务没有生效,即第一条数据插入到了数据库里。
指定回滚时的异常
如果要使得非运行时期异常也回滚,那么在使用@Transactional
注解时,指定rollbackFor属性。
@Transactional(rollbackFor = Exception.class)
@Override
public String addData() throws Exception{
List<T> data = new ArrayList<>();
for (int i = 0; i < 2; i++) {
T item = new T();
item.setA(i);
item.setB(i);
data.add(item);
}
for (int i = 0; i < data.size(); i++) {
String sql = "insert into t(a,b) values (" + data.get(i).getA() + "," + data.get(i).getB() + ")";
logger.info("sql:{}", sql);
if (data.get(i).getA() == 1) {
// throw new NullPointerException("人为抛出运行时异常异常");
throw new FileNotFoundException("人为抛出非运行时异常");
}
template.execute(sql);
}
return null;
}
从jdbc到spring-boot-starter-jdbc的更多相关文章
- Spring Boot 整合JDBC 实现后端项目开发
一.前言 二.新建Spring Boot 项目 三.Spring Boot 整合JDBC 与MySQL 交互 3.1 新建数据表skr_user 3.2 Jdbcproject 项目结构如下 3.3 ...
- Spring Boot系列(三) Spring Boot 之 JDBC
数据源 类型 javax.sql.DataSource javax.sql.XADataSource org.springframework.jdbc.datasource.embedded,Enbe ...
- spring -boot s-tarter 详解
Starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合.你可以获取所有Spring及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符.例如,如果你想使用Sprin ...
- SpringBoot 之Spring Boot Starter依赖包及作用
Spring Boot 之Spring Boot Starter依赖包及作用 spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. spri ...
- Spring Boot Starter列表
转自:http://blog.sina.com.cn/s/blog_798f713f0102wiy5.html Spring Boot Starter 基本的一共有43种,具体如下: 1)spring ...
- Druid Spring Boot Starter 从配置到简单运行 -解决zone不匹配 -解决dataSource加载失败
Druid Spring Boot Starter 中文 | English Druid Spring Boot Starter 用于帮助你在Spring Boot项目中轻松集成Druid数据库连接池 ...
- 手把手教你手写一个最简单的 Spring Boot Starter
欢迎关注微信公众号:「Java之言」技术文章持续更新,请持续关注...... 第一时间学习最新技术文章 领取最新技术学习资料视频 最新互联网资讯和面试经验 何为 Starter ? 想必大家都使用过 ...
- Spring Boot Starter 介绍
http://www.baeldung.com/spring-boot-starters 作者:baeldung 译者:http://oopsguy.com 1.概述 依赖管理是任何复杂项目的关键部分 ...
- Spring Boot (一): Spring Boot starter自定义
前些日子在公司接触了spring boot和spring cloud,有感于其大大简化了spring的配置过程,十分方便使用者快速构建项目,而且拥有丰富的starter供开发者使用.但是由于其自动化配 ...
- Spring boot starter pom的依赖关系说明
Spring Boot 通过starter依赖为项目的依赖管理提供帮助.starter依赖起始就是特殊的maven依赖,利用了传递依赖解析,把常用库聚合在一起,组成了几个为特定功能而定制的依赖. sp ...
随机推荐
- 【笔记】Java语法
Java语法 兜兜转转,又绕回到Java了. 最近在学习Java,其实以前也学过,但是技术发展太快了,Java都出到14了..是时候该更新一下知识体系了. 然后看的是网上好评如潮的<Java核心 ...
- Scala 基础(十四):Scala 模式匹配(二)
1 匹配数组 1)Array(0) 匹配只有一个元素且为0的数组. 2)Array(x,y) 匹配数组有两个元素,并将两个元素赋值为x和y.当然可以依次类推Array(x,y,z) 匹配数组有3个元素 ...
- 数据可视化之powerBI基础(二十)Power BI度量值和新建表,有什么异同?
https://zhuanlan.zhihu.com/p/101812525 PowerBI中,有三个地方可以使用DAX,分别是度量值.新建列和新建表,这三个功能并成一排摆放在这里,如图所示, 之前 ...
- 01 drf源码剖析之restful规范
01 restful规范 目录 01 restful规范 1. 什么是restful规范 2.restful规范详细 1. 什么是restful规范 restful是一套规则,是程序间进行数据传输的一 ...
- [USACO3.1]形成的区域(扫描线+离散化)
[USACO3.1]形成的区域(P6432) 日期:2020-05-31 目录 [USACO3.1]形成的区域(P6432) 一.题意分析 二.算法分析 1. 暴力 0). 初始状态(红点为原点) 1 ...
- hls&flv直播请求过程
hls&flv直播请求过程 直播类产品层出不穷,从各方面塑造了我们的生活方式.直播产品中,延时是决定用户体验的关键因素,它也将间接决定直播产品的成败.这其间,对延时影响较大的就是直播架构中选择 ...
- ScheduledThreadPoolExecutor源码主要部分解析
ScheduledThreadPoolExecutor继承与基础线程池类ThreadPoolExecutor并实现ScheduledExecutorService接口. 其中ScheduledExec ...
- 第一部分软件测试综述——软件测试背景【软件测试】(美)Ron Patton中文电子版
截取自:第一部分软件测试综述——软件测试背景[软件测试](美)Ron Patton中文电子版(有需要的可以关注我) 第一部分软件测试综述 对手的程序死掉叫崩溃.自己的程序死掉叫“身体不良反应(idio ...
- Ubuntu18.04安装Docker并部署(编译、发布、构建镜像)Asp.NetCore项目全过程笔记
环境准备:阿里云Ubuntu18.04 全新安装 一.安装Docker 1.删除旧版本并更新包索引: sudo apt-get remove docker docker-engine dock ...
- Android Studio(Kotlin)之RecyclerView
RecyclerView应该是ListView的增强版. RecyclerView与ListView的区别(我认为的): RecyclerView的性能比ListView高 RecyclerView支 ...