zoukankan      html  css  js  c++  java
  • spring事务实现方式有哪些?

    • 编程式事务管理,在代码中调用 commit()、rollback()等事务管理相关的方法

    maven pom.xml文件

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
     
    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.18</version>
    </dependency>
     

    编程式事务管理,可以通过 java.sql.Connection 控制事务。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"
        xmlns:context="http://www.springframework.org/schema/context"
        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">
            
        <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
     
        <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
            <constructor-arg index="0" name="driver" ref="driver" />
            <constructor-arg index="1">
                <value>jdbc:mysql://localhost:3306/test</value>
            </constructor-arg>
            <constructor-arg index="2">
                <value>root</value>
            </constructor-arg>
            <constructor-arg index="3">
                <value>root</value>
            </constructor-arg>
        </bean>
        
    </beans>

    测试代码

    package constxiong.interview.transaction;
     
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
     
    import javax.sql.DataSource;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    public class TransactionTest {
     
        public static void main(String[] args) throws Exception {
            testManualTransaction();//测试函数式控制事务
        }
        
        private static void testManualTransaction() throws SQLException {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
            DataSource ds = (DataSource)context.getBean("datasource");
            Connection conn = ds.getConnection();
            try {
                initTable(conn);//初始化表
                conn.setAutoCommit(false);//设置不自动提交事务
                queryUsers(conn);//查询打印用户表
                deleteUser(conn);//删除 id=1 用户
                conn.rollback();//回滚
                queryUsers(conn);//查询打印用户表
            } finally {
                conn.close();
            }
        }
     
        private static void initTable(Connection conn) throws SQLException {
            conn.createStatement().execute("drop table if exists user");
            conn.createStatement().execute("create table user(id int, username varchar(60)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ");//是否支持事务与数据库引擎有关,此处删除 ENGINE=InnoDB DEFAULT CHARSET=utf8 可能不支持事务
            conn.createStatement().execute("insert into user values(1, 'user1')");
            conn.createStatement().execute("insert into user values(2, 'user2')");
        }
     
        private static void deleteUser(Connection conn) throws SQLException {
            conn.createStatement().execute("delete from user where id = 1");
        }
     
        private static void queryUsers(Connection conn) throws SQLException {
            Statement st = conn.createStatement();
            st.execute("select * from user");
            ResultSet rs = st.getResultSet();
            while (rs.next()) {
                System.out.print(rs.getString("id"));
                System.out.print(" ");
                System.out.print(rs.getString("username"));
                System.out.println();
            }
        }
        
    }

    删除用户语句回滚,打印出两个用户

    1 user1
    2 user2
    1 user1
    2 user2
    • 基于 TransactionProxyFactoryBean 的声明式事务管理

    新增 UserDao 接口

    package constxiong.interview.transaction;
     
    import java.util.List;
    import java.util.Map;
     
    public interface UserDao {
     
        /**
         * 查询用户
         * @return
         */
        public List<Map<String, Object>> getUsers();
        
        /**
         * 删除用户
         * @param id
         * @return
         */
        public int deleteUser(int id);
        
    }

    新增 UserDao 实现

    package constxiong.interview.transaction;
     
    import java.util.List;
    import java.util.Map;
     
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
     
    public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
        
        /**
         * 查询用户
         * @return
         */
        public List<Map<String, Object>> getUsers() {
            String sql = "select * from user";
            return this.getJdbcTemplate().queryForList(sql);
        }
        
        /**
         * 删除用户
         * @param id
         * @return
         */
        public int deleteUser(int id){
            String sql = "delete from user where id = " + id;
            int result = this.getJdbcTemplate().update(sql);
            if (id == 1) {
                throw new RuntimeException();
            }
            return result;
        }
    }

    修改 spring 配置文件,添加事务管理器 DataSourceTransactionManager 和事务代理类 TransactionProxyFactoryBean

    <?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"
        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">
            
        <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
        
        <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
            <constructor-arg index="0" name="driver" ref="driver" />
            <constructor-arg index="1">
                <value>jdbc:mysql://localhost:3306/test</value>
            </constructor-arg>
            <constructor-arg index="2">
                <value>root</value>
            </constructor-arg>
            <constructor-arg index="3">
                <value>root</value>
            </constructor-arg>
        </bean>
        
        <bean id="userDao" class="constxiong.interview.transaction.UserDaoImpl">
            <property name="dataSource" ref="datasource"></property>
        </bean>
        
        <!-- 事务管理器 -->
        <bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="datasource"></property>
        </bean>
        
        <bean id="userProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <property name="transactionManager" ref="tracnsactionManager"></property>
            <property name="target" ref="userDao"></property>
            <property name="transactionAttributes">
                <props>
                    <!-- 主要 key 是方法   
                        ISOLATION_DEFAULT  事务的隔离级别
                        PROPAGATION_REQUIRED  传播行为
                    -->
                    <!-- -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
                    <prop key="deleteUser">-java.lang.RuntimeException</prop>
                </props>
            </property>
        </bean>
        
    </beans>

    测试代码

    package constxiong.interview.transaction;
     
    import java.util.Map;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    public class TransactionTest {
     
        static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
        
        public static void main(String[] args) throws Exception {
            testUseTransactionProxy(); //测试使用 spring TransactionProxyFactoryBean
        }
        
        private static void testUseTransactionProxy() {
            final UserDao userDao = (UserDao)context.getBean("userProxy");
            printUsers(userDao);//打印用户
            userDao.deleteUser(1);//删除 id=1 用户
        }
     
        private static void printUsers(UserDao userDao) {
            for (Map<String, Object> user : userDao.getUsers()) {
                System.out.println(user);
            }
        }
     
    }

     结果输出

    {id=1, username=user1}
    {id=2, username=user2}
    Exception in thread "main" java.lang.RuntimeException
        at constxiong.interview.transaction.UserDaoImpl.deleteUser(UserDaoImpl.java:28)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
        at com.sun.proxy.$Proxy3.deleteUser(Unknown Source)
        at constxiong.interview.transaction.TransactionTest.testUseTransactionProxy(TransactionTest.java:32)
        at constxiong.interview.transaction.TransactionTest.main(TransactionTest.java:13)

    • 基于注解 @Transactional 的声明式事务管理

    UserDaoImpl 删除用户方法添加注解 @Transactional(rollbackFor=RuntimeException.class) 出现 RuntimeException 回滚

    package constxiong.interview.transaction;
     
    import java.util.List;
    import java.util.Map;
     
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    import org.springframework.transaction.annotation.Transactional;
     
    public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
        
        /**
         * 查询用户
         * @return
         */
        public List<Map<String, Object>> getUsers() {
            String sql = "select * from user";
            return this.getJdbcTemplate().queryForList(sql);
        }
        
        /**
         * 删除用户
         * @param id
         * @return
         */
        @Transactional(rollbackFor=RuntimeException.class)
        public int deleteUser(int id){
            String sql = "delete from user where id = " + id;
            int result = this.getJdbcTemplate().update(sql);
            if (id == 1) {
                throw new RuntimeException();
            }
            return result;
        }
    }

    修改 spring 配置文件,开启 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"
        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/tx
            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
            
        <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
        
        <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
            <constructor-arg index="0" name="driver" ref="driver" />
            <constructor-arg index="1">
                <value>jdbc:mysql://localhost:3306/test</value>
            </constructor-arg>
            <constructor-arg index="2">
                <value>root</value>
            </constructor-arg>
            <constructor-arg index="3">
                <value>root</value>
            </constructor-arg>
        </bean>
        
        <bean id="userDao" class="constxiong.interview.transaction.UserDaoImpl">
            <property name="dataSource" ref="datasource"></property>
        </bean>
        
        <!-- 事务管理器 -->
        <bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="datasource"></property>
        </bean>
        
        <!-- 启用事务注解 -->
        <tx:annotation-driven transaction-manager="tracnsactionManager"/>
        
    </beans>

    测试代码

    package constxiong.interview.transaction;
     
    import java.util.Map;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    public class TransactionTest {
     
        static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
        
        public static void main(String[] args) throws Exception {
            testAnnotationTransaction();
        }
        
        
        private static void testAnnotationTransaction() {
            UserDao userDao = (UserDao)context.getBean("userDao");
            printUsers(userDao);
            userDao.deleteUser(1);
        }
     
     
        private static void printUsers(UserDao userDao) {
            for (Map<String, Object> user : userDao.getUsers()) {
                System.out.println(user);
            }
        }
     
    }

    输出结果

    {id=1, username=user1}
    {id=2, username=user2}
    Exception in thread "main" java.lang.RuntimeException
        at constxiong.interview.transaction.UserDaoImpl.deleteUser(UserDaoImpl.java:30)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
        at com.sun.proxy.$Proxy5.deleteUser(Unknown Source)
        at constxiong.interview.transaction.TransactionTest.testAnnotationTransaction(TransactionTest.java:20)
        at constxiong.interview.transaction.TransactionTest.main(TransactionTest.java:13)

    • 基于 Aspectj AOP 配置(注解)事务

    maven pom.xml 添加 Aspectj 的支持

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.13</version>
    </dependency>

    去除 UserDaoImpl 注解@Transactional(rollbackFor=RuntimeException.class)

    package constxiong.interview.transaction;
     
    import java.util.List;
    import java.util.Map;
     
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
     
    public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
        
        /**
         * 查询用户
         * @return
         */
        public List<Map<String, Object>> getUsers() {
            String sql = "select * from user";
            return this.getJdbcTemplate().queryForList(sql);
        }
        
        /**
         * 删除用户
         * @param id
         * @return
         */
        public int deleteUser(int id){
            String sql = "delete from user where id = " + id;
            int result = this.getJdbcTemplate().update(sql);
            if (id == 1) {
                throw new RuntimeException();
            }
            return result;
        }
    }

    修改 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"
        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/tx
            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
            
        <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
        
        <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
            <constructor-arg index="0" name="driver" ref="driver" />
            <constructor-arg index="1">
                <value>jdbc:mysql://localhost:3306/test</value>
            </constructor-arg>
            <constructor-arg index="2">
                <value>root</value>
            </constructor-arg>
            <constructor-arg index="3">
                <value>root</value>
            </constructor-arg>
        </bean>
        
        <bean id="userDao" class="constxiong.interview.transaction.UserDaoImpl">
            <property name="dataSource" ref="datasource"></property>
        </bean>
        
        <!-- 事务管理器 -->
        <bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="datasource"></property>
        </bean>
        
        <tx:advice id="txAdvice" transaction-manager="tracnsactionManager">
            <tx:attributes>
                <!-- 为连接点指定事务属性 -->
                <tx:method name="deleteUser" rollback-for="java.lang.RuntimeException"/>
            </tx:attributes>
        </tx:advice>
        
        <aop:config>
            <!-- 切入点配置 -->
            <aop:pointcut id="point" expression="execution(* *constxiong.interview.transaction.UserDao.deleteUser(..))" />
            <aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
        </aop:config>
        
    </beans>

    测试代码

    package constxiong.interview.transaction;
     
    import java.util.Map;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    public class TransactionTest {
     
        static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
        
        public static void main(String[] args) throws Exception {
            testAspectjTransaction();
        }
        
        
        private static void testAspectjTransaction() {
            UserDao userDao = (UserDao)context.getBean("userDao");
            printUsers(userDao);
            userDao.deleteUser(1);
        }
     
     
        private static void printUsers(UserDao userDao) {
            for (Map<String, Object> user : userDao.getUsers()) {
                System.out.println(user);
            }
        }
     
    }

    输出结果

    {id=1, username=user1}
    {id=2, username=user2}
    Exception in thread "main" java.lang.RuntimeException
        at constxiong.interview.transaction.UserDaoImpl.deleteUser(UserDaoImpl.java:28)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
        at com.sun.proxy.$Proxy2.deleteUser(Unknown Source)
        at constxiong.interview.transaction.TransactionTest.testAnnotationTransaction(TransactionTest.java:20)
        at constxiong.interview.transaction.TransactionTest.main(TransactionTest.java:13)

    PS:

    这篇仅用事务回滚为例,了解 spring 事务控制,还需要关注数据库的ACID四种特性、事务传播特性、事务的隔离级别(脏读、不可重复读、幻读)。

    详细可参考:https://blog.csdn.net/chinacr07/article/details/78817449

    spring 事务的源码学习可以参考:


    原文链接
     


     

  • 相关阅读:
    spring cloud 和 阿里微服务spring cloud Alibaba
    为WPF中的ContentControl设置背景色
    java RSA 解密
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Hystrix 配置参数全解析
    spring cloud 2020 gateway 报错503
    Spring Boot 配置 Quartz 定时任务
    Mybatis 整合 ehcache缓存
    Springboot 整合阿里数据库连接池 druid
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
  • 原文地址:https://www.cnblogs.com/ConstXiong/p/12123299.html
Copyright © 2011-2022 走看看