【小家Spring】Spring-jdbc的使用以及Spring事务管理的8种方式介绍(声明式事务+编程式事务)(上)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 【小家Spring】Spring-jdbc的使用以及Spring事务管理的8种方式介绍(声明式事务+编程式事务)(上)

前言


前面已经讲述了Spring Aop的原理以及源码分析~


若对Spring AOP还不是太了解的话,强烈建议出门左拐,先掌握AOP相关内容,因为Spring的事务管理就是基于Spring AOP实现的


本文主要讲解Spring-JDBC的使用以及它对事务的管理。

主要分为两大块:


1.Spring对jdbc的支持


2.Spring对事务的支持


源码展示基于Spring版本号为:5.1.6.RELEASE 下同下同下同

源码展示基于Spring版本号为:5.1.6.RELEASE 下同下同下同

源码展示基于Spring版本号为:5.1.6.RELEASE 下同下同下同


环境准备


Pom里导入相关jar(基于之前的工程基础上导包):

        <!-- 链接数据库  此处若你的MySql是8.0+版本,请使用8.0+版本的MySql驱动程序-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <!-- 含有spring-tx/core/beans等必须包  所有spring-tx可以不用再单独导入了-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>


配置文件:


@Configuration
public class JdbcConfig {
    // 此处只是为了演示 所以不用连接池了===========生产环境禁止这么使用==========
    @Bean
    public DataSource dataSource() {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setURL("jdbc:mysql://localhost:3306/jedi");
        return dataSource;
    }
     为了执行sql方便 此处采用JdbcTemplate进行===========
    // 生产环境一下一般我们不需要此配置,因为一般我们会使用ORM框架~
    // 但是如果是SpringBoot,这两个类默认都会配置上(导入了Spring-JDBC的jar即可)  比如MyBatis就是基于JDBC的
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    @Bean
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
        return new NamedParameterJdbcTemplate(dataSource);
    }
}


测试连接是否通畅:


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class, JdbcConfig.class})
public class TestSpringBean {
    @Autowired
    private DataSource dataSource;
    @Test
    public void test1() throws SQLException {
        System.out.println(dataSource); // com.mysql.jdbc.jdbc2.optional.MysqlDataSource@650eab8
        System.out.println(dataSource.getConnection()); // com.mysql.jdbc.JDBC4Connection@72bc6553
        System.out.println(jdbcTemplate); //org.springframework.jdbc.core.JdbcTemplate@66982506
        System.out.println(namedParameterJdbcTemplate); //org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate@70cf32e3
    }
}

Spring JDBC


为了使JDBC更加易于使用,Spring 在 JDBC API 上定义了一个抽象层,以此建立一个 JDBC 存取框架


说明:

在实际开发中,我们DAO层一般都会使用ORM框架(Mybatis,hibernate)等。在有些特殊的情况下,ORM框架的搭建略显笨重(比如下面我们演示Spring事务的时候)。这时最好的选择就是Spring中的jdbcTemplate了


JdbcTemplate和NamedParameterJdbcTemplate


jdbcTemplate提供的主要方法


1.execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;


2.update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;

batchUpdate方法用于执行批处理相关语句;


3.query方法及queryForXXX方法:用于执行查询相关语句;


4.call方法:用于执行存储过程、函数相关语句


Demo:


    @Test
    public void test1() throws SQLException {
        String sql = "select * from user where id = ?";
        // 默认情况下:它就是使用的PreparedStatement,所以不用担心Sql注入问题的
        RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);
        List<User> list = jdbcTemplate.query(sql, rowMapper, 1);
        User user = jdbcTemplate.queryForObject(sql, rowMapper, 1);
        System.out.println(list);
        System.out.println(user);
    }


NamedParameterJdbcTemplate提供的主要方法


在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制. 定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定,否则就绑定错了


在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter).

具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定. 具名参数更易于维护, 也提升了可读性. 具名参数由框架类在运行时用占位符取代


NamedParameterJdbcTemplate:是Spring2.0提供的,比JdbcTemplate出现得晚。它可以使用全部jdbcTemplate方法

// @since 2.0
public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {
  // 它持有一个JdbcTemplate的引用,所以它能够执行它所有的方法
  private final JdbcOperations classicJdbcTemplate;
  ...
}


Demo Show:


    @Test
    public void test1() throws SQLException {
        String sql = "insert into user (name,age) values (:name,:age)";
        User u = new User();
        u.setName("fsx2");
        u.setAge(20);
        SqlParameterSource sqlParameterSource = new BeanPropertySqlParameterSource(u);
        // 不需要id使用这个方法
        //namedParameterJdbcTemplate.update(sql,sqlParameterSource);
        // 这个可议把id输出出来
        KeyHolder keyHolder = new GeneratedKeyHolder();
        namedParameterJdbcTemplate.update(sql, sqlParameterSource, keyHolder);
        int k = keyHolder.getKey().intValue();
        System.out.println(k); //2  id就为2
    }

NamedParameterJdbcTemplate和JdbcTemplate有KeyHolder类,使用它我们可以获得主键,类似Mybatis中的useGeneratedKeys。


因为整体上直接使用JdbcTemplate来操作数据库的可能性几乎没有,所以此处只做一个简单的介绍,重点是后面的Spring事务的讲解~~


Spring事务


事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。


通常情况下,如果在事务中抛出了未检查异常(继承自 **RuntimeException** 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式


事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。


数据库向用户提供保存当前程序状态的方法,叫事务提交(commit);当事务执行过程中,使数据库忽略当前的状态并回到前面保存的状态的方法叫事务回滚(rollback)


Spring配置文件中关于事务配置总是由三个组成部分:


1.DataSource


2.TransactionManager


3.动态代理(核心内容)


DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化。DataSource实际为SessionFactory,TransactionManager的实现为 HibernateTransactionManager(MyBatis还是使用的DataSourceTransactionManager)

Spring Framework对事务管理提供了一致的抽象,其特点如下:


  • 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects)
  • 支持声明式事务管理,特别是基于注解的声明式事务管理,简单易用
  • 提供比其他事务API如JTA更简单的编程式事务管理API
  • 与spring数据访问抽象的完美集成


下面示例的事务管理器通知配置为:


@Configuration
public class JdbcConfig {
  ...
    // ==============Spring事务相关配置~~~==================
    // 必须配置一个事务管理器:此处用的DataSourceTransactionManager来管理事务~~~
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
        return dataSourceTransactionManager;
    }
    ...
}


业务类为:


public interface HelloService {
    Object hello();
}
@Service
public class HelloServiceImpl implements HelloService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public Object hello() {
        // 向数据库插入一条记录
        String sql = "insert into user (name,age) values ('fsx',21)";
        jdbcTemplate.update(sql);
        // 做其余的事情  可能抛出异常
        System.out.println(1 / 0);
        return "service hello";
    }
}



相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
64 0
|
3月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
162 0
|
15天前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
81 10
|
9天前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
74 1
|
8月前
|
Java 关系型数据库 MySQL
mysql5.7 jdbc驱动
遵循上述步骤,即可在Java项目中高效地集成MySQL 5.7 JDBC驱动,实现数据库的访问与管理。
1581 1
|
10月前
|
SQL druid Java
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(下)
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)
109 3
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(下)
|
10月前
|
SQL Java 关系型数据库
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(上)
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)
489 3
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(上)
|
8月前
|
SQL 分布式计算 关系型数据库
Hadoop-24 Sqoop迁移 MySQL到Hive 与 Hive到MySQL SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
Hadoop-24 Sqoop迁移 MySQL到Hive 与 Hive到MySQL SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
230 0
|
8月前
|
SQL 分布式计算 关系型数据库
Hadoop-23 Sqoop 数据MySQL到HDFS(部分) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
Hadoop-23 Sqoop 数据MySQL到HDFS(部分) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
103 0
|
8月前
|
SQL 分布式计算 关系型数据库
Hadoop-22 Sqoop 数据MySQL到HDFS(全量) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
Hadoop-22 Sqoop 数据MySQL到HDFS(全量) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
148 0