1. Spring框架的事务管理
1. PlatformTransactionManager接口 -- 平台事务管理器.(真正管理事务的类)。该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类!
2. TransactionDefinition接口 -- 事务定义信息.(事务的隔离级别,传播行为,超时,只读)
3. TransactionStatus接口 -- 事务的状态
4. 总结:上述对象之间的关系:平台事务管理器真正管理事务对象.根据事务定义的信息TransactionDefinition 进行事务管理,在管理事务中产生一些状态.将状态记录到TransactionStatus中
5. PlatformTransactionManager接口中实现类和常用的方法
1. 接口的实现类
* 如果使用的Spring的JDBC模板或者MyBatis框架,需要选择DataSourceTransactionManager实现类
* 如果使用的是Hibernate的框架,需要选择HibernateTransactionManager实现类
2. 该接口的常用方法
* void commit(TransactionStatus status)
* TransactionStatus getTransaction(TransactionDefinition definition)
* void rollback(TransactionStatus status)
6. TransactionDefinition
1. 事务隔离级别的常量
* static int ISOLATION_DEFAULT -- 采用数据库的默认隔离级别
* static int ISOLATION_READ_UNCOMMITTED
* static int ISOLATION_READ_COMMITTED
* static int ISOLATION_REPEATABLE_READ
* static int ISOLATION_SERIALIZABLE
2. 事务的传播行为常量
* 先解释什么是事务的传播行为:解决的是业务层之间的方法调用!!
A、B代表业务层的两个事务方法
* PROPAGATION_REQUIRED(默认值) -- A中有事务,使用A中的事务.如果没有,B就会开启一个新的事务,将A包含进来.(保证A,B在同一个事务中),默认值!!
* PROPAGATION_SUPPORTS -- A中有事务,使用A中的事务.如果A中没有事务.那么B也不使用事务.
* PROPAGATION_MANDATORY -- A中有事务,使用A中的事务.如果A没有事务.抛出异常.
* PROPAGATION_REQUIRES_NEW -- A中有事务,将A中的事务挂起.B创建一个新的事务.(保证A,B没有在一个事务中)
* PROPAGATION_NOT_SUPPORTED -- A中有事务,将A中的事务挂起.
* PROPAGATION_NEVER -- A中有事务,抛出异常.
* PROPAGATION_NESTED -- 嵌套事务.当A执行之后,就会在这个位置设置一个保存点.如果B没有问题.执行通过.如果B出现异常,运行客户根据需求回滚(选择回滚到保存点或者是最初始状态)
2. Spring框架的事务管理的分类
Spring的事务管理的分类
1. Spring的编程式事务管理(不常用)
* 通过手动编写代码的方式完成事务的管理
2. Spring的声明式事务管理
* 通过一段配置的方式完成事务的管理
2.1 编程式的事务管理
1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!!
2. 手动编程方式的具体步骤如下:
1. 步骤一:配置一个事务管理器,Spring使用PlatformTransactionManager接口来管理事务,所以咱们需要使用到他的实现类!!
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2. 步骤二:配置事务管理的模板
<!-- 配置事务管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
3. 步骤三:在需要进行事务管理的类中,注入事务管理的模板.
<bean id="accountService" class="com.yp.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
4. 步骤四:在业务层使用模板管理事务:
// 注入事务模板对象
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void pay(final String out, final String in, final double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
// 扣钱
accountDao.outMoney(out, money);
// 加钱
accountDao.inMoney(in, money);
}
});
}
2.2 声明式事务管理
声明式事务管理又分成两种方式
* 基于AspectJ的XML方式
* 基于AspectJ的注解方式
2.2.1 基于AspectJ的XML方式(JDBCTemplate)
1. 步骤一:配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2. 步骤二:配置事务增强
<!-- 配置事务增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
name :绑定事务的方法名,可以使用通配符,可以配置多个。
propagation :传播行为
isolation :隔离级别
read-only :是否只读
timeout :超时信息
rollback-for:发生哪些异常回滚.
no-rollback-for:发生哪些异常不回滚.
-->
<!-- 哪些方法加事务 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
3. 步骤三:配置AOP的切面
<!-- 配置AOP切面产生代理 -->
<aop:config>
<aop:pointcut expression="execution(* com.yichangapp.*.service.*Impl.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
2.2.2 基于AspectJ的注解方式
1. 步骤一:配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2. 步骤二:开启注解事务
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
3. 步骤三:在业务层上添加一个注解:@Transactional
3. 常用持久化框架配置
3.1 MyBatis配置
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局setting配置,根据需要添加 -->
<!-- 批量别名定义,扫描整个包下的类,首字母大写小写都可以,但程序可读性差
<typeAliases>
<package name="com.yichangapp.po"/>
</typeAliases>-->
</configuration>
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
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-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 加载数据库参数配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- c3p0数据库连接池 -->
<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}"/>
<!-- 还可以继续设置其他参数
... -->
</bean>
<!-- sqlSession的工厂类sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入sql映射的配置文件 -->
<property name="configLocation" value="classpath:mybatis/sqlMapConfig.xml"/>
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- mapper扫描器配置,直接将所扫描的包下的Mapper注入IOC容器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描包配置,如果需要配置多个包,使用半角逗号隔开 -->
<property name="basePackage" value="com.yichangapp.mine.mapper"/>
<!-- 注意这里是value,不是ref -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- Mybatis使用jdbc的事务控制器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务通知, 定义需要添加事务的方法-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- spring AOP 管理事务 -->
<aop:config>
<aop:pointcut expression="execution(* com.yichangapp.*.service.*Impl.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
3.2 Hibernate配置
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">none</property>
<!-- 懒加载,配合web.xml中配置的 openSessionInViewFilter -->
<property name="hibernate.enable_lazy_load_no_trans">true</property>
<!--校验模式 JPA java persistent api-->
<property name="javax.persistence.validation.mode">none</property>
<!-- 加载映射文件-->
<mapping resource="com/yichangapp/domain/Dept.hbm.xml"></mapping>
<mapping resource="com/yichangapp/domain/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/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">
<!-- c3p0数据源连接Oracle数据库 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />
<property name="jdbcUrl" value="jdbc:oracle:thin:@192.168.110.131:1521:orcl" />
<property name="user" value="yypp" />
<property name="password" value="xxxxx" />
</bean>
<!-- 加载hibernate.cfg.xml,注入dataSource获取session工厂 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<!-- 获取链接来管理事务,可以认为AOP将要织入的增强 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 通知或称增强,以及将要增强那些方法或可以说那些方法加事务 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="get*" read-only="true" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- AOP切面,即 通知 + 切入点 其实有时候目录很难组织事务管理,可以配置多个pointcut -->
<aop:config>
<aop:pointcut expression="execution(* com.yichangapp.*.service.*Impl.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
<!-- 导入其他模块的spring配置文件 -->
<import resource="classpath:applicationContext-dao.xml" />
<import resource="classpath:applicationContext-service.xml" />
</beans>