springboot2原理实战(16)--jdbc数据源和事务

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: springboot2原理实战(16)--jdbc数据源和事务

目录:


本文主要记录下springboot

5d4c6812c8535adbb050f4ddf2e1bce8.png


一、jdbc操作mysql


使用jdbc的话,前提示导入springboot的jdbc的jar


<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>


1.加入数据库驱动


<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
    <scope>runtime</scope>
</dependency>


2.加入配置在application.properties


spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot
spring.datasource.username=root
spring.datasource.password=123456


3.测试是否加入数据源


@SpringBootApplication
public class Demo16Application {
    public static void main(String[] args) throws SQLException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        DataSource dataSource= context.getBean(DataSource.class);
        System.out.println(dataSource);
//        System.out.println(context.getBean(DataSourceProperties.class));
        System.out.println(dataSource.getConnection());
        //打印出数据库名字 springboot装配好的dataSource
        System.out.println(dataSource.getConnection().getCatalog());
//        System.out.println(dataSource.getDataUsername());
    }


如下图: 显示已经获取了springboot2默认的数据源和我们自建的mysql的数据库名称为springboot

46a9d80a6e05e4e3b19d57a0ee70bcdf.png

以上操作,springboot会自动装配好DataSource,JdbcTemplate可以直接使用。


3.测试mysql的新增数据


@Repository
public class ProductDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public void addProduct(String name){
        //注意有sql注入的风险
        String sql = "insert into product(name) values('"+name+"')";
        jdbcTemplate.execute(sql);
    }
    public void addProductBatch(String ... names) throws FileNotFoundException {
       for (String name: names){
           //注意有sql注入的风险
           String sql = "insert into product(name) values('"+name+"')";
            jdbcTemplate.execute(sql);
            if("MP4".equals(name)){
                throw new FileNotFoundException();
            }
        }
        add(names);
    }
    public void add(String ... names){
        for (String name: names){
            //注意有sql注入的风险
            String sql = "insert into product(name) values('"+name+"')";
            jdbcTemplate.execute(sql);
            if("MP4".equals(name)){
                throw new NullPointerException();
            }
        }
    }
}


@SpringBootApplication
public class Demo16Application {
    public static void main(String[] args) throws SQLException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        System.out.println(context.getBean(JdbcTemplate.class));
        context.getBean(ProductDao.class).addProduct("TV");
    }
 }


查询数据库,显示数据已经加入:


二、数据源切换:


1.springboot内置的数据源和默认的数据源是什么:


springboot内置的数据源有5种,在DataSourceAutoConfiguration下:


spring2默认开启的是DataSourceConfiguration.Hikari.class的数据源,我们打印数据源看下:


@SpringBootApplication
public class Demo16Application {
    public static void main(String[] args) throws SQLException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        DataSource dataSource= context.getBean(DataSource.class);
        System.out.println(dataSource);
    }


打印结果如下图:显示默认的是tomcat数据源:


1dc618a0ed9580ce8bfa6facb208c08f.png


2.springboot切换内置的数据源:


方式1:jar包+配置文件配置实现


pom中添加:


<dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>


我们可以使用:pring.datasource.type切换数据源:


在spring.properties下配置:


spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource


入口函数再次打印:


@SpringBootApplication
public class Demo16Application {
    public static void main(String[] args) throws SQLException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        DataSource dataSource= context.getBean(DataSource.class);
        System.out.println(dataSource);
        System.out.println(context.getBean(DataSourceProperties.class));
        }
 }


如下图:显示数据源已经切换:


1dc618a0ed9580ce8bfa6facb208c08f.png


方式2:通过排除+jar包


pom中添加:


<dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>
1


同时排除默认的数据源


<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jdbc</artifactId>
     <exclusions>
         <exclusion>
             <groupId>com.zaxxer</groupId>
             <artifactId>HikariCP</artifactId>
         </exclusion>
     </exclusions>
</dependency>


运行测试:如下图,说明也切换成了tomcat数据源。


1dc618a0ed9580ce8bfa6facb208c08f.png


2.配置自己的的数据源 阿里的druid。


只要装配一个DataSource到spring容器中即可。


1)添加jar包


在pom中添加druid的jar包


<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.1.20</version>
</dependency>


测试:


application.properties中写个数据库地址:


spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot
spring.datasource.username=root
spring.datasource.password=123456


2)配置方式注入数据源


@SpringBootConfiguration
public class DBConfiguration {
    @Autowired
    private Environment env;
    @Bean
    public DataSource createDataSource(){
        DruidDataSource  ds = new DruidDataSource();
        ds.setUrl(env.getProperty("spring.datasource.url"));
        ds.setUsername(env.getProperty("spring.datasource.username"));
        ds.setPassword(env.getProperty("spring.datasource.password"));
        ds.setDriverClassName(env.getProperty("spring.datasource.driverClassName"));
        return ds;
    }
}


3)测试


入口函数中:


public static void main(String[] args) throws SQLException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        DataSource dataSource = context.getBean(DataSource.class);
        // 默认的数据源; class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());
        context.close();
    }


运行结果如下:显示已经成为了我们自定义的数据源。

1dc618a0ed9580ce8bfa6facb208c08f.png


三、事务


springboot2使用事务的方式很简单:


1.步骤:


1.在启动类上首先使用@@EnableTransactionManagement启用对事务的支持


2.在需要使用事物的方法上面加上@Transactional


举例说明:

@EnableTransactionManagement
@SpringBootApplication
public class Demo16Application {
    //测试事务
    public static void main4(String[] args) throws FileNotFoundException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        System.out.println(context.getBean(JdbcTemplate.class));
        context.getBean(ProductDao.class).addProductBatch("TV","MP3","MP4");
    }
    }


@Repository
public class ProductDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;  
   @Transactional
    public void addProductBatch(String ... names) {
        for (String name: names){
            //注意有sql注入的风险
            String sql = "insert into product(name) values('"+name+"')";
            jdbcTemplate.execute(sql);
            if("MP4".equals(name)){
                throw new RuntimeException("异常");
            }
        }


可以看到当我们插入MP4应该全部回滚,看下是否能达到预期效果,运行入口函数。

看下数据库,有没有插入:

1dc618a0ed9580ce8bfa6facb208c08f.png

显示没有插入,说明事务成功。


2.特别注意: 默认只会对运行时异常进行事务回滚,非运行时异常不会回滚事务。


我们可以测试下:


@Repository
public class ProductDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
   @Transactional
    public void addProductBatch(String ... names) throws Exception {
        for (String name: names){
            //注意有sql注入的风险
            String sql = "insert into product(name) values('"+name+"')";
            jdbcTemplate.execute(sql);
            if("MP4".equals(name)){
                throw new FileNotFoundException();
            }
        }
    }
    }


@EnableTransactionManagement
@SpringBootApplication
public class Demo16Application {
    //测试事务
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo16Application.class, args);
        System.out.println(context.getBean(JdbcTemplate.class));
        context.getBean(ProductDao.class).addProductBatch("TV","MP3","MP4");
    }
}


结果显示插入了,说明配置的事务失效。

1dc618a0ed9580ce8bfa6facb208c08f.png


3.控制事务回滚策略


上面的注意我们看到了,事务默认值对运行时异常起作用,那么我们怎么让我们的异常都用上事务呢?


我们看下Transactional的源码:

1dc618a0ed9580ce8bfa6facb208c08f.png


transactionManager 对多数据源下情况下有效

rollbackFor设置那些异常进行回滚,默认是运行时异常

noRollbackFor 设置不对那些异常进行回滚,默认是非运行时异常


刚才的案例如果改成:


@Transactional(rollbackFor = Exception.class)
    public void addProductBatch(String ... names) throws Exception {
        for (String name: names){
            //注意有sql注入的风险
            String sql = "insert into product(name) values('"+name+"')";
            jdbcTemplate.execute(sql);
            if("MP4".equals(name)){
                throw new FileNotFoundException();
            }
        }
    }


删除掉数据,再测试下:

1dc618a0ed9580ce8bfa6facb208c08f.png

显示回滚正常了。


4.特别注意2: 只对方法上加@Trancational的方法内的jdbc操作事务有效


只对方法上加@Trancational的方法内的jdbc操作事务有效,调用子方法,子方法上有这个注释无效。


测试下:


@Repository
public class ProductDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
  //直接调用的方法没加@Transactional注解,看下效果
    public void addProductBatch(String ... names) throws Exception {
       add(names);
    }
    @Transactional(rollbackFor = Exception.class)
    public void add(String ... names){
        for (String name: names){
            //注意有sql注入的风险
            String sql = "insert into product(name) values('"+name+"')";
            jdbcTemplate.execute(sql);
            if("MP4".equals(name)){
                throw new NullPointerException();
            }
        }
    }
    }


运行入口函数,然后看下数据库:


1dc618a0ed9580ce8bfa6facb208c08f.png

结果显示:事务失效,说明在直接调用jdbc操作数据库的方法上加@Transactional,事务才有效。


本篇主要围绕springboot2的jdbc展开讲了操作mysql,数据源的默认的5种,如何切换内置的数据源,定义自己的数据源,和事务的相关使用和注意事项。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
3月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1267 0
|
4月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
757 3
|
5月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
933 0
|
2月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
2月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
320 3
|
2月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
410 2
|
3月前
|
消息中间件 Ubuntu Java
SpringBoot整合MQTT实战:基于EMQX实现双向设备通信
本教程指导在Ubuntu上部署EMQX 5.9.0并集成Spring Boot实现MQTT双向通信,涵盖服务器搭建、客户端配置及生产实践,助您快速构建企业级物联网消息系统。
1372 1
|
5月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
9月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
815 79
|
7月前
|
监控 Java 调度
SpringBoot中@Scheduled和Quartz的区别是什么?分布式定时任务框架选型实战
本文对比分析了SpringBoot中的`@Scheduled`与Quartz定时任务框架。`@Scheduled`轻量易用,适合单机简单场景,但存在多实例重复执行、无持久化等缺陷;Quartz功能强大,支持分布式调度、任务持久化、动态调整和失败重试,适用于复杂企业级需求。文章通过特性对比、代码示例及常见问题解答,帮助开发者理解两者差异,合理选择方案。记住口诀:单机简单用注解,多节点上Quartz;若是任务要可靠,持久化配置不能少。
687 4

热门文章

最新文章