spring事务管理

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w1lgy/article/details/81625848 一、事务的相关概念概念 1、事务:事务指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w1lgy/article/details/81625848

一、事务的相关概念概念

1、事务:事务指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。这一组操作需要满足事务的四大特效(ACID)。
2、事务的传播行为:事务的传播行为是指在开始当前事务前,如果一个事务上下文已经存在,此时采取的事务执行行为。Spring 的 TransactionDefinition 接口中定义了如下的事务传播行为:

  • PROPAGATION_REQUIRED(默认) :如果当前已存在事务,则加入该事务;如果当前不存在事务,则创建一个新的事务。
  • PROPAGATION_REQUIRES_NEW :无论如何创建一个新的事务;如果当前存在事务,将当前事务挂起。
  • PROPAGATION_SUPPORTS :如果当前已存在事务,则加入事务;如果当前不存在事务,则以非事务方式执行。
  • PROPAGATION_NOT_SUPPORTED :以非事务方式执行;如果当前已存在事务,则将当前事务挂起。
  • PROPAGATION_NEVER :以非事务方式执行;如果当前已存在事务,则抛出异常。
  • PROPAGATION_MANDATORY :如果当前已存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
  • PROPAGATION_NESTED:如果当前已存在事务,则创建一个事务作为当前事务的嵌套事务执行;如果当前不存在事务,则创建一个新的事务。
    0679c98493b92f13fab6e51d8817b1754528e60d
    注:上述事务传播行为大同小异,一般记住默认的事务传播行为(PROPAGATION_REQUIRED)即可。值得注意的是,以 PROPAGATION_NESTED 启动的事务如果内嵌于外部事务中,此时内嵌事务并不是一个独立的事务。只有外部事务提交,内嵌事务才能提交,外部事务回滚也会导致内嵌事务回滚。内嵌事务依赖于外部事务而存在,内嵌事务相当于安全点的作用。
    3、事务的超时:事务超时是指一个事务所允许执行的最长时间。如果超过该时间事务还没执行完毕,则自动回滚事务。
    4、事务的只读属性:事务的只读属性是指对事务性资源(如数据库资源等)执行只读操作。比如事务只读属性设置为 true ,那么只能对数据库执行读操作(如 select ),不能执行写操作(如 insert、update 等)。当我们确定只对数据库进行只读操作时,开启该属性有利于提高事务处理的性能。
    5、事务的回滚规则:事务的回滚规则是指在抛出某些异常时事务的处理方式。默认情况下,如果事务抛出未检查异常(也称运行时异常,指所有继承自 RuntimeException 的异常),则回滚事务;如果没有抛出异常或抛出已检查异常,则提交事务。在实际应用中,我们可以自定义回滚规则,比如在抛出某些未检查异常时提交事务,抛出某些已检查异常时回滚事务。

二、事务的四大特性(ACID)

1、原子性(Atomicity):一个事务中的SQL,要么全部执行,要么全部不执行;

  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

2、一致性(Consistency):一个事务执行前后,数据库中的所有约束依然然满足;

  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

3、持久性(Durability):一个事务执行完成后,事务对数据的修修改必须持久化到数据库中。

  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

4、隔离性(Isolation):一个事务执行过程中,数据不受另一个事务的影响;

  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:

a、脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下

update account set money=money+100 where name=’B’;  (此时A通知B)
update account set money=money - 100 where name=’A’;

当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

b、不可重复读:不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

  例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……

c、虚读(幻读)

  幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

三、MySQL数据库的四种隔离级别:

① Serializable (序列化):可避免脏读、不可重复读、幻读的发生;性能最低,事务只能一个个执行,解决所有问题。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生,可能出现幻读现象(MySQL默认);。
③ Read committed (读已提交):可避免脏读的发生(大多数数据库默认);。
④ Read uncommitted (读未提交):最低级别,性能最高;事务中三种问题都可能产生;

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

在MySQL数据库中查看当前事务的隔离级别:

select @@tx_isolation;

193556c74f02ca496bfa899a2c7b3cbba083a35b
在MySQL数据库中设置事务的隔离 级别:

set  [glogal | session]  transaction isolation level 隔离级别名称;
set tx_isolation=’隔离级别名称;

7607d129776e40cd97e4cc6b6fb4c149eec7afec
或者:
a144007cfbc82378d9ea95e223b15d8c2b544b7e
注意:设置数据库的隔离级别一定要是在开启事务之前!
如果是使用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别,至于参数level,可以使用Connection对象的字段:
805432de3e0791d6417aaa463b3adbc37a4f05d2
在JDBC中设置隔离级别的部分代码:
b320bf32dc03bba8f06ee93e50a766c5f9e5a9e2
补充:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。

Spring 的 TransactionDefinition 接口中定义了五个表示隔离级别的常量,分别是:

ISOLATION_DEFAULT(默认) :表示采用底层数据库的隔离级别,比如底层数据库采用的是 MySQL ,则采用的隔离级别就是 REPEATABLE_READ 。
ISOLATION_READ_UNCOMMITTED :对应隔离级别 READ_UNCOMMITTED 。
ISOLATION_READ_COMMITTED :对应隔离级别 READ_COMMITTED 。
ISOLATION_REPEATABLE_READ :对应隔离级别 REPEATABLE_READ 。
ISOLATION_SERIALIZABLE :对应隔离级别 SERIALIZABLE 。

四、Spring提供了的两种事务管理方式:

1、编程式事务管理

PlatformTransactionManager实现编程式事务管理

步骤1、配置Spring事务管理器
springConfig.xml:

<?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-3.0.xsd
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 配置Spring自动扫描的目录 -->
    <context:component-scan base-package="com.prosay.transaction"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器) -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

步骤2、获取PlatformTransactionManager实例
步骤3、获取TransactionStatus对象,打开事务
步骤4、提交事务/回滚事务

@Component("orderService4Platform")
public class OrderService4Platform implements IOrderService {

    @Autowired
    private IOrderDao orderDao;

    @Autowired
    @Qualifier("productDaoImpl4Platform")
    private IProductDao productDao;

    @Autowired
    private PlatformTransactionManager transaction;

    public void createOrder(){
        //打开默认事务   
        TransactionStatus status = transaction.getTransaction(new DefaultTransactionDefinition());
        try {
            Order order = new Order();
            order.setOrder_id(104);
            order.setProduct_id(1004);
            order.setCustomer("Kevin");
            order.setNumber(100);
            int row = orderDao.insertOrder(order);

            System.out.println("添加订单影响行数:"+row);
            if(row>0){
                //下单成功,修改库存
                boolean falg = productDao.updateProduct(order);
                if(falg){
                    System.out.println("库存修改成功。");
                }else{
                    System.out.println("库存修改失败。");
                }
            }
            //通过事务管理器提交当前事务
            transaction.commit(status);
        } catch (Exception e) {
            //通过事务管理器回滚当前事务
            transaction.rollback(status);
            e.printStackTrace();
        }
    }
}
@Component("productDaoImpl4Platform")
public class ProductDaoImpl4Platform implements IProductDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public boolean updateProduct(Order order) {
        String sql = "update t_product set count = count-? where product_id=?";
        int row = jdbcTemplate.update(sql, order.getNumber(), order.getProduct_id());
//      MessageUtil.sendMessage();
        if(row>0){
            return true;
        }
        return false;
    }

}
@Component
public class OrderDaoImpl implements IOrderDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int insertOrder(Order order) {
        String sql = "insert into t_order(order_id, product_id, customer, number) values(?,?,?,?)";
        int row = jdbcTemplate.update(sql, order.getOrder_id(), order.getProduct_id(), order.getCustomer(), order.getNumber());
        System.out.println("execute row:"+row);
        return row;
    }

}
public class Client {

    public static void main(String[] args) {

        AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        IOrderService orderService = (IOrderService) context.getBean("orderService4Platform");
        orderService.createOrder();
    }
}

TransactionTemplate实现编程式事务管理

步骤1、配置Spring事务管理器
springConfig.xml

<?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-3.0.xsd
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 配置Spring自动扫描的目录 -->
    <context:component-scan base-package="com.prosay.transaction"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器)  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置TransactionTemplate -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
        <!-- 定义事务隔离级别 -->
        <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property>
        <!-- 定义事务传播属性 -->
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>
    </bean>
</beans>

步骤2、获取TransactionTemplate实例
步骤3、通过TransactionTemplate.execute(),打开事务环境

public class Client {

    public static void main(String[] args) {

        AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        IOrderService orderService = (IOrderService) context.getBean("orderService4Template");
        orderService.createOrder();
    }
}
@Component("orderService4Template")
public class OrderService4Template implements IOrderService {

    @Autowired
    private IOrderDao orderDao;

    @Autowired
    @Qualifier("productDaoImpl4Template")
    private IProductDao productDao;

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void createOrder(){
        Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
            public Integer doInTransaction(TransactionStatus status) {
                Order order = new Order();
                order.setOrder_id(104);
                order.setProduct_id(1004);
                order.setCustomer("Kevin");
                order.setNumber(100);
                int row = orderDao.insertOrder(order);

                System.out.println("添加订单影响行数:"+row);
                if(row>0){
                    //下单成功,修改库存
                    boolean falg = productDao.updateProduct(order);
                    if(falg){
                        System.out.println("库存修改成功。");
                    }else{
                        System.out.println("库存修改失败。");
                    }
                }
                return row;
            }
        });

    }
}
@Component("productDaoImpl4Template")
public class ProductDaoImpl4Template implements IProductDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public boolean updateProduct(Order order) {

        String sql = "update t_product set count = count-? where product_id=?";
        int row = jdbcTemplate.update(sql, 100, 1004);
//      MessageUtil.sendMessage();
        if(row>0){
            return true;
        }
        return false;
    }

}

2、声明式事务管理

注解实现声明式事务管理

步骤1、开启注解式事务管理
springConfig.xml

<?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-3.0.xsd
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 配置Spring自动扫描的目录 -->
    <context:component-scan base-package="com.prosay.transaction"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器)  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置启动注解方式使用事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

步骤2、使用@Transactional注解使用事务

public class Client {

    public static void main(String[] args) {

        AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        IOrderService orderService = (IOrderService) context.getBean("orderService4Annotation");
        orderService.createOrder();
    }
}
@Component("orderService4Annotation")
public class OrderService4Annotation implements IOrderService {

    @Autowired
    private IOrderDao orderDao;

    @Autowired
    @Qualifier("productDaoImpl4Annotation")
    private IProductDao productDao;

    @Transactional(propagation=Propagation.REQUIRED)
    public void createOrder(){
        Order order = new Order();
        order.setOrder_id(104);
        order.setProduct_id(1004);
        order.setCustomer("Kevin");
        order.setNumber(100);
        int row = orderDao.insertOrder(order);

        System.out.println("添加订单影响行数:"+row);
        if(row>0){
            try {
                //下单成功,修改库存
                boolean falg = productDao.updateProduct(order);
                if(falg){
                    System.out.println("库存修改成功。");
                }else{
                    System.out.println("库存修改失败。");
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
@Component("productDaoImpl4Annotation")
public class ProductDaoImpl4Annotation implements IProductDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public boolean updateProduct(Order order) {

        String sql = "update t_product set count = count-? where product_id=?";
        int row = jdbcTemplate.update(sql, 100, 1004);
//      MessageUtil.sendMessage();
        if(row>0){
            return true;
        }
        return false;
    }

}

补充:
在上例上OrderService4Annotation添加事务@Transactional(propagation=Propagation.REQUIRED) 和ProductDaoImpl4Annotation添加的事务@Transactional(propagation=Propagation.REQUIRES_NEW) 注解参数是事务的传播属性,上文已经提到REQUIRES_NEW表示当当前有事务时,挂起当前事务,新建事务,这就把这里的下单和修改库存变成两个事务了,由事务的隔离性,当修改库存时出现异常时,库存修改不会成功,事务会回滚;在createOrder方法中处理了修改库存的异常,所以createOrder不会抛出异常,下单的事务没有问题,事务不会回滚。这就会有下单成功,但是库存不会修改的情况。

TransactionTemplate实现编程式事务管理

步骤1、配置事务属性
步骤2、配置事务切点
springConfig.xml

<?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-3.0.xsd
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 配置Spring自动扫描的目录 -->
    <context:component-scan base-package="com.prosay.transaction"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/java?useSSL=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置Spring事务管理器(无论哪种方式都要这个事务管理器)  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean> 
    <!-- AOP配置声明式事务管理 -->
    <tx:advice id="advice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 方法名可以直接指定也可以用正则表达式去匹配,propagation是隔离级别属性,还可以加入其它属性 -->
            <tx:method name="createOrder" propagation="REQUIRED"  />
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut expression="execution(** com.prosay.transaction.service.*.*(..))" id="pointCut"/>
        <aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
    </aop:config>
</beans>
public class Client {

    public static void main(String[] args) {

        AbstractApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        IOrderService orderService = (IOrderService) context.getBean("orderService4Advice");
        orderService.createOrder();
    }
}
@Component("orderService4Advice")
public class OrderService4Advice implements IOrderService {

    @Autowired
    private IOrderDao orderDao;

    @Autowired
    @Qualifier("productDaoImpl4Advice")
    private IProductDao productDao;

    public void createOrder(){
        Order order = new Order();
        order.setOrder_id(104);
        order.setProduct_id(1004);
        order.setCustomer("Kevin");
        order.setNumber(100);
        int row = orderDao.insertOrder(order);

        System.out.println("添加订单影响行数:"+row);
        if(row>0){
            //下单成功,修改库存
            boolean falg = productDao.updateProduct(order);
            if(falg){
                System.out.println("库存修改成功。");
            }else{
                System.out.println("库存修改失败。");
            }
        }
    }
}
@Component("productDaoImpl4Advice")
public class ProductDaoImpl4Advice implements IProductDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public boolean updateProduct(Order order) {

        String sql = "update t_product set count = count-? where product_id=?";
        int row = jdbcTemplate.update(sql, 100, 1004);
//      MessageUtil.sendMessage();
        if(row>0){
            return true;
        }
        return false;
    }
}
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
4月前
|
Java 关系型数据库 MySQL
Spring 事务失效场景总结
Spring 事务失效场景总结
64 4
|
15天前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
31 1
Spring高手之路24——事务类型及传播行为实战指南
|
9天前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
15 3
|
2月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
2月前
|
Java 测试技术 数据库
Spring事务传播机制(最全示例)
在使用Spring框架进行开发时,`service`层的方法通常带有事务。本文详细探讨了Spring事务在多个方法间的传播机制,主要包括7种传播类型:`REQUIRED`、`SUPPORTS`、`MANDATORY`、`REQUIRES_NEW`、`NOT_SUPPORTED`、`NEVER` 和 `NESTED`。通过示例代码和数据库插入测试,逐一展示了每种类型的运作方式。例如,`REQUIRED`表示如果当前存在事务则加入该事务,否则创建新事务;`SUPPORTS`表示如果当前存在事务则加入,否则以非事务方式执行;`MANDATORY`表示必须在现有事务中运行,否则抛出异常;
143 4
Spring事务传播机制(最全示例)
|
1月前
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
32 2
|
1月前
|
Java 程序员 Spring
Spring事务的1道面试题
每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。
Spring事务的1道面试题
|
2月前
|
Java Spring
Spring 事务传播机制是什么?
Spring 事务传播机制是什么?
23 4
|
1月前
|
监控 Java 数据库
Spring事务中的@Transactional注解剖析
通过上述分析,可以看到 `@Transactional`注解在Spring框架中扮演着关键角色,它简化了事务管理的复杂度,让开发者能够更加专注于业务逻辑本身。合理运用并理解其背后的机制,对于构建稳定、高效的Java企业应用至关重要。
56 0
下一篇
无影云桌面