SpringbootJDBC主要给我们提供了三个功能,第一个就是对数据源的装配,第二个就是提供一个JDBCTemplte
简化我们的使用,第三个就是事务。
看个demo,加入数据库驱动,和spring-boot-starter-jdbc
依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
配置数据库连接:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username=root
spring.datasource.password=root
以上步骤springboot会自动装配数据源DataSource和JDBC工具了JdbcTemplate
启动类:
package com.zhihao.miao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.sql.Connection;
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception{
ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
DataSource ds = context.getBean(DataSource.class);
System.out.println(ds.getClass().getName()); //默认的使用的是tomcat的数据源
Connection connection = ds.getConnection();
System.out.println(connection.getCatalog()); //test
System.out.println(context.getBean(JdbcTemplate.class));
connection.close();
}
}
启动打印:
发现加入数据库驱动,和spring-boot-starter-jdbc
依赖和配置了数据库的信息之后自动装配的是org.apache.tomcat.jdbc.pool.DataSource
。也主动装配了JdbcTemplate这个类。
那么springboot默认支持哪些数据源呢?可以看DataSourceAutoConfiguration
源码,
默认支持
tomcat-jdbc
,Hikari
,dbcp
,dbcp2
,Generic
这五种数据源。那么怎么装配这些数据源呢?因为我们知道springboot在默认情况下装配的是tomcat-jdbc
数据源,比如我们自己配置一个Hikari数据源。
配置方式有二种,第一种是加入相关数据源的依赖,并且排除tomcat的数据源依赖,
<dependencies>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
第二种就是加入相关数据源依赖并在配置文件指定默认的数据源,
<dependencies>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
在application.properties中指定数据源:
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
对于springboot默认支持的五种数据源,我们只要将其依赖加入并且进行排除默认的tomcat数据源(或者使用配置文件,如上图所示就能使用自己的数据源了),那么如果使用springboot默认不支持的数据源呢,比如阿里的druid数据源
也有二种方式,第一种直接加入依赖,并在配置文件中指定数据源类型
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
第二种方式也是加入相应的数据源依赖,
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
修改启动类:
@SpringBootApplication
public class Application {
@Autowired
private Environment environment;
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(environment.getProperty("spring.datasource.url"));
dataSource.setUsername(environment.getProperty("spring.datasource.username"));
dataSource.setPassword(environment.getProperty("spring.datasource.password"));
return dataSource;
}
public static void main(String[] args) throws Exception{
ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
DataSource ds = context.getBean(DataSource.class);
System.out.println(ds.getClass().getName()); //默认的使用的是tomcat的数据源
Connection connection = ds.getConnection();
System.out.println(connection.getCatalog()); //test
System.out.println(context.getBean(JdbcTemplate.class));
connection.close();
}
}
推荐第二种方式,因为可以定制一些数据源的一些其他信息比如初始化连接,最大连接数,最小连接数等等。
Springboot JDBC的事务
事务:
- 要使用@EnableTransactionManagement启用对事务的支持
- 在需要使用事务的方法上面加上@Transactional
注意,默认只会对运行时异常进行事务回滚,非运行时异常不会回滚事务。
下面我发现不加@EnableTransactionManagement这个注解事务也是生效的
看一个demo:
定义Controller,
@RestController
public class GoodController {
@Autowired
private GoodService goodService;
@PostMapping("/addGood")
public String addGood(@RequestBody Map<String,List<Good>> map){
List<Good> goodsList = map.get("goodslist");
try {
goodService.addGood(goodsList);
return "addGood success";
} catch (Exception e) {
return "addGood fail";
}
}
}
定义Service层及其实现,
public interface GoodService {
void addGood(List<Good> goodslist) throws Exception;
}
@Service("goodService")
public class GoodServiceImpl implements GoodService{
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addGood(List<Good> goodslist) throws Exception{
for (int i = 0; i < goodslist.size(); i++) {
Good good = goodslist.get(i);
String sql = "insert into tb_good (good_id,good_name) values" +
"('"+good.getGoodId()+"','"+good.getGoodName()+"')";
logger.info(sql);
jdbcTemplate.execute(sql);
}
}
}
启动执行测试,执行成功数据库中增加了三条记录
修改代码,人为的在增加第二条记录的时候抛出异常,删除上面的三条数据,
@Service("goodService")
public class GoodServiceImpl implements GoodService{
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void addGood(List<Good> goodslist) throws Exception{
for (int i = 0; i < goodslist.size(); i++) {
Good good = goodslist.get(i);
String sql = "insert into tb_good (good_id,good_name) values" +
"('"+good.getGoodId()+"','"+good.getGoodName()+"')";
logger.info(sql);
if("书籍".equals(good.getGoodName())){
throw new NullPointerException("");
}
jdbcTemplate.execute(sql);
}
}
}
再去测试,发现事务生效,我们都知道默认事务回滚运行期异常,我们修改代码,人为的抛出非运行期异常,发现事务并没有回滚,
@Service("goodService")
public class GoodServiceImpl implements GoodService{
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void addGood(List<Good> goodslist) throws Exception{
for (int i = 0; i < goodslist.size(); i++) {
Good good = goodslist.get(i);
String sql = "insert into tb_good (good_id,good_name) values" +
"('"+good.getGoodId()+"','"+good.getGoodName()+"')";
logger.info(sql);
if("书籍".equals(good.getGoodName())){
throw new FileNotFoundException("");
}
jdbcTemplate.execute(sql);
}
}
}
那么要使得非运行期异常也回滚,就要使用@Transactional进行相关配置,比如@Transactional(rollbackFor=Exception.class)对所有异常进行回滚不管是运行期还是非运行期异常。
@Service("goodService")
public class GoodServiceImpl implements GoodService{
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(rollbackFor=Exception.class)
public void addGood(List<Good> goodslist) throws Exception{
for (int i = 0; i < goodslist.size(); i++) {
Good good = goodslist.get(i);
String sql = "insert into tb_good (good_id,good_name) values" +
"('"+good.getGoodId()+"','"+good.getGoodName()+"')";
logger.info(sql);
if("书籍".equals(good.getGoodName())){
throw new FileNotFoundException("");
}
jdbcTemplate.execute(sql);
}
}
}
还可以通过transactionManager对哪些数据源进行回滚(多数据源情况下),propagation配置事务的传播行为,isolation配置事务的隔离级别,timeout事务的超时时间,noRollbackForClassName哪些数据可以不回滚等等。
修改代码
@Service("goodService")
public class GoodServiceImpl implements GoodService{
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private JdbcTemplate jdbcTemplate;
public void addGood(List<Good> goodslist) throws Exception{
addGoodreal(goodslist);
}
@Transactional
public void addGoodreal(List<Good> goodslist) throws Exception{
for (int i = 0; i < goodslist.size(); i++) {
Good good = goodslist.get(i);
String sql = "insert into tb_good (good_id,good_name) values" +
"('"+good.getGoodId()+"','"+good.getGoodName()+"')";
logger.info(sql);
if("书籍".equals(good.getGoodName())){
throw new NullPointerException("");
}
jdbcTemplate.execute(sql);
}
}
}
在我们controller层调用addGood的方法上没有加 @Transactional,这时事务就没有回滚。