五、事務操作
- 五、事務操作
- 事務概念
- 1、什麼是事務
- (1)事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,如果有一個失敗所有操作都失敗
- (2)典型場景:銀行轉賬
- 2、事務特性(ACID)
- (1)原子性
- (2)一緻性
- (3)隔離性
- (4)持久性
- 事務操作(搭建事務操作環境)
- 1、建立資料庫表,添加記錄
- 2、建立service,搭建dao,完成對象建立和注入關系
- (1)service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource
- 建立子產品spring5_txdemo1/service/UserService
- dao/UseDao
- dao/UseDaoImpl
- 3、在dao建立兩個方法,多錢和少錢的方法,在service建立方法(轉賬的方法)
- UserDaoImpl
- UserService
- test/testTx
- 4、上面代碼,如果正常執行沒有問題的,但是如果代碼執行過程中出現異常,有問題
- (1)上面問題如何解決呢?
- (2)事務操作過程
- 事務操作(Spring事務管理介紹)
- 事務操作(注解聲明式事務管理)
- 1、在spring配置檔案配置事務管理器
- bean1.xml
- 2、在spring配置檔案,開啟事務注解
- (1)在spring配置檔案引入名稱空間tx
- (2)開啟事務注解
- 3、在service類上面(或者service類裡面的方法上面)添加事務注解
- 執行testAccount
- 事務操作(聲明式事務管理參數配置)
- 事務操作(XML聲明式事務管理)
- 1、在spring配置檔案中進行配置
- 第一步 配置事務管理器
- 第二步 配置通知
- 第三步 配置切入點和切面
- src/建立bean2.xml
- UserService
- testTX
- 事務操作(完全注解聲明式事務管理)
- 1、建立配置類,使用配置類替代xml配置檔案
- spring5/建立config包/建立TxConfig
- UserService
- testTX
說明
五、事務操作
事務概念
1、什麼是事務
(1)事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,如果有一個失敗所有操作都失敗
(2)典型場景:銀行轉賬
- lucy 轉賬100元給 mary
- lucy少100,mary多100
2、事務特性(ACID)
(1)原子性
(2)一緻性
(3)隔離性
(4)持久性
事務操作(搭建事務操作環境)
1、建立資料庫表,添加記錄
2、建立service,搭建dao,完成對象建立和注入關系
(1)service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource
建立子產品spring5_txdemo1/service/UserService
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
}
dao/UseDao
package com.atguigu.spring5.dao;
public interface UserDao {
}
dao/UseDaoImpl
package com.atguigu.spring5.dao;
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;
}
3、在dao建立兩個方法,多錢和少錢的方法,在service建立方法(轉賬的方法)
UserDaoImpl
//lucy轉賬100給mary
//少錢
@Override
public void reduceMoney() {
String sql="update t_account set money=money-? where username=?";
jdbcTemplate.update(sql,100,"lucy");
}
//多錢
@Override
public void addMoney() {
String sql="update t_account set money=money+? where username=?";
jdbcTemplate.update(sql,100,"mary");
}
UserService
//轉賬的方法
public void accountMoney(){
//lucy少100
userDao.reduceMoney();
//mary多100
userDao.addMoney();
}
test/testTx
package com.atguigu.spring5.test;
import com.atguigu.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testTX {
@Test
public void testAccount(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
}
4、上面代碼,如果正常執行沒有問題的,但是如果代碼執行過程中出現異常,有問題
(1)上面問題如何解決呢?
- 使用事務進行解決
(2)事務操作過程
事務操作(Spring事務管理介紹)
1、事務添加到JavaEE三層結構裡面Service層(業務邏輯層)
2、在Spring進行事務管理操作
(1)有兩種操作:程式設計式事務管理和聲明式事務管理(使用)
3、聲明式事務管理
(1)基于注解方式
(2)基于xml配置檔案方式
4、在Spring進行聲明式事務管理,底層使用AOP原理
5、Spring事務管理API
(1)提供一個接口,代表事務管理器,這個接口針對不同的架構提供不同的實作類
事務操作(注解聲明式事務管理)
1、在spring配置檔案配置事務管理器
bean1.xml
<!--建立事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入資料源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2、在spring配置檔案,開啟事務注解
(1)在spring配置檔案引入名稱空間tx
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/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">
(2)開啟事務注解
<!--開啟事務注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在service類上面(或者service類裡面的方法上面)添加事務注解
(1)@Transactional,這個注解添加到類上面,也可以添加到方法上面
(2)如果把這個注解添加到類上面,這個類裡面所有方法都添加事務
(3)如果把這個注解添加到方法上面,為這個方法添加事務
@Service
@Transactional
public class UserService {
執行testAccount
資料沒變
事務操作(聲明式事務管理參數配置)
1、在service類上面添加注解@Transactional,在這個注解裡面可以配置事務相關的參數
2、propagation:事務傳播行為
(1)多事務方法之間進行調用,這個過程中事務是如何進行管理的
3、isolation:事務隔離級别
(1)事務有特性,稱作隔離性,多事務操作之間不會影響。不考慮隔離性産生很多問題
(2)有三個讀問題:髒讀、不可重複讀、虛(幻)讀
(3)髒讀:一個為送出事務讀取到另一個為送出事務的資料
(4)不可重複讀:一個未送出事務讀取到另一送出事務修改資料
(5)虛讀:一個未送出事務讀取到另一送出事務添加資料
(6)通過設定事務隔離級别,解決讀問題
事務操作(XML聲明式事務管理)
1、在spring配置檔案中進行配置
第一步 配置事務管理器
第二步 配置通知
第三步 配置切入點和切面
src/建立bean2.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/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.atguigu"></context:component-scan>
<!-- 資料庫連接配接池 -->
<!-- 配置連接配接池 -->
<!-- DruidDataSource dataSource = new DruidDataSource(); -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close" >
<property name="url" value="jdbc:mysql://localhost:3306/user_db?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<!-- JdbcTemplate對象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--1 建立事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入資料源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2 配置通知 -->
<tx:advice id="txadvice">
<!-- 配置事務參數 -->
<tx:attributes>
<!-- 指定那種規則的方法上面添加事務 -->
<tx:method name="accountMoney" propagation="REQUIRED"/>
<!-- <tx:method name="account*"/>-->
</tx:attributes>
</tx:advice>
<!--3 配置切入點和切面-->
<aop:config>
<!-- 配置切入點 -->
<aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
</beans>
UserService
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
//@Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
//轉賬的方法
public void accountMoney(){
// try {
//第一步 開啟事務
//第二部 進行業務操作
//lucy少100
userDao.reduceMoney();
//模拟異常
int i=10/0;
//mary多100
userDao.addMoney();
//第三步 沒有發生異常,送出事務
// } catch (Exception e) {
//第四步 出現異常,事務復原
// }
}
}
testTX
@Test
public void testAccount1(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
事務操作(完全注解聲明式事務管理)
1、建立配置類,使用配置類替代xml配置檔案
spring5/建立config包/建立TxConfig
package com.atguigu.spring5.config;
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.atguigu") //元件掃描
@EnableTransactionManagement //開啟事務
public class TxConfig {
//建立資料庫連接配接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/user_db?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//JdbcTemplate對象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
//到IOC容器中根據類型找到dataSource
JdbcTemplate jdbcTemplate=new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//建立事務管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
UserService
package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
//轉賬的方法
public void accountMoney(){
// try {
//第一步 開啟事務
//第二部 進行業務操作
//lucy少100
userDao.reduceMoney();
//模拟異常
int i=10/0;
//mary多100
userDao.addMoney();
//第三步 沒有發生異常,送出事務
// } catch (Exception e) {
//第四步 出現異常,事務復原
// }
}
}
testTX
@Test
public void testAccount2(){
ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}