1.什么是声明式事务控制
Spring的声明式事务:采用声明的方式来处理事务。
声明指的是在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。
Spring声明式事务控制底层就是AOP
主要注意的点:谁是切点,谁是通知,配置切面
2.基于XML的声明式事务控制
-
引入tx命名空间(Pom.xml引入
-
配置事务增强
-
配置事务AOP织入(ApplicationContext.xml
-
测试
tx:method 表示切点方法的事务参数的配置
Name: 切点方法的名称
Isolation:事务的隔离级别
Propogation:事务的传播行为
Timeout:超时时间
Read-only:是否只读
例子:计算库存与售出数量,若售出50件商品,库存数量减50,售出数据加50
** 引入tx命名空间(Pom.xml引入**
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Lab5-SpringAOP-2.1</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
配置事务增强 + 配置事务AOP织入 (applicationContext.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:context="http://www.springframework.org/schema/context"
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
http://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.hyy"></context:component-scan>
<!-- 数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--下面为加载类-->
<bean id="billDao" class="com.hyy.dao.impl.BillDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--目标对象 内部方法就是切点-->
<bean id="billService" class="com.hyy.service.impl.BillServiceImpl">
<property name="billDao" ref="billDao"></property>
</bean>
<!--配置平台事务管理器,得声明dao是jdbc还是hibernate-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--通知 事务的增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--设置事务的属性信息的-->
<tx:attributes>
<!--transfer是AccountServiceImpl有的方法,就是给Tranfer绑定事务-->
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<!--update是AccountServiceImpl有的方法,带*号就是给update开头的方法绑定事务
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>-->
<tx:method name="*"></tx:method>
</tx:attributes>
</tx:advice>
<!--配置事务的aop织入-->
<aop:config>
<!--抽取切点表达式-->
<aop:pointcut id="txPointcut" expression="execution(* com.hyy.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"></aop:advisor>
</aop:config>
</beans>
dao层(数据持久层
接口
package com.hyy.dao;
public interface BillDao {
public void in(String inStatus,int num);
public void out(String outStatus,int mun);
}
实现类
package com.hyy.dao.impl;
import com.hyy.dao.BillDao;
import org.springframework.jdbc.core.JdbcTemplate;
public class BillDaoImpl implements BillDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
//售出数量增加
@Override
public void in(String inStatus, int num) {
jdbcTemplate.update("update bill set num=num+? where status=?",num,inStatus);
}
//库存数量减少
@Override
public void out(String outStatus, int num) {
jdbcTemplate.update("update bill set num=num-? where status=?",num,outStatus);
}
}
实体类
package com.hyy.domain;
public class Bill {
private int id;
private String status;
private int num;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
服务层Service
接口
package com.hyy.service;
public interface BillService {
public void transfer(String inStatus,String outStatus,int num);
}
实现类
package com.hyy.service.impl;
import com.hyy.dao.BillDao;
import com.hyy.service.BillService;
public class BillServiceImpl implements BillService {
private BillDao billDao;
public void setBillDao(BillDao billDao) {
this.billDao = billDao;
}
@Override
public void transfer(String inStatus, String outStatus, int num) {
//售出数量增加
billDao.in(inStatus,num);
//查看能否事务控制,出错后是否会出现售出数量增加但是库存数量没有减少的情况
//int i=1/0;
//库存数量减少
billDao.out(outStatus,num);
}
}
测试
package com.hyy.text;
import com.hyy.service.BillService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BillTest {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BillService billService = context.getBean(BillService.class);
//售出+50 库存-50
billService.transfer("售出","库存",50);
}
}
测试结果
测试前
测试后
3.基于注解的声明式事务控制
- 1.编写Dao
- 2.编写Service
- 3.applicationContext.xml 配置文件
- 4.测试
注解声明式事务控制的配置要点:
1.使用@Transactional 在需要进行事务控制的类或是方法上修饰,注解可以用的属性同xml配置 方式,例如隔离级别,传播行为。
2.注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置
3.使用在方法上,不同方法可以采用不同的事务参数配置
4.xml配置文件中要开启事务的注解驱动tx:annotatio-driven
pom.xml
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Lab5-SpringAOP-2.2</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置平台事务管理器,得声明dao是jdbc还是hibernate-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--组件扫描-->
<context:component-scan base-package="com.hyy"/>
<!--事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
dao层(数据访问层
接口
package com.hyy.dao;
public interface BillDao {
public void in(String inStatus,int num);
public void out(String outStatus,int mun);
}
实现类
package com.hyy.dao.impl;
import com.hyy.dao.BillDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository("billDao")
public class BillDaoImpl implements BillDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void in(String inStatus, int num) {
jdbcTemplate.update("update bill set num=num+? where status=?",num,inStatus);
}
@Override
public void out(String outStatus, int num) {
jdbcTemplate.update("update bill set num=num-? where status=?",num,outStatus);
}
}
实体类
package com.hyy.domain;
public class Bill {
/*实体类*/
private int id;
private String status;
private int num;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
服务层Sevice
接口
package com.hyy.service;
public interface BillService {
public void transfer(String inStatus,String outStatus,int num);
}
实现类
package com.hyy.service.impl;
import com.hyy.dao.BillDao;
import com.hyy.service.BillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Service("billService")
@Transactional(isolation = Isolation.REPEATABLE_READ)//隔离事务
public class BillServiceImpl implements BillService {
@Autowired
private BillDao billDao;
@Override
public void transfer(String inStatus, String outStatus, int num) {
billDao.in(inStatus,num);
//int i=1/0;
billDao.out(outStatus,num);
}
}
测试
package com.hyy.text;
import com.hyy.service.BillService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BillTest {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BillService billService = context.getBean(BillService.class);
billService.transfer("售出","库存",50);
}
}