声明式事务管理

Spring 事务管理

1、事务添加到 Service 层

2、两种方式

(1)编程式事务管理:代码实现,不使用

(2)声明式事务管理:实际开发使用

3、声明式事务管理

(1)基于注解方式:实际开发使用

(2)基于 xml 配置文件方式

(3)底层使用 AOP

4、PlatformTransactionManager 接口:代表事务管理器,针对不同的框架提供不同的实现类

 

基于注解方式

1、配置

(1)xml:创建事务管理器,引入名称空间 tx,开启事务注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 开启注解(组件)扫描 -->
    <context:component-scan base-package="*"></context:component-scan>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc_url}" />
        <property name="username" value="${jdbc_user}" />
        <property name="password" value="${jdbc_password}" />

        <property name="filters" value="stat" />

        <property name="maxActive" value="20" />
        <property name="initialSize" value="1" />
        <property name="maxWait" value="6000" />
        <property name="minIdle" value="1" />

        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />

        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="20" />

        <property name="asyncInit" value="true" />
    </bean>

    <!-- 创建JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 创建事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

(2)配置类 + 注解

@Configuration
//开启组件扫描
@ComponentScan(basePackages = {"包路径"})
//开启事务
@EnableTransactionManagement
public class ConfigTX {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql://localhost:3306:druid");
        druidDataSource.setUsername("用户名");
        druidDataSource.setPassword("密码");
        //其余配置略
        return druidDataSource;
    }

    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        //到IOC容器中找到dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        //到IOC容器中找到dataSource
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        //注入dataSource
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

2、事务注解:@Transactional

(1)位置:类上 / 方法上

(2)如果把这个注解添加类上,这个类里面所有的方法都添加事务

(3)如果把这个注解添加方法上,只有这个方法添加事务

@Service
@Transactional
class TestService {
    @Autowired
    private Dao dao;

    public void transfer() {
        
        dao.reduce();
        dao.add();
    }
}

interface BaseDao {
    void add();

    void reduce();
}

@Repository
class Dao implements BaseDao {
    //注入JdbcTemplate对象
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add() {
        String sql = "update user set account=account+? where id=?";
        jdbcTemplate.update(sql, 1000, "1");
    }

    @Override
    public void reduce() {
        String sql = "update user set account=account-? where id=?";
        jdbcTemplate.update(sql, 1000, "2");
    }
}

 

@Transactional 参数配置

1、Propagation:事务传播行为:当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行

传播属性 描述
Propagation.REQUIRED 如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务,这是 Spring 默认的传播行为
Propagation.REQUIRES_NEW 不管是否存在事务,该方法总会为自己发起一个新的事务,如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建
Propagation.SUPPORTS 该方法在某个事务范围内被调用,则方法成为该事务的一部分,如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行
Propagation.NOT_SUPPORTED 声明方法不需要事务,如果方法没有关联到一个事务,容器不会为它开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行
Propagation.MANDATORY 该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务,如果在没有事务的环境下被调用,容器抛出异常
Propagation.NEVER 该方法绝对不能在事务范围内执行,如果在就抛异常,只有该方法没有关联到任何事务,才正常执行
Propagation.NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按 REQUIRED 属性执行,它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点,内部事务的回滚不会对外部事务造成影响,它只对 DataSourceTransactionManager 事务管理器起效

2、Isolation:事务隔离级别

隔离级别 脏读 不可重复读 幻读 加锁读
读未提交:Isolation.READ UNCOMMITTED 可能出现 可能出现 可能出现 不加锁
读已提交:Isolation.READ COMMITTED 不会出现 可能出现 可能出现 不加锁
可重复读:Isolation.REPEATABLE READ 不会出现 不会出现 可能出现 不加锁
可串行化:Isolation.SERIALIZABLE 不会出现 不会出现 不会出现 不加锁
Spring 默认:DEFAULT:使用数据库本身使用的隔离级别,ORACLE(读已提交) MySQL(可重复读)

3、timeout:超时时间

(1)事务需要在一定时间内进行提交,如果不提交,则进行回滚

(2)默认值:-1,表示没有超时时间

(3)设置时间以秒单位进行计算

4、readOnly:是否只读

(1)false:默认值,表示可以查询、添加、修改、删除操作

(2)true:只能查询

5、rollbackFor:回滚

(1)设置出现哪些异常进行事务回滚

6、noRollbackFor:不回滚

(1)设置出现哪些异常不进行事务回滚

 

基于 xml 配置文件方式

1、配置事务管理器

2、配置通知

3、配置切入点、切面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 开启注解(组件)扫描 -->
    <context:component-scan base-package="*"></context:component-scan>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc_url}" />
        <property name="username" value="${jdbc_user}" />
        <property name="password" value="${jdbc_password}" />

        <property name="filters" value="stat" />

        <property name="maxActive" value="20" />
        <property name="initialSize" value="1" />
        <property name="maxWait" value="6000" />
        <property name="minIdle" value="1" />

        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />

        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="20" />

        <property name="asyncInit" value="true" />
    </bean>

    <!-- 创建JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 创建事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置通知 -->
    <tx:advice id="txAdvice">
        <!-- 配置事务参数 -->
        <tx:attributes>
            <!-- 指定哪种规则的方法添加事务 -->
            <tx:method name="方法名" isolation="SERIALIZABLE"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut id="pt" expression="execution(* *..*.*(..))"/>
        <!-- 配置切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>
</beans>
posted @   半条咸鱼  阅读(59)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示