Spring对事务的管理
1.Spring管理事务的接口
- 事务管理器接口(PlatformTransactionManager)
- 事务定义接口(TransactionDefinition)
2.事务管理的实现方式
- 通过配置xml实现事务的管理
- 利用注解实现事务的管理
下面用一个转账实例通过配置xml实现事务的管理,助于理解
项目目录
- dao层负责与数据库进行交互。dao层通常包含接口(interface),这些接口定义了与数据库交互的方法,例如增加、删除、修改和查询等等操作。
- impl(implementation缩写)软件包,通常用来放置这些接口的实现类。
这样的结构带来的好处:
- 分离接口和实现:这是一种常见的软件设计模式,称为接口分离原则。通过将接口与实现分离,可以提供更清晰的职责划分,并允许接口在不同实现之间的重用。
- 易于维护和扩展:如果将来需要更改数据访问的实现方式(例如,从JDBC切换到JPA或MyBatis),只需要在impl包中更改或添加新的实现类,而不需要修改接口或使用这些接口的代码。
- 便于测试:接口允许开发者编写更易于测试的代码。通过使用接口,可以在单元测试中轻松地替换真实的数据库实现类。
- 降低不同层之间的耦合度
数据库表格:
AliDaoImpl文件:
import com.qcby.dao.AlipayDao;
import org.springframework.jdbc.core.JdbcTemplate;
public class AlipayDaoImpl implements AlipayDao {
@Override
public void transfer(String fromA, String toB, Double money) {
jdbcTemplate.update("update affair set money = money-? where name = ? ",money,fromA);
//Integer a = Integer.valueOf("你好");
jdbcTemplate.update("update affair set money = money+? where name = ? ",money,toB);
}
/*
* 让A给B转账100
* @Param fromA
* @Param toB
* @param money
* */
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate(){
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
}
dao接口(AlipayDao):
定义了方法
public interface AlipayDao {
public void transfer(String fromA,String toB,Double money);
}
实体层entity(Alipay):
封装属性并生成get、set和tostring()方法
public class Alipay {
private String name;
private Double money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Alipay{" +
"name='" + name + '\'' +
", money=" + money +
'}';
}
}
测试类:
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Application.xml");
AlipayDao alipayDao = (AlipayDao) applicationContext.getBean("AlipayDaoImpl");
alipayDao.transfer("张三","李四",50.00);
}
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: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 https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置连接DriverManagerDataSource-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
<property name="username" value="root"/>
<property name="password" value="2020"/>
</bean>
<!--配置jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="AlipayDaoImpl" class="com.qcby.dao.impl.AlipayDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--定义事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--编写事务的通知-->
<!-- method标识匹配的切点方法都进行事务管理,这里*表示匹配的所有的切点方法,propagation="REQUIRED"表示匹配的切点方法必须在事务内执行。
isolation="DEFAULT"表示事务隔离级别默认,对于MySQL数据库,隔离级别为REPEATABLE_READ(可重复读),read-only="false"表示非只读。-->
<tx:advice id="txTransaction" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 将配置好的事务放到切入点当中-->
<aop:config>
<!--定义出切入点-->
<aop:pointcut id="transfer" expression="execution(* com.qcby.dao.impl.AlipayDaoImpl.transfer(..))"/>
<!-- 将事务和切入点组合-->
<aop:advisor advice-ref="txTransaction" pointcut-ref="transfer"/>
</aop:config>
</beans>
通知有五种(见小编Spring AOP一文)放到这边都不适用,因为我们这里需要将事务和通知放在一起。
正常情况下的运行结果(在AlipayDaoImpl中注释掉Integer a = Integer.valueOf("你好");这个人为设置的报错):
数据库结果:
张三变成了50,李四变成了150
如果人为加上错误
最后运行结果:
人为设置错误,数据库没有改变,证实了事务的特性,其中一旦有错,两条语句都不执行。