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,這時事務就沒有回滾。