一、事务
1.事务(transaction)
事务是指一个完整的业务逻辑,一个不可再分的工作单元。
JavaEE事务逻辑一般添加到Service层中实现。
2.事务的四大特性
事务是恢复和并发的基本单位。
① 原子性(Atomicity)
② 一致性(Consistency)
③ 隔离性(Isolation)
④ 持久性(Durability)
3.Spring的事务管理
(1)编程式事务管理:编写程序代码实现管理
(2)声明式事务管理:在配置文件中进行事务规则声明,就可以将事务应用到业务逻辑中(常用)
二、声明式事务
声明式事务:在配置文件中进行事务规则声明,就可以将事务应用到业务逻辑中。底层使用aop实现事务管理
需要使用的jar包:
1.基于xml的声明式事务
配置文件applicationContext-xml.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
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:component-scan base-package="com.jd.tx"/>
<!--1.配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springjdbc"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</bean>
<!--2.配置jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--3.配置事务管理器,依赖于数据源(需要注入datasource)-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--4.编写通知,对事务进行增强处理-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
</tx:attributes>
</tx:advice>
<!--5.编写aop,让Spring自动对目标生成代理,需要使用AspectJ的表达式-->
<aop:config>
<!--切入点-->
<aop:pointcut id="txPointCut" expression="execution(* com.jd.tx.*.*(..))"/>
<!--切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
//Dao层接口AccountDao
public interface AccountDao {
public void transfer(String outUser, String inUser, double money);
}
//Dao层接口AccountDao的实现类AccountDaoImpl
@Repository(value = "accountDao")
public class AccountDaoImpl implements AccountDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void transfer(String outUser, String inUser, double money) {
String sql1 = "update account set balance=balance-? where username = ?";
this.jdbcTemplate.update(sql1,money,outUser);
// int i = 10/0;//模拟事务处理过程中的突发异常
String sql2 = "update account set balance=balance+? where username = ?";
this.jdbcTemplate.update(sql2,money,inUser);
}
}
测试:
@Test
public void xmlTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-xml.xml");
AccountDao accountDao = (AccountDao) context.getBean("accountDao");
accountDao.transfer("赵敏","张无忌",200.0);
System.out.println("转账成功...");
}
2.基于注解的声明式事务
@Transactional注解
1.@Transactional 注解的参数及描述
参数名称 | 描述 |
---|---|
value | 指定需要的事务管理器,默认为“”,其别名transactionManager |
transactionManager | 指定事务的限定符值,用于确定目标事务管理器,匹配特定的限定值(或Bean的name值),默认是“”,别名value |
isolation | 指定事务的隔离级别,默认为Isolation.DEFAULT |
noRollbackFor | 指定遇到特定异常时强制不回滚事务 |
noRollbackForClassName | 指定遇到特定的多个异常时强制不回滚事务 |
propagation | 指定事务的传播行为,默认为Propagation.REQUIRED |
read-only | 指定事务是否只读,默认false |
rollbackFor | 指定遇到特定异常的时强制回滚事务 |
rollbackForClassName | 指定遇到特定的多个异常时强制回滚事务。属性可以指定多个异常类名 |
timeout | 指定事务的超时时长,默认TransactionDefinition.TIMEOUT_DEFAULT |
说明:
① 事务传播行为:指在事务方法内调用另一个方法并将事务传递给它;
spring事务传播机制(针对被调用者) 有七种:REQUIRED(默认,有事务则加入,没有则创建)、REQUIRES_NEW(有事务就创建新事务)、NESTED、SUPPORTS、NOT_SUPPORTED、MANDATORY和NEVER。
② 隔离级别默认:可重复读(mysql);
③ timeout(超时):事务在一定的时间内进行提交,否则回滚;(设置以秒为单位,默认-1)
④ readOnly(是否只读):只读(true):查询;写(false,默认):CRUD操作;
2.注解方式实现事务两个步骤:
① 在Spring容器中注册事务注解驱动
<tx:annotation-driven transaction-manager="transactionManager"/>
② 在使用事务的类上或类的方法上添加注解@Transactional
(添加在Bean上,事务设置对Bean中的所有方法有效;添加在Bean的某个方法上,事务设置对该方法有效)
配置文件applicationContext-annotation.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
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:component-scan base-package="com.jd.tx"/>
<!--1.配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springjdbc"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</bean>
<!--2.配置jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--3.配置事务管理器,依赖于数据源-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--4.配置注册事务管理器驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Dao层接口AccountDao不改变,只需要在AccountDao的实现类AccountDaoImpl类的上方添加如下注解:
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
//isolation隔离级别默认是可重复读
测试:
@Test
public void annotationTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
AccountDao accountDao = (AccountDao) context.getBean("accountDao");
accountDao.transfer("赵敏","张无忌",200.0);
System.out.println("转账成功...");
}
3.完全注解开发实现声明式事务
完全注解开发:是指使用配置类完全替代配置文件实现开发,此处需要先导入数据库连接池的jar包druid-1.1.10.jar
@Configuration//声明当前类是配置类
@ComponentScan(basePackages = "com.jd.tx")//设置组件扫描
@EnableTransactionManagement//开启事务
public class MyConfig {
//创建数据库连接池
@Bean
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/springjdbc");
dataSource.setUsername("root");
dataSource.setPassword("12345678");
return dataSource;
}
//创建JdbcTemplate
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//在IOC中找到dataSource完成注入
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器对象
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
测试:
@Test
public void allAnnotationTest(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
AccountDao accountDao = (AccountDao) context.getBean("accountDao");
accountDao.transfer("张无忌","赵敏",200.0);
System.out.println("转账成功...");
}