springboot jdbc

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-jdbcHikaridbcpdbcp2Generic这五种数据源。那么怎么装配这些数据源呢?因为我们知道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,这时事务就没有回滚。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 这部分的参考文档涉及数据访问和数据访问层和业务或服务层之间的交互。 Spring的综合事务管理支持覆盖很多细节,然...
    竹天亮阅读 1,026评论 0 0
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,678评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 目录 4.1李白——《清平调三首》 4.2元稹——《离思》 4.3王阳明——《泛海》 4.4诗经——《子衿》 4....
    翟伟阅读 492评论 0 0
  • 今天也是有点忙碌,一直到现在才有时间来点滴,可以安静下来写写东西。整理这一天的内心活动,觉察每个环节自己情绪的波动...
    效艳一亩田阅读 292评论 0 3