zoukankan      html  css  js  c++  java
  • Spring事务管理实现方式(注解,Xml)

    事务隔离级别和传播行为

    Isolation :隔离级别

    隔离级别是指若干个并发的事务之间的隔离程度,与我们开发时候主要相关的场景包括:脏读取、重复读、幻读。

    具体的设置方式(注解):例如@Transactional(isolation = Isolation.DEFAULT )

    隔离级别 含义
    DEFAULT 使用数据库默认的事务隔离级别
    READ_UNCOMMITTED 允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
    READ_COMMITTED 允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生
    REPEATABLE_READ 对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生
    SERIALIZABLE 完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。

    Propagation:传播行为

    所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。

    具体的设置方式(注解):@Transactional(propagation = Propagation.REQUIRED)

    传播行为 含义
    REQUIRED 表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
    MANDATORY 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
    NEVER 表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常
    NOT_SUPPORTED 表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行
    SUPPORTS 表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行
    NESTED 表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation_required的一样
    REQUIRES_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

    基于Aspectj AOP配置事务

    几点说明:

    导入外部资源文件

    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder
    

    注册组件包扫描,把类上标注了@Controller @Service @Repository @Component 都会自动加入到Spring容器中

     <context:component-scan base-package="zfcoding.tx.aspectaop"></context:component-scan>
    

    <tx:advice>配置一个事物通知,即执行的方法隔离级别和传播行为, <aop:config>配置事务通知在类上执行操作(切入点)。

      <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!-- 为连接点指定事务属性 -->
                <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <aop:config>
            <aop:pointcut id="point" expression="execution (* zfcoding.tx.aspectaop..*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor>
        </aop:config>
    

    实现步骤:

    ​ 1、定义数据库的配置文件(db.properties),定义业务类UserDao,UserService。

    ​ 2、定义Spring的配置文件(spring-aspect.xml)

    ​ 导入通过<context:property-placeholder>导入数据库配置文件,然后通过包扫描的方式<context:component-scan>把UserDao,UserService注册到Spring的容器当中,配置数据额源,JDBC 的模板,最后事务管理器,配置事务通知,切入点。

    配置文件(db.properties)

    db.username=root
    db.password=root
    db.url=jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
    db.driverClass=com.mysql.jdbc.Driver                             
    

    业务类(UserDao,UserService)

    @Repository
    public class UserDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        public void insertUser() {
            String sql = "INSERT INTO t_user (username,`password`) VALUES(?,?);";
            String username = UUID.randomUUID().toString().substring(0, 3);
            jdbcTemplate.update(sql, username, 12);
            System.out.println("插入成功");
            int i=10/0;
        }
    
    }
    
    @Service
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        public void insertUser() {
            userDao.insertUser();
        }
    }
    

    Spring配置文件(spring-aspect.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:aop="http://www.springframework.org/schema/aop"
           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/aop
    	http://www.springframework.org/schema/aop/spring-aop.xsd
    	http://www.springframework.org/schema/tx
    	http://www.springframework.org/schema/tx/spring-tx.xsd">
    
        <!-- 导入外部资源文件 -->
        <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
        <!--包扫描,把类上标注了@Controller @Service @Repository @Component 都会自动加入到Spring容器中-->
        <context:component-scan base-package="zfcoding.tx.aspectaop"></context:component-scan>
        <!-- 配置C3P0数据源 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="user" value="${db.username}"></property>
            <property name="password" value="${db.password}"></property>
            <property name="jdbcUrl" value="${db.url}"></property>
            <property name="driverClass" value="${db.driverClass}"></property>
        </bean>
        <!-- 配置Spring 的JdbcTemplate -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <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" transaction-manager="transactionManager">
            <tx:attributes>
                <!-- 为连接点指定事务属性 -->
                <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <aop:config>
            <aop:pointcut id="point" expression="execution (* zfcoding.tx.aspectaop..*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor>
        </aop:config>
    </beans>
    

    测试方法

    public class AspectTest {
        @Test
        public void aspectAop(){
            ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring-aspect.xml");
            UserService userService = applicationContext.getBean(UserService.class);
            userService.insertUser();
        }
    }
    

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

    基于注解实现

    第一步是在需要事务的类或者方法上面添加@Transactional() 注解,里面可以通过propagation和isolation指定事务的隔离级别和传播行为。

    @Service
    public class UserService {
    
        @Autowired
        private UserDao userDao;
        @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
        public void insertUser() {
            userDao.insertUser();
        }
    }
    

    @EnableTransactionManagement 来启用注解式事务管理,相当于之前在xml中配置的<tx:annotation-driven />注解驱动。

    通过包扫描@ComponentScan相当于 <context:component-scan>实现业务类注册到Spring容器当中。

    通过@PropertySource和 @Value实现读取配置文件,并且把之赋值到对应的属性当中。

    @Configuration 说明该类是一个配置类相当于(),@Bean 相当于(),注册数据源,JDBC模板,事务管理器。

    @EnableTransactionManagement
    @ComponentScan(basePackages = "zfcoding.tx")
    @PropertySource("classpath:db.properties")
    @Configuration
    public class MyDataSourceConfig {
    
        @Value("${db.username}")
        private String username;
        @Value("${db.password}")
        private String password;
        @Value("${db.url}")
        private String url;
        @Value("${db.driverClass}")
        private String driveClass;
    
        @Bean
        public DataSource dataSource() throws PropertyVetoException {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setUser(username);
            dataSource.setPassword(password);
            dataSource.setJdbcUrl(url);
            dataSource.setDriverClass(driveClass);
            return dataSource;
        }
    
        @Bean
        public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource());
            return jdbcTemplate;
        }
        //注册事务管理器在容器中
        @Bean
        public PlatformTransactionManager transactionManager() throws PropertyVetoException {
            return new DataSourceTransactionManager(dataSource());
        }
    }
    

    测试类

    public class TxTest {
        @Test
        public void test(){
            AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyDataSourceConfig.class);
            UserService userService = applicationContext.getBean(UserService.class);
            userService.insertUser();
        }
    }
    

    基于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:aop="http://www.springframework.org/schema/aop"
           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/aop
    	http://www.springframework.org/schema/aop/spring-aop.xsd
    	http://www.springframework.org/schema/tx
    	http://www.springframework.org/schema/tx/spring-tx.xsd">
    
        <!-- 导入外部资源文件 -->
        <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
        <!--包扫描,把类上标注了@Controller @Service @Repository @Component 都会自动加入到Spring容器中-->
        <context:component-scan base-package="zfcoding.xmltx"></context:component-scan>
        <!-- 配置C3P0数据源 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="user" value="${db.username}"></property>
            <property name="password" value="${db.password}"></property>
            <property name="jdbcUrl" value="${db.url}"></property>
            <property name="driverClass" value="${db.driverClass}"></property>
        </bean>
        <!-- 配置Spring 的JdbcTemplate -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <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"/>
    </beans>
    

    测试类

    public class XmlTxTest {
        @Test
        public void test(){
            ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:bean.xml");
            UserServiceXml userServiceXml = applicationContext.getBean(UserServiceXml.class);
            userServiceXml.insertUser();
        }
    }
    

    以上就是Spring 事务配置的全过程,完事。

    往期内容

    Spring IOC 知识点汇总

    Spring Aop 的实现方式(XML, 注解)

    深入理解Spring中Bean的生命周期

    我是阿福,公众号「阿福聊编程」作者,对后端技术保持学习爱好者,我会经常更新JAVA技术文章,在进阶的路上,共勉!

    欢迎大家关注我的公众号,后台回复666,领取Java全套进阶实战课程。

  • 相关阅读:
    P3834 【模板】可持久化线段树 (静态主席树)
    P3834 【模板】可持久化线段树 (静态主席树)
    2019 南昌网络赛 I. Max answer
    Linux从入门到精通——系统的进程
    Linux从入门到精通——文件权限
    Linux从入门到精通——命令行使用技巧
    Linux从入门到精通——Linux系统的文件及其管理
    Linux从入门到精通——vim及管理输入输出
    Linux从入门到精通——用户管理
    thiny mission 2021 10 15
  • 原文地址:https://www.cnblogs.com/xiaofuzi123456/p/13179571.html
Copyright © 2011-2022 走看看