本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1.注解式声明事物管理
<!--创建事物管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2.开启事物注解
1.在Spring配置文件,开启事物注解需要引入名称空间tx
<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/aop http://www.springframework.org/schema/aop/spring-aop.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">
2.创建tx注解开启
<!--开启事物注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3.在Service类上面(或者service类里面的方法上面)添加事物注解
@Transactional
- 下面为全部代码
- 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/aop http://www.springframework.org/schema/aop/spring-aop.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">
<!--开启组件扫描-->
<context:component-scan base-package="com.jdbc.account"></context:component-scan>
<!--数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<!--jdbctemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--创建事物管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事物注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
接口
package com.jdbc.account.service;
public interface UserDao {
//多钱
public void addMoney();
//少钱
public void reduceMoney();
}
- dao
package com.jdbc.account.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//多钱
@Override
public void addMoney() {
String sql = "update t_account set money = money+? where username=?";
jdbcTemplate.update(sql,100,"zhang");
}
//少钱 l转帐给zhang 100元
@Override
public void reduceMoney() {
String sql = "update t_account set money = money-? where username=?";
jdbcTemplate.update(sql,100,"lic");
}
}
- service
package com.jdbc.account.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
//转账操作,业务逻辑层
public void accountMoney() {
//lic少一百
int i = 10/0;
//出先异常进行事物回滚
userDao.reduceMoney();
//zhang 多一百
userDao.addMoney();
}
}
- 测试
package com.jdbc.account.service;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testMoney {
@Test
public void testAccount() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
}
3.事物操作声明事物管理参数配置
1.在service类上面添加的注解@Transactional,这个注解里面的参数配置
- propagation:事物传播行为:多事物方法直接调用,这个过程中事物是如何管理
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。 propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
propagation_required类似的操作Spring 默认的事务传播行是PROPAGATION_REQUIRED,它适合于绝大多数的情况。假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的 调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3个方法通过 Spring 的事务传播机制都工作在同一个事务中。
- ioslation:事物隔离性 事物有特性成为隔离性,多事物操作之间不会产生影响,不考虑隔离性产生很多问题 1.胀读:一个未提交的事物读取到另一个未提交事物的数据 2.不可重读:一个未提交的事物读取到另一个提交事物修改的数据 3.虚度:一个未提交事物读到另一个提交事物添加数据 4.解决:通过设置事物隔离级别,解决读问题
| 脏读 | 不可重读 | 幻读 | |
|---|---|---|---|
| READ UNCOMMITTED(读未提交) | 有 | 有 | 有 |
| READ COMMITTED(读已提交) | 无 | 有 | 有 |
| REPEATABLE READ(可重复读) | 无 | 无 | 有 |
| SERIALIZABLE(串行化) | 无 | 无 | 无 |
例如:设置隔离级别,MySQL默认是未REPEATABLE READ (可重读)
@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
- timeout :超时时间 1.事物需要在一定的时间类进行提交,如果不提交就进行回滚,其默认值为-1,设置时间以秒为单位进行计算
-
readOnly :是否只读 1.读:查询操作,写:添加修改操作 2.readOnly默认值是false,表示可以查询,可以添加修改删除操作,当设置为true是只能查询
-
rollbackFor :回滚 1.设置出现那些异常进行事物回滚
-
noRollbackFor :不回滚 1.设置出现那些异常不进行事物回滚
4.事物操作基于xml声明事物管理
1.在Spring配置文件进行配置
- 1.配置事物管理器
- 2.配置通知 增强的那一部分就叫通知
- 3.配置切入点和切面 把方法加入增强的地址
<?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/aop http://www.springframework.org/schema/aop/spring-aop.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">
<!--开启组件扫描-->
<context:component-scan base-package="com.jdbc.account"></context:component-scan>
<!--数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<!--jdbctemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置创建事物管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置通知-->
<tx:advice id="txadvice">
<!--配置事物参数-->
<tx:attributes>
<!--指定那这规则的方法上面添加事物-->
<tx:method name="accountMoney" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.jdbc.account.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
</beans>
进行测试
- 接口类
package com.jdbc.account.service;
public interface UserDao {
//多钱
public void addMoney();
//少钱
public void reduceMoney();
}
- dao
package com.jdbc.account.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//多钱
@Override
public void addMoney() {
String sql = "update t_account set money = money+? where username=?";
jdbcTemplate.update(sql,100,"zhang");
}
//少钱 l转帐给zhang 100元
@Override
public void reduceMoney() {
String sql = "update t_account set money = money-? where username=?";
jdbcTemplate.update(sql,100,"lic");
}
}
- service
package com.jdbc.account.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
//@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
//转账操作,业务逻辑层
public void accountMoney() {
//lic少一百
int i = 10/0;
//出先异常进行事物回滚
userDao.reduceMoney();
//zhang 多一百
userDao.addMoney();
}
}
- 测试
package com.jdbc.account.service;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testMoney {
@Test
public void testAccount() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
}
实现回滚,数据库不变
5.事物操作完全注解声明式事物管理
1.创建配置类,使用配置类代替xml配置文件
package com.jdbc.account.service;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration //配置类
@ComponentScan(basePackages = "com.jdbc") //开启组件扫描
@EnableTransactionManagement //开启事物
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/test");
druidDataSource.setName("root");
druidDataSource.setPassword("");
return druidDataSource;
}
//创建jdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
//到ioc容器中根据类型找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事物管理器
public DataSourceTransactionManager getDateSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}