Spring对事务的支持

tech2022-11-03  102

Spring对事务的支持

对事务的支持无论是基于xml配置还是基于注解形式 底层原理都是通过AOP环绕增强的方式实现的,特点都是不改变原有的代码逻辑

数据库表格: 目的是:张三给李四转50时采用事务保证数据的可靠性,不会因为程序运行期错误导致转账出现问题

1.项目案例

创建MoneyDao接口及实现类并注入到Spring容器中 @Repository public class MoneyDaoImpl implements MoneyDao { @Autowired private JdbcTemplate template; @Override public void tranceOut(String name, Integer count) { template.update("update money set money=money-? where `name` =? ",count,name); } @Override public void tranceIn(String name, Integer count) { template.update("update money set money=money+? where `name` =? ",count,name); } } 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 https://www.springframework.org/schema/context/spring-context.xsd"> <!--将dao添加到Spring容器中--> <context:component-scan base-package="com.example.dao com.example.service"></context:component-scan> <!--加载配置文件--> <context:property-placeholder location="classpath:com/example/jdbc-config.properties"></context:property-placeholder> <!--放置连接池对象--> <bean name="database" class="com.alibaba.druid.pool.DruidDataSource"> <!--将配置文件参数传入连接池--> <property name="driverClassName" value="${jdbc.driverClassName}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="url" value="${jdbc.url}"></property> </bean> <!--将Spring支持的jdbcTemplate放入容器中--> <bean name="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="database" ></constructor-arg> </bean> </beans> 创建外部连接池配置文件 jdbc-config.properties jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///temporary?useUnicode=true&characterEncoding=UTF-8 jdbc.username=root jdbc.password=12345 创建service接口及实现类并注入到Spring容器中 @Service public class MoneyServiceImpl implements MoneyService { @Autowired private MoneyDao moneyDao; @Override public void thrance(String out, String in, Integer count) { moneyDao.tranceOut(out,count); int a = 10/0; //这里模拟运行期异常 moneyDao.tranceIn(in,count); } } 创建test类 @RunWith(SpringRunner.class) @ContextConfiguration("classpath:com/example/spring/spring-jdbc.xml") public class TestDemo3 { @Autowired private MoneyService moneyService; //测试增加 @Test public void testTrance(){ moneyService.thrance("张三","李四",50); } } 显示结果 张三的钱数少了,但是李四的钱数没有增加,这样的结果就是需要增加事务管理,防止数据出错

1.基于XML配置

核心对象 平台事务管理器(PlatformTransactionManager) 基于JDBC事务的实现: DataSourceTransactionManager将它注册到Spring 容器中。 <!--事务管理器--> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="database"></property> </bean> 使用事务的标签开启事务 <!--设置事务增强--> <tx:advice id = "txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--设置想要事务管理的方法名,并设置事务权限--> <tx:method name="thrance" read-only="false"/> </tx:attributes> </tx:advice> 使用AOP配置指定增强的方法 <aop:config> <!--表达式中第一个*表示返回值类型,中间用空格隔开--> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.service.impl.*ServiceImpl.*(..))"></aop:advisor> </aop:config> 使用另一种从容器中获取Bean的方式测试 public class Demo3 { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "classpath:com/example/spring/spring-jdbc.xml"); MoneyService moneyService = (MoneyService) context.getBean("moneyServiceImpl"); moneyService.thrance("张三","李四",50); } } 测试结果: 数据不变,并且程序报错

2.基于注解配置

在需要进行事务控制的类上(Service实现类)使用注解: @Transactional 此注解既可以使用在类上,也可以使用在方法上,加在类上表示所有的方法都被事务管理加在方法上表示只有该方法被事务管理 @Service @Transactional public class MoneyServiceImpl implements MoneyService { @Autowired private MoneyDao moneyDao; @Override public void thrance(String out, String in, Integer count) { moneyDao.tranceOut(out,count); int a = 10/0; moneyDao.tranceIn(in,count); } } 在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/context https://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"> <!--将dao添加到Spring容器中--> <context:component-scan base-package="com.example.dao com.example.service"></context:component-scan> <!--加载配置文件--> <context:property-placeholder location="classpath:com/example/jdbc-config.properties"></context:property-placeholder> <!--放置连接池对象--> <bean name="database" class="com.alibaba.druid.pool.DruidDataSource"> <!--将配置文件参数传入连接池--> <property name="driverClassName" value="${jdbc.driverClassName}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="url" value="${jdbc.url}"></property> </bean> <!--将Spring支持的jdbcTemplate放入容器中--> <bean name="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="database" ></constructor-arg> </bean> <!--事务管理器--> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="database"></property> </bean> <!--开启事务驱动--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans>

一般为了简化xml配置文件会将连接池的配置单独放在一个xml中,然后在这个里面进行引入import

在类上或者方法上加@Transactional可以设置readOnly属性: @Transactional(readOnly = false)

最新回复(0)