Spring基础篇:Spring操作数据库的方式以及事务控制(上)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Spring操作数据库的方式以及事务控制(上)

以一个例子学习:

银行转账(用烂的萌新例子),当出错时,如何用Spring控制Mysql的事务。

前期准备

创建数据表

创建一个名字为account的数据表,列名有:

  • id: 主键自增
  • user_name: 用户名
  • money: 该用户有多少钱
CREATE TABLE account(
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    user_name VARCHAR(20),
    money INTEGER
);

数据表插入数据

往表里插入两条数据

INSERT INTO account (user_name,money) VALUES 
("chengyunlai",1000),
("yunlaicheng",1000);

Spring连接数据库需要依赖

这里使用的是Spring对JDBC操作封装的spring-jdbc

<!--Spring对JDBC的封装-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.framework.version}</version>
</dependency>

<!--java连接mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

数据源的配置

配置数据源,获得数据库的访问。在Spring中,我们需要配置的数据源在导入包spring-jdbc中,类名为:DriverManagerDataSource,按照IOC的思想就是,我们需要让Spring管理这个Bean。

DriverManagerDataSource类中我们可以发现一个set方法,即可以通过依赖注入的方式,注入DriverClassName驱动,因为我们是使用Java连接Mysql,所以这个驱动实现是mysql-connector-java,也就是导入的mysql-connector-javaJar包。

image.png

为什么填上com.mysql.jdbc.Driver就可以注入Driver类给setDriverClassName了呢?我们看setDriverClassName中有这样一句代码:

Class.forName(driverClassNameToUse, true, ClassUtils.getDefaultClassLoader());

是不是非常熟悉呢?通过放射的方式就可以实现了。

那么其他的url,username,password呢?我们可以发现DriverManagerDataSource继承了一个抽象类,而抽象类其中一个作用就是做一些子类重复做的事。

public class DriverManagerDataSource extends AbstractDriverBasedDataSource

果然在抽象类中定义了,那么就表示spring-jdbc可以通过driverClassName的不同操作其他不同的数据库了,这个大家可以按照我的思路去试一试其他的数据,这里还是以Mysql为主。
image.png

XML

回到正题,我们通过XML的方式将数据源进行配置,至于为什么这样做已经在上面展开。这里我们需要做的就是将DriverManagerDataSource交给Spring容器管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/juejin_sql"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
</beans>

注解

就是将New的对象交给Spring管理,也很简单。

@Configuration
public class JdbcAnnotationConfig {
    @Bean
    public DriverManagerDataSource driverManagerDataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/juejin_sql");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

测试数据源

以注解的方式为例子,拿到一个connection即可

public class JdbcAnnotationApplication {
    public static void main(String[] args) throws SQLException {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JdbcAnnotationConfig.class);
        DriverManagerDataSource bean = ctx.getBean(DriverManagerDataSource.class);
        Connection connection = bean.getConnection();
        System.out.println(connection);
    }
}

配置Template

我们是使用Template去执行SQL语句的,而Template需要指定数据源,这一步操作就不详细说啦,直接以XML为例:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

编写Dao

  • Dao需要注入Template
  • Dao需要完成两个动作,一个是加钱,一个是减钱

写一个BaseDao

为什么突然要写一个BaseDao?我们上面阅读的过程中发现抽象类可以完成重复动作的抽取,因为实际中我们需要写大量注入Template,所以我们将这个动作可以抽出来形成一个抽象类。

抽象类

@Component
public abstract class BaseDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }
}

定义接口

public interface AccountDao {
    // 加钱
    public void addMoney(Integer num);
    // 减钱
    public void reduceMoney(Integer num);
}

实现类
写了两个SQL,一个是用来加money的,一个是用来减money的。

@Repository
public class AccountDaoImpl extends BaseDao implements AccountDao {

    @Override
    public void addMoney(Integer id,Integer num) {
        this.getJdbcTemplate().update("UPDATE account SET money = money + ? WHERE  id = ?",num,id);
    }

    @Override
    public void reduceMoney(Integer id,Integer num) {
        this.getJdbcTemplate().update("UPDATE account SET money = money - ? WHERE  id = ?",num,id);
    }
}

编写Service

也就是一个普通的模拟一个账户加钱,一个账户减钱的操作。

@Service
public class AccountService {
    @Autowired
    AccountDao accountDao;
    // 一个交易方法
    public void deal(){
        accountDao.addMoney(1,100);
        accountDao.reduceMoney(2,100);
    }
}

直接通过启动类执行当然没问题,ok现在模拟一个出错。在两个方法之间加上int i = 1 / 0

发现问题

Exception in thread "main" java.lang.ArithmeticException: / by zero
首先会报这个错误,然后我们看数据库。

image.png

很好,事务的问题出现了。这两个SQL执行并未按照事务的原则执行。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
SQL 关系型数据库 MySQL
乐观锁在分布式数据库中如何与事务隔离级别结合使用
乐观锁在分布式数据库中如何与事务隔离级别结合使用
|
5天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
31 13
|
1月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
45 2
Spring高手之路26——全方位掌握事务监听器
|
1月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
8天前
|
SQL 存储 Java
数据库———事务及bug的解决
事务的一些概念,并发事务以及并发事务引起的bug,脏读,不可重复读,幻读,数据库中的隔离级别,事务的简单应用
|
2月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
61 1
Spring高手之路24——事务类型及传播行为实战指南
|
2月前
|
Java 关系型数据库 数据库连接
使用 Spring Boot 执行数据库操作:全面指南
使用 Spring Boot 执行数据库操作:全面指南
143 1
|
2月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
2月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
70 3
|
3月前
|
数据库
什么是数据库的事务隔离级别,有什么作用
【10月更文挑战第21】什么是数据库的事务隔离级别,有什么作用
26 3