Spring框架-fifteen(spring声明式事务SM集成)

15-【掌握】spring声明式事务SM集成

1.以前的事务处理【编程式事务】

mybatis

从sqlSessionFactory里面得到sqlSession
使用sqlSession开启事务
执行crud 调用API
使用sqlSession提交事务
关闭sqlSession

2.为什么声明式事务要放在service层不放在dao层

dao 操作数据库的某一个张表
service 代表一个业务 可能会操作数据库 里面的多张表
–什么叫一个业务
|–转帐
Spring框架-fifteen(spring声明式事务SM集成)

3.,为什么要使用声明式事务

大多数Spring用户选择声明式事务管理的原因是,这个是对应用代码影响最小的选择,使用aop的特点在某个方法执行前开启事务,结束时提交事务,因此也最符合 非侵
入式 轻量级容器的理念。
1,Spring声明式事务管理可以在任何环境下使用。只需更改配置文件, 它就可以和JDBC、JDO、Hibernate或其他的事务机制一起工作。
2,Spring的声明式事务管理可以被应用到任何类(以及那个类的实例)上。
3,Spring提供了声明式的回滚规则。
add add* 需要事务 代表当前切面类里面的所有add开头的方法都要事务
update
delete
select 不用事务 read-only=true
4,Spring允许你通过AOP定制事务行为。(例如,如果需要,你可以在事务回滚中插入定制的行为。 你也可以增加任意的通知,就象事务通知一样。)。
5,Spring不提供高端应用服务器提供的跨越远程调用的事务上下文传播。如果你需要这些特性,我们推荐你使用EJB。 然而,不要轻易使用这些特性。因为通常我们并不希 望事务跨越远程调用。

3,Spring是如何实现声明式事务的
Spring的事务管理是通过AOP代理实现的。 其中的事务通知由元数据(目前基于XML或注解)驱动。
代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager 接口配合事务拦截器,在方法调用前后实施事务。
从概念上来说,在事务代理上调用方法的工作过程看起来像这样:
Spring框架-fifteen(spring声明式事务SM集成)

4.使用spring+mybatis集成完成声明式事务

1.创建项目并导包
spring
Spring框架-fifteen(spring声明式事务SM集成)
mybatis
|–mybatis-spring
Spring框架-fifteen(spring声明式事务SM集成)
mysql
Spring框架-fifteen(spring声明式事务SM集成)
2.创建项目并导包

3.创建User
Spring框架-fifteen(spring声明式事务SM集成)
4.创建UserMapper
Spring框架-fifteen(spring声明式事务SM集成)
5.创建UserMapper.xml、
Spring框架-fifteen(spring声明式事务SM集成)
6.创建UserService
Spring框架-fifteen(spring声明式事务SM集成)
7.创建UserServiceImpl

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserMapper userMapper;

	@Override
	public void addUser(User user) {
		userMapper.insertSelective(user);
	}

	@Override
	public void updateUser(User user) {
		userMapper.updateByPrimaryKeySelective(user);

	}
	@Override
	public void deleteUser(Integer userId) {

		userMapper.deleteByPrimaryKey(userId);
	}
	@Override
	public User queryUserById(Integer userId) {
		return userMapper.selectByPrimaryKey(userId);
	}
	@Override
	public List<User> queryAllUser() {
		return userMapper.queryAllUser();
	}

}

8.创建mybatis.cfg.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>

	<settings>
		<setting name="logImpl" value="LOG4J"/>
	</settings>
	<!-- 加载mybait数据库操作的映射文件 -->
	<mappers>
		<mapper resource="com/sxt/mapper/UserMapper.xml" />
	</mappers>
</configuration>

9.创建application-dao.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:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	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/context
	http://www.springframework.org/schema/context/spring-context.xsd
        ">
	<!-- 声明数据源 -->
	<bean id="dataSource" 
	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!-- 注入数据库的连接属性 -->
		<property name="driverClassName" value="com.mysql.jdbc.Driver">
		</property>
		<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"
		></property>
		<property name="username" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	<!-- 声明sqlSessionFactory -->
	<bean id="sqlSessionFactory" 
	class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 注入 数据源-->
		<property name="dataSource" ref="dataSource"></property>
		<!-- 注入mybatis的核心配置文件 -->
		<property name="configLocation" value="classpath:mybatis.cfg.xml">
		</property>
		
		<!-- 配置字段别名 -->
		<!-- <property name="typeAliasesPackage" 
		value="com.sxt.domain1,com.sxt.domain2" ></property> -->
		<!-- <property name="typeAliasesPackage" >
			<value>
				com.sxt.domain1
				com.sxt.domain2 
			</value>
		</property> -->
		
		<!-- 配置映射文件 -->
		<!-- <property name="mapperLocations" >
			<array>
				<value>classpath:com/sxt/mapper/*Mapper.xml</value>
			</array>
		</property> -->
		
	</bean>
	 
	 
	 <!-- 配置mapper的扫描 -->
	 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	 	<!-- 注入扫描的包 -->
	 	<!-- <property name="basePackage" value="com.sxt.mapper"></property> -->
	 	<property name="basePackage">
	 		<value>com.sxt.mapper</value>
	 	</property>
	 	<!-- <property name="basePackage">
	 		<value>com.sxt.mapper,com.bjsxt.mapper</value>
	 	</property>
	 	<property name="basePackage">
	 		<value>
	 		com.sxt.mapper
	 		com.bjsxt.mapper
	 		</value>
	 	</property> -->
	 	<!-- 注入sqlSessionFactory -->
	 	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">
	 	</property>
	 	
	 </bean>
	
	
	

</beans>


10.创建application-service.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:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	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/context
	http://www.springframework.org/schema/context/spring-context.xsd
        ">
     <!-- 扫描 -->
     <context:component-scan base-package="com.sxt.service.impl">
     </context:component-scan>

</beans>

11.创建applicationContext.xml
Spring框架-fifteen(spring声明式事务SM集成)
12.创建log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

13.测试
Spring框架-fifteen(spring声明式事务SM集成)

5.存在问题

修改UserServiceImpl里面的删除方法
Spring框架-fifteen(spring声明式事务SM集成)

测试
Spring框架-fifteen(spring声明式事务SM集成)

测试存在问题
发现92条数据被删除,而91没有被删除,但是两个删除方法在同一个service的方法里面调用 。应该是要么全部删除,要把全部不删除

6.使用纯XML的方式配置事务【掌握】

修改application-service.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:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	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
	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.sxt.service.impl">
	</context:component-scan>
	
	<!-- 声明一个事务管理器 -->
	<bean id="transactionManager" 
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 注入数据源 -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置事务的传播特性-->
	<tx:advice id="myAdvise" transaction-manager="transactionManager">	
		<!-- 配置方法的传播特性 -->
		<tx:attributes>
		
			<!-- 
			propagation  的属性值 说明
				REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入
				到这个事务中。这是最常见的选择。
				SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。  [不推荐]
				MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。  [不推荐]
				REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。  [不推荐]
				NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,
				就把当前事务挂起。 [不推荐]
				NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。 [不推荐]
				NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
				REQUIRED类 似的操作  【可能用到】
				read-only="true",只读事务,对数据库只能是查询操
				timeout :设置事务的超时时间  -1代表没有超时时间   500 如果service的方
				法500毫秒还执行完成,那么就回滚事务
			 -->
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="mod*" propagation="REQUIRED"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<tx:method name="del*" propagation="REQUIRED"/>
			<tx:method name="reset*" propagation="REQUIRED"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- 进行AOP织入 -->
	<aop:config>
		<!-- 声明切面 -->
		<aop:pointcut expression="execution(* com.sxt.service.impl.*.*(..))" 
		id="pc"/>
		<!-- <aop:pointcut expression="execution(* com.bjsxt.service.impl.*.*(..))" 
		id="pc2"/> -->
		<!-- 织入 -->
		<aop:advisor advice-ref="myAdvise" pointcut-ref="pc"/>
		<!-- <aop:advisor advice-ref="myAdvise" pointcut-ref="pc2"/> -->
	</aop:config>
</beans>

7.使用注解的试配置事务[重点掌握]

为什么会有注解的方式
1,因为springboot里面没有applicationContext.xml的配置文件了
2,XML的配置对方式的取名要求高
3,XML的配置不能精确到某一个方法的事务上

修改application-service.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:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	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
	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.sxt.service.impl">
	</context:component-scan>
	<!-- 声明一个事务管理器 -->
	<bean id="transactionManager" 
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 注入数据源 -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 开启注解事务 -->
	<tx:annotation-driven/>
	
</beans>

修改*ServiceImpl
Spring框架-fifteen(spring声明式事务SM集成)

8.使用spring+mybatis集成配置有mybatis.cfg.xml

分页jar包
Spring框架-fifteen(spring声明式事务SM集成)
Spring框架-fifteen(spring声明式事务SM集成)
修改mybatis.cfg.xml
配置日志输入
配置映射文件
配置分页插件
Spring框架-fifteen(spring声明式事务SM集成)
修改application-dao.xml的配置
Spring框架-fifteen(spring声明式事务SM集成)

9.使用spring+mybatis集成配置无mybatis.cfg.xml

删除mybatis.cfg.xml

修改application-dao.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:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	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/context
	http://www.springframework.org/schema/context/spring-context.xsd
        ">
	<!-- 声明数据源 -->
	<bean id="dataSource" 
	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!-- 注入数据库的连接属性 -->
		<property name="driverClassName" value="com.mysql.jdbc.Driver">
		</property>
		
		<property name="url" value="jdbc:mysql://127.0.0.1:3306/test">
		</property>
		<property name="username" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	
	<!-- 声明mybatis的配置 -->
	<bean id="configuration" class="org.apache.ibatis.session.Configuration">
		<!-- 设置日志输出形式 -->
		<property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl" 
		></property>
	</bean>
	<!-- 声明sqlSessionFactory -->
	<bean id="sqlSessionFactory" 
	class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 注入 数据源-->
		<property name="dataSource" ref="dataSource"></property>
		<!-- 配置configration  configLocation这两个属性不能同时存在-->
		<!-- <property name="configLocation" value="classpath:mybatis.cfg.xml">
		</property> -->
		<property name="configuration" ref="configuration"></property>
		<!-- 配置插件 -->
		<property name="plugins">
			<!-- 分页插件 -->
			<array>
				<bean class="com.github.pagehelper.PageInterceptor"></bean>
			</array>
		</property>
		<!-- 配置映射文件 -->
		<property name="mapperLocations" >
			<array>
				<value>classpath:com/sxt/mapper/*Mapper.xml</value>
				<!-- <value>classpath:com/bjsxt/mapper/*Mapper.xml</value> -->
			</array>
		</property>
		
	</bean>
	 
	 
	 <!-- 配置mapper的扫描 -->
	 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	 	<!-- 注入扫描的包 -->
	 	<!-- <property name="basePackage" value="com.sxt.mapper"></property> -->
	 	<property name="basePackage">
	 		<value>com.sxt.mapper</value>
	 	</property>
	 	<!-- <property name="basePackage">
	 		<value>com.sxt.mapper,com.bjsxt.mapper</value>
	 	</property>
	 	<property name="basePackage">
	 		<value>
	 		com.sxt.mapper
	 		com.bjsxt.mapper
	 		</value>
	 	</property> -->
	 	<!-- 注入sqlSessionFactory -->
	 	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">
	 	</property>
	 	
	 </bean>
	
	
	

</beans>