这些天我看了一下《Spring FrameWork开发手册》这个技术文档,我翻阅了里面事务管理,现在在这里写下来,以后翻阅的时候可以复习一下:
个人认为Spring框架主要在于它的IOC和AOP以及事务管理,这里有时间再去介绍IOC和AOP,在Spring中事务管理可以有两种方式来进行:
1、声明式事务管理(基于注解)
2、编程式事务管理(基于xml)
大多时候都应该选择声明式事务管理,这对我们的业务代码影响最小,符合非入侵式编程。
一、声明式事务管理
Spring的声明式事务管理是通过SpringAOP实现的,Spring的声明式事务管理可以被应用到任何类(以及那个类的实例上),Spring提供了声明式的回滚规则,Spring允许你通过AOP定制事务行为。在理解Spring的声明式事务管理方面最重要的概念是:Spring事务管理是通过AOP实现的,其中的事务通知由元数据(目前基于XML或注解)驱动,代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatFormTransactionManager实现配合TranSactionInterceptor,在方法调用前后实施事务。
案例:
用maven创建一个项目名为transactionalAnnotation的项目,这里就简单的写一下:
pom.xml:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ry</groupId>
<artifactId>transactionalAnnotation</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>transactionalAnnotation Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<springframework>4.2.4.RELEASE</springframework>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- 引入Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${springframework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${springframework}</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
</dependencies>
<build>
<finalName>transactionalAnnotation</finalName>
</build>
</project>
在resource里面创建数据库配置文件jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm
jdbc.username=root
jdbc.password=root
接着创建spring-application.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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<bean id="studentService" class="com.ry.serviceImpl.StudentServiceImpl" />
<!-- 注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- don't forget the DataSource -->
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30" />
<property name="minPoolSize" value="10" />
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false" />
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000" />
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
当然web.xml也必须配置
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
创建StudentService.java:
public interface StudentService{
//基本业务 这里就不给参数了
public void addStu();
public void updateStu();
public List selectStu();
public int deleteStu();
}
创建StudentServiceImpl.java:
@Transactional
public class StudentServiceImpl implements StudentService {
// 事务:完成多个操作,只要一个中断或退出,其他操作的结果就不会被确认。即:一个整体性的操作
//为了测试事务 在这里抛出异常,阻止事务的继续进行
@Override
public void addStu() {
throw new NullPointerException();
}
@Override
public void updateStu() {
throw new NullPointerException();
}
@Override
public List selectStu() {
throw new NullPointerException();
//这里 抛出异常后 不要再加return了,不然会报错,不能通过编译
}
@Override
public int deleteStu() {
throw new NullPointerException();
}
}
接下来写一个测试:
public class TransactionTest {
@org.junit.Test
public void Test(){
ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-application.xml");
StudentService stu =(StudentService) ac.getBean("studentService");
stu.selectStu();
}
}
结果是会报空指针异常,当然如果你在ServiceImpl里面添加业务方法,由于空指针异常,这时事务会发生回滚。
二、编程式事务管理
编程式事务管理是基于xml的形式,与AOP一起结合使用,下面看一下实例:
使用maven创建项目transactional,maven的pom.xml配置以及其他的配置同上,主要是spring-application.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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<bean id="studentService" class="com.ry.serviceImpl.StudentServiceImpl" />
<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<!-- 查询只有只读权限 -->
<tx:method name="select*" read-only="true" />
<!-- 其他的方法用事务默认的 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- aop -->
<aop:config>
<aop:pointcut expression="execution(* com.ry.serviceImpl.*.*(..))" id="stuOperation" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="stuOperation" />
</aop:config>
<!-- don't forget the DataSource -->
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30" />
<property name="minPoolSize" value="10" />
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false" />
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000" />
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
这种是基于xml的配置。实际上在开发过程中会更加复杂,这里只是简单的介绍一下如何配置。