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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 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执行并未按照事务的原则执行。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
2月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
2月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
532 5
|
3月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
8月前
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
8月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
208 0
|
8月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
1120 0
|
8月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
229 0
|
4月前
|
安全 Java Nacos
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
|
5月前
|
中间件 关系型数据库 Go
Go语言数据库编程:数据迁移与事务控制
本文介绍了《Go语言实战指南》中关于数据库编程的核心内容,涵盖使用 GORM 进行数据迁移与事务控制。主要内容包括:AutoMigrate 方法自动创建或更新表结构;事务控制的自动与手动实现方式;事务隔离级别的设置;以及在 Gin 框架中统一管理事务的实践建议。适合开发阶段的数据库结构管理和事务性操作需求。
|
4月前
|
SQL XML Java
配置Spring框架以连接SQL Server数据库
最后,需要集成Spring配置到应用中,这通常在 `main`方法或者Spring Boot的应用配置类中通过加载XML配置或使用注解来实现。
433 0

热门文章

最新文章

下一篇
oss云网关配置