事务在项目开发过程主要是处理数据的一致性问题!!
事务是数据库在操作业务逻辑上的一组操作,要么都成功,如果有一个失败这一组操作都失败。
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。
假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。
就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!
事务有特性称为隔离性,设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和幻读。mysql默认隔离级别可重复读
jar包:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-study</artifactId>
<groupId>com.com.lmy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-06-transcation</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.22</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--使用aop时需导入该jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
</dependencies>
</project>
数据库持久层:
package com.lmy.dao.impl;
import com.lmy.dao.UserDao;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
/**
* @author : liu ming yong
* @date : 2022/8/14 上午 10:28
* @description : 数据库操作实现类
*/
public class UserDaoImpl implements UserDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public List<Map<String, Object>> getUser() {
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from tb_user");
return list;
}
@Override
public Integer addUser(Object[] ars) {
int update = jdbcTemplate.update("insert into tb_user(username,password,phone,created) values (?,?,?,?)",ars);
return update;
}
@Override
public Integer deleteUser(int id) {
int update = jdbcTemplate.update("delete from tb_user where id=?",new Object[]{id});
return update;
}
}
业务逻辑层:
package com.lmy.service.impl;
import com.lmy.dao.UserDao;
import com.lmy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @author : liu ming yong
* @date : 2022/8/14 下午 6:42
* @description : 用户业务逻辑实现类
*/
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public List<Map<String, Object>> getUser() {
List<Map<String, Object>> list = userDao.getUser();
Integer integer = userDao.addUser(new Object[]{"wangmazi8", "123", "17823594211", new Date()});
// 在新增后出现任何错误导致删除不成功时,都面临着事务是否要处理问题。若处理,getUser方法就是一个事务,新增会回滚。若不处理就会新增成功删除失败
// int i =1/0;
Integer update = userDao.deleteUser(33);
return list;
}
}
配置文件:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.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 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<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/db2?useSSL=false&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="userDao" class="com.lmy.dao.impl.UserDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="userService" class="com.lmy.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
</beans>
测试类:
package com.lmy;
import com.lmy.dao.UserDao;
import com.lmy.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @author : liu ming yong
* @date : 2022/8/14 上午 10:55
* @description : spring 事务测试类
*/
public class myTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("jdbc-resources.xml");
UserService userService = context.getBean("userService", UserService.class);
List<Map<String, Object>> list = userService.getUser();
System.out.println(list);
}
}
结果:未进行事务管理时结果为新增数据库成功,删除数据库失败
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
将事务管理作为横切关注点,通过spring的aop方法模块化。
aop所需jar包:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
声明式事务配置:
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--结合AOP实现事务织入,配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务(只有配置了事务的方法才会进行事务管理) *表示所有方法-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="aspect" expression="execution(* com.lmy.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="aspect"/>
</aop:config>
声明式事务结果:因逻辑失败导致删除无法成功,则新增被事务回滚,最后新增删除均不成功
将事务管理代码嵌到业务方法中来控制事务的提交和回滚