首页  

spring事务的一些知识点     所属分类 spring 浏览量 21
org.springframework.jdbc.datasource.DataSourceUtils
org.springframework.transaction.support.TransactionSynchronizationManager

1. 获取 DataSource
DataSource 是 Spring 管理的数据库连接池对象,通常通过依赖注入或上下文获取

方式1:通过 @Autowired 注入
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;

@Service
public class MyService {

    @Autowired
    private DataSource dataSource;

    public void doSomething() {
        // 使用 dataSource 获取连接
    }
}


方式2:通过 ApplicationContext 获取
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = context.getBean(DataSource.class);
    }
}


2. 获取 JDBC 连接
在 Spring 中,不建议直接使用 DataSource.getConnection(),因为这会绕过 Spring 的事务管理;

推荐通过以下方式获取连接:

方式1:使用 DataSourceUtils(推荐)
DataSourceUtils 是 Spring 提供的工具类,确保连接与当前事务绑定。

import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.Connection;

public class MyService {

    private final DataSource dataSource;

    public MyService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void doSomething() {
        Connection connection = DataSourceUtils.getConnection(dataSource);
        try {
            // 使用 connection 执行操作
        } finally {
            DataSourceUtils.releaseConnection(connection, dataSource); // 自动回滚或提交事务
        }
    }
}



方式2:使用 TransactionSynchronizationManager(高级)

如果需要手动绑定连接到当前事务,可以通过 TransactionSynchronizationManager 获取:

import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.sql.DataSource;
import java.sql.Connection;

public class MyService {

    private final DataSource dataSource;

    public MyService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void doSomething() {
        Connection connection = null;
        try {
            // 如果当前存在事务,返回绑定到事务的连接;否则返回新连接
            connection = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource().getConnection();
            // 使用 connection
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.close(); // 手动关闭连接
            }
        }
    }
}


TransactionAwareDataSourceProxy 是 Spring 对 DataSource 的代理,确保连接与事务绑定;
需要确保 DataSource 是通过 Spring 配置的代理对象


3. 在事务中获取连接

在 Spring 事务方法中,直接使用 JdbcTemplate 或 NamedParameterJdbcTemplate 是推荐的方式,因为它们会自动管理连接和事务

示例:使用 JdbcTemplate

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void doSomething() {
        jdbcTemplate.update("INSERT INTO users (name) VALUES (?)", "Alice");
    }
}


4. 手动管理连接(不推荐)
如果必须手动管理连接(例如执行原生 SQL),请确保连接与事务绑定,并在 finally 块中释放资源:

import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class MyService {

    private final DataSource dataSource;

    public MyService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Transactional
    public void doSomething() {
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            connection = DataSourceUtils.getConnection(dataSource);
            ps = connection.prepareStatement("INSERT INTO users (name) VALUES (?)");
            ps.setString(1, "Bob");
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (ps != null) ps.close();
                DataSourceUtils.releaseConnection(connection, dataSource); // 自动提交或回滚
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}



5. 关键点总结
场景	推荐方式
使用事务管理	JdbcTemplate 或 ORM 框架(如 MyBatis),Spring 自动管理连接和事务
手动获取连接(绑定事务)	使用 DataSourceUtils.getConnection(dataSource) 和 releaseConnection()
需要直接操作 Connection	确保通过 Spring 代理的 DataSource 获取连接,并绑定到当前事务
避免资源泄漏	在 finally 块中调用 releaseConnection() 或 close()

6. 常见问题
Q1: 为什么直接调用 DataSource.getConnection() 会出问题?
事务隔离:直接获取的连接不会参与 Spring 的事务管理,可能导致事务不一致
连接复用:Spring 事务中可能已经绑定了连接,直接获取会创建新连接,破坏事务上下文

Q2: 如何确保手动操作的连接与事务绑定?
使用 DataSourceUtils.getConnection(dataSource),Spring 会自动绑定到当前事务
使用 TransactionAwareDataSourceProxy 代理 DataSource


Q3: 是否需要显式关闭连接?
使用 DataSourceUtils.releaseConnection():会根据事务状态自动提交或回滚,并释放连接
直接调用 connection.close():可能破坏事务,仅在非事务场景下使用


7. 配置示例(Spring Boot)
在 Spring Boot 中,DataSource 通常由框架自动配置,只需注入即可:

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

通过以上方式,可以安全地在 Spring 中获取 DataSource 和 JDBC 连接,并确保与事务管理无缝集成

上一篇     下一篇
CPI PPI PMI

springboot自定义日志注解

词向量 Word Embedding

MyBatis Plus 动态数据源注解 @DS 注解

MyBatis Plus @DS注解原理

多个AOP切面注解 执行顺序说明