zoukankan      html  css  js  c++  java
  • spring事务管理中,注解方式和xml配置方式优先级谁高?

    在spring事务管理中,可以通过xml配置的方式去设置,也可以通过@Transactional注解去设置,那么这两种方式可以共存吗,如果可以共存,哪一种方式的优先级高呢?

    创建一个maven项目,导入maven依赖:

    	<dependencies>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-context</artifactId>
    			<version>5.2.6.RELEASE</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-core</artifactId>
    			<version>5.2.6.RELEASE</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-beans</artifactId>
    			<version>5.2.6.RELEASE</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-aspects</artifactId>
    			<version>5.2.6.RELEASE</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-jdbc</artifactId>
    			<version>5.2.6.RELEASE</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-tx</artifactId>
    			<version>5.2.6.RELEASE</version>
    		</dependency>
    
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>8.0.20</version>
    		</dependency>
    
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.13</version>
    			<scope>test</scope>
    		</dependency>
    
    	</dependencies>
    

    创建一个User实体类:

    public class UserEntity {
    
    	private long id;
    
    	private String userName;
    
    	private String userSex;
    
    	// 省略getter/setter
    }
    

    创建一个UserDao:

    public class UserDao {
    
    	private JdbcTemplate jdbcTemplate;
    
    	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    		this.jdbcTemplate = jdbcTemplate;
    	}
    
    	/**
    	 * 保存用户
    	 * 
    	 * @param user
    	 */
    	public void saveUser(UserEntity user) throws Exception {
    		StringBuilder sql = new StringBuilder();
    		sql.append("INSERT INTO t_user ( `id`, `user_name`, `user_sex` ) VALUES (").append(user.getId()).append(",'")
    				.append(user.getUserName()).append("',").append("'").append(user.getUserSex()).append("')");
    		System.out.println(sql.toString());
    		jdbcTemplate.execute(sql.toString());
    	}
    
    	/**
    	 * 通过id删除用户
    	 * 
    	 * @param id
    	 */
    	public void removeUserById(int id) throws Exception {
    		String sql = "delete from t_user where id=" + id;
    		System.out.println(sql.toString());
    		jdbcTemplate.execute(sql.toString());
    	}
    
    }
    

    创建UserService和UserServiceImpl:

    public interface UserService {
    	/**
    	 * 保存用户
    	 * 
    	 * @param user
    	 */
    	void saveUser(UserEntity user) throws Exception;
    
    	/**
    	 * 通过id删除用户
    	 * 
    	 * @param id
    	 */
    	void removeUserById(int id) throws Exception;
    }
    
    public class UserServiceImpl implements UserService {
    
    	private UserDao userDao;
    
    	public void setUserDao(UserDao userDao) {
    		this.userDao = userDao;
    	}
    
    	public void saveUser(UserEntity user) throws Exception {
    		userDao.saveUser(user);
    	}
    
    	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED, readOnly = false)
    	public void removeUserById(int id) throws Exception {
    		userDao.removeUserById(id);
    	}
    
    }
    

    创建数据库配置文件:

    jdbc.mysql.driverClass=com.mysql.cj.jdbc.Driver
    jdbc.mysql.url=jdbc:mysql://127.0.0.1:3306/learn_work?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    jdbc.mysql.username=root
    jdbc.mysql.password=root
    

    创建spring的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:jdbc.properties" />
    
    	<!-- 配置jdbcTemplate对象 -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    
    	<!-- 配置dataSource -->
    	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName" value="${jdbc.mysql.driverClass}" />
    		<property name="url" value="${jdbc.mysql.url}" />
    		<property name="username" value="${jdbc.mysql.username}" />
    		<property name="password" value="${jdbc.mysql.password}" />
    	</bean>
    
    	<!--配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
    	<!-- 开启注解配置事务支持 -->
     	<tx:annotation-driven transaction-manager="transactionManager"/>
     
     	<!-- xml声明式注解配置 -->
    	<!--配置AOP-->
        <aop:config>
            <!--通用切入点表达式-->
            <aop:pointcut id="pCut" expression="execution(* com.learn.service.impl.*.*(..))"/>
            <!--建立切入点和通知的对应关系-->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pCut"/>
        </aop:config>
        
        <!--配置事务的通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" propagation="REQUIRED" read-only="false"  isolation="DEFAULT" rollback-for="java.lang.Exception" />
            </tx:attributes>
        </tx:advice>
    
    	<!-- 配置userDao对象 -->
    	<bean id="userDao" class="com.learn.dao.UserDao">
    		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
    	</bean>
    	
    	<!-- 配置userService对象 -->
    	<bean id="userService" class="com.learn.service.impl.UserServiceImpl">
    		<property name="userDao" ref="userDao"></property>
    	</bean>
    
    </beans>
    

    配置文件里面同时配置了注解方式的事务声明和xml配置方式的事务声明,最终项目结构:
    在这里插入图片描述
    测试一下数据能否正常插入:

    public class Application {
    
    	private UserService userService;
    
    	@Before
    	public void init() {
    		@SuppressWarnings("resource")
    		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    		userService = (UserService) ctx.getBean("userService");
    	}
    
    	@Test
    	public void testSave() throws Exception {
    		UserEntity user = new UserEntity();
    		user.setId(100);
    		user.setUserName("张三");
    		user.setUserSex("男");
    		userService.saveUser(user);
    	}
    
    }
    

    数据库:
    在这里插入图片描述
    程序可以正常运行,下面进行正式测试。

    1.测试注解式事务声明和xml配置式事务声明能否共存:

    修改UserServiceImpl类中的实现方法:

    public void saveUser(UserEntity user) throws Exception {
    		userDao.saveUser(user);
    		int i = 1 / 0;// 发生异常事务是否回滚
    	}
    
    	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED, readOnly = false)
    	public void removeUserById(int id) throws Exception {
    		userDao.removeUserById(id);
    		int i = 1 / 0;// 发生异常事务是否回滚
    	}
    

    测试类:

    /**
    	 * 测试再次插入user
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void testSave2() throws Exception {
    		UserEntity user = new UserEntity();
    		user.setId(101);
    		user.setUserName("王麻子");
    		user.setUserSex("男");
    		userService.saveUser(user);
    	}
    
    	/**
    	 * 测试删除之前插入的id 100
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void testRemove() throws Exception {
    		userService.removeUserById(100);
    	}
    

    数据库结果:
    在这里插入图片描述
    可以看到,插入和删除操作都因为发生异常进行了事务回滚,说明注解式事务声明和xml配置式事务声明是可以共存的。

    2.测试注解方式和xml配置方式的优先级:

    修改spring的xml配置文件,指定remove方法的事务传播机制:

    <!--配置事务的通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" propagation="REQUIRED" read-only="false"  isolation="DEFAULT" rollback-for="java.lang.Exception" />
                <!-- remove开头的方法以非事务的方法运行 -->
                <tx:method name="remove*" propagation="NOT_SUPPORTED" />
            </tx:attributes>
        </tx:advice>
    

    再次运行删除的测试方法:

    /**
    	 * 测试删除之前插入的id 100
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void testRemove() throws Exception {
    		userService.removeUserById(100);
    	}
    

    可以在数据库看到,数据被删除了,也就是说xml里面配置了remove开头的方法不使用事务,虽然removeUserById使用@Transactional注解开启了事务管理,但是发生了异常以后事务并没有回滚,处于无事务管理状态,那么是不是说明xml配置方式优先级高于注解方式呢?

    修改一下配置文件,交换一下注解方式和xml配置方式配置代码的位置:

     	<!-- xml声明式注解配置 -->
    	<!--配置AOP-->
        <aop:config>
            <!--通用切入点表达式-->
            <aop:pointcut id="pCut" expression="execution(* com.learn.service.impl.*.*(..))"/>
            <!--建立切入点和通知的对应关系-->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pCut"/>
        </aop:config>
        
        <!--配置事务的通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" propagation="REQUIRED" read-only="false"  isolation="DEFAULT" rollback-for="java.lang.Exception" />
                <!-- remove开头的方法以非事务的方法运行 -->
                <tx:method name="remove*" propagation="NOT_SUPPORTED" />
            </tx:attributes>
        </tx:advice>
    
    	<!-- 开启注解配置事务支持 -->
     	<tx:annotation-driven transaction-manager="transactionManager" />
    

    重新插入一条id为100的数据,再次运行测试方法:
    在这里插入图片描述
    这次数据并没有删除,说明事务管理是生效的,发生异常以后事务回滚了,这时xml配置的事务管理失效了,到这里你应该明白了,注解方式和xml配置方式优先级谁高,取决于谁最后配置,最后配置会覆盖前面配置的属性。

    那有没有可以指定谁优先的方法呢,当然是可以的,可以借助order属性指定,order属性越大加载顺序越靠后,可以覆盖之前的属性,也就是优先级越高,修改配置文件,依旧把注解方式放在前面,但使用order指定顺序:

    <!-- 开启注解配置事务支持 -->
     	<tx:annotation-driven transaction-manager="transactionManager" order="2"/>
    	
     	<!-- xml声明式注解配置 -->
    	<!--配置AOP-->
        <aop:config>
            <!--通用切入点表达式-->
            <aop:pointcut id="pCut" expression="execution(* com.learn.service.impl.*.*(..))"/>
            <!--建立切入点和通知的对应关系-->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pCut" order="1"/>
        </aop:config>
        
        <!--配置事务的通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" propagation="REQUIRED" read-only="false"  isolation="DEFAULT" rollback-for="java.lang.Exception" />
                <!-- remove开头的方法以非事务的方法运行 -->
                <tx:method name="remove*" propagation="NOT_SUPPORTED" />
            </tx:attributes>
        </tx:advice>
    

    再次运行测试方法,可以发现数据依旧没有删除,说明removeUserById方法依然有事务。

    结论:
    1.注解方式和xml配置方式的事务管理可以共存;
    2.注解方式和xml配置方式优先级谁高,取决于谁最后加载,最后加载的设置会覆盖之前的设置。

    一颗安安静静的小韭菜。文中如果有什么错误,欢迎指出。
  • 相关阅读:
    MySQL学习笔记(六):索引
    正则表达式基础知识,持续更新…
    js改变盒子大小(上下左右)分析
    表单自定义样式
    js拖拽分析
    javascript右键菜单分析
    简要分析javascript的选项卡和轮播图
    表单联动的总结
    浅显总结ASCII Unicode UTF-8的区别
    瀑布流知识的延伸
  • 原文地址:https://www.cnblogs.com/c-Ajing/p/13448342.html
Copyright © 2011-2022 走看看