spring的声明式事务AOP

代码仓库:https://gitee.com/DerekAndroid/SpringTransaction.git

spring的声明式事务AOP-maven版-代码仓库:https://gitee.com/DerekAndroid/springaction.git

 关系图

一: spring的 jdbcTemplate

一: spring的 jdbcTemplate
	jdbcTemplate是spring提供的dao层用来和数据库数据交互的技术
 
回顾dao层操作数据库数据的技术:  
	    1 jdbc+c3p0            任何代码要想操作数据库的数据都得遵循jdbc规范
	    2 dbutils		   apache组织提供的对jdbc+c3p0的封装
	    3 hibernate		   对jdbc+c3p0的封装
	    4 jdbctemplate         spring对jdbc+c3p0的封装
	    5 hibernateTemplate    spring对hibernate又封装一次
	    6 mybatis		   对jdbc+c3p0的封装
	    7 SqlMapClientTemplate sping对mybatis又封装一次

A  mybatis
B  dbutils
c  hibernateTemplate

		
	   jdbctemplate -------- dbutils

	dbutils:  apache
		  QueryRunner qr=new QueryRunner();
		  qr.setDataSource(连接池)
		  String sql="crud"

		  qr.update()
		  qr.query()


	jdbctemplate: spring
		 jdbctemplate qr=new jdbctemplate();
		  qr.setDataSource(连接池)
		  String sql="crud"

		  qr.update()
		  qr.query()


	jdbctemplate的开发步骤:
		  1 导包
			 spring-jdbc.jar
			 spring-tx.jar 

		  2 对数据库的数据进行crud操作

		  3 作业: 在dao层使用jdbctempate对数据库数据进行crud操作
				写2遍即可

		 
	jdbctemplate在dao层有2种注入方式:
			 set方式注入  能使用注解
			 继承的方式  让jdbctemplate继承JdbcDaoSupport 不能使用注解

	hibernateTempalte也有这2中方式

二: spring的声明式事务

		回顾事务: 面试题

		事务有什么特性: ACID
		原子性: 一件完成的事情,要不全部成功 要不全部失败
			转账: 加钱 减钱
		一致性: 事务的前后,数据总数不发生变化
			jack 1000   rose 1000   2000
			jack 500    rose 1500   2000
		持久性: 只要事务已完成(提交),数据就会到数据库中

		隔离性: 事务具备隔离性,如果没有隔离性,会发送读取数据的问题

		不具备隔离性的话,会发生什么问题: 
			 会发送读取数据的问题
				脏读: 在一个事务中,读取到了另一个事务还没有提交的数据   必须杜绝的
						ps:所有的数据库都自动避免的脏读
				重复读:在一个事务中,2次读取到的数据内容不一致(update)    可以允许
				虚读/幻读:在一个事务中,2次读取到的数据内容不一致(insert) 可以允许

		可以通过调整数据库的隔离级别,避免以上问题的发生:
			设置隔离级别
					read uncommitted 效率最高 安全最低
					read committed oracle
					repeatable read mysql
					serializable  安全最高 效率最低


		事务的编写:
			   1 获取连接
			   2 通过连接开启事务 
				  con.setAutoCommit(false)
				  con.commit()
				  con.rollback()


			开启事务(spring提供的方法) 增强的方法
		    save() 切入点
			提交事务(spring提供的方法) 增强的方法


	 我得让spring提供的事务方法在指定的save之前执行,在save之后执行 ------AOP

			
					

以前的事务都得自己来编写操作,那spring给我们提供好了一套操作事务的封装,只要拿过来用即可

spring给我们提供了4种操作事务的方式:(掌握xml+注解)

API的方式

硬编码方式

,可以将提供好的API以代码的方式进行事务的控制 (没人用)  纯编码方式

package cn.itcast.jdbctempalte;

import java.beans.PropertyVetoException;


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class Demo
{
	@Test // 硬编码的方式
	public void test1() throws Exception
	{
		// c3p0
		ComboPooledDataSource ds = new ComboPooledDataSource();  //ioc
		ds.setDriverClass("com.mysql.jdbc.Driver");
		ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring04");
		ds.setUser("root");									// di
		ds.setPassword("1234");
		
		
		JdbcTemplate jdbcTemplate = new JdbcTemplate();   
		jdbcTemplate.setDataSource(ds);					
		String sql="insert into account values(?,?)";
		jdbcTemplate.update(sql, "jack",1000);
		
	}
	
	@Test // ioc+di
	public void test2()
	{
		ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
		JdbcTemplate jdbcTemplate =(JdbcTemplate)context.getBean("jdbcTemplate");
		String sql="insert into account values(?,?)";
		jdbcTemplate.update(sql, "rose",1000);
	}
}

纯注解方式

		  PlatformTransactionManager: 平台事务管理器  spring提供接口 封装事务的方法
				 提交方法
				 回滚方法
				我们要用只能找这个接口的实现类来用:
				DataSourceTransactionManager: dbutils jdbcTempalte  connnection
				切面类	 提交方法 回滚方法  通知/增强
				HibernateTransactionManager: hibernate hibernateTemplate session

 具体实现代码:

package cn.itcast.springconfig;

import java.beans.PropertyVetoException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
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 com.mchange.v2.c3p0.ComboPooledDataSource;

@Configuration
@ComponentScan(basePackages="cn.itcast")
@EnableTransactionManagement  //<tx:annotation-driven transaction-manager="transactionManager"/>
public class SpringConfig 
{
	// 创建出来c3p0 给spring
	@Bean(name="c3p0")
	public  DataSource createDataSourceC3p0() throws PropertyVetoException
	{
		ComboPooledDataSource ds = new ComboPooledDataSource();  //ioc
		ds.setDriverClass("com.mysql.jdbc.Driver");
		ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring04");
		ds.setUser("root");									// di
		ds.setPassword("1234");
		return ds;
	}
	
	@Bean(name="jdbcTemplate")
	public  JdbcTemplate createJdbcTemplate(@Qualifier("c3p0") DataSource ds)  // 使用注解问spring要
	{
		JdbcTemplate jdbcTemplate = new JdbcTemplate(); 
		jdbcTemplate.setDataSource(ds);
		return jdbcTemplate;
	}
	
	
	@Bean(name="transactionManager")
	public  DataSourceTransactionManager createDataSourceTransactionManager(@Qualifier("c3p0") DataSource ds)  // 使用注解问spring要
	{
		DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
		dataSourceTransactionManager.setDataSource(ds);
		return dataSourceTransactionManager;
	}
}

xml方式 (重点掌握)

底层就是API的封装 直接以xml方式告诉给sping即可 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: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/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
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!-- spring加载src下的properties文件 -->
	<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <!-- c3p0 -->
    <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>


	<!-- jdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="c3p0"></property>
	</bean>

	<!-- tranFerDao -->
	<bean id="tranFerDao" class="cn.itcast.daoimpl.TranFerDaoImpl">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	<!-- tranFerService 目标类 -->
	<bean id="tranFerService" class="cn.itcast.serviceimpl.TranFerServiceImpl">
		<property name="tranFerDao" ref="tranFerDao"></property>
	</bean>
	
	<!-- 切面类 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="c3p0"></property>
	</bean>
	<!-- 配置DataSourceTransactionManager里面事务方法的一些参数
		 不写 该方法使用的事务参数都是默认值
	 -->
	<tx:advice transaction-manager="transactionManager" id="txadvice">
			<tx:attributes>
				<tx:method name="tranfer"/>
			</tx:attributes>
	</tx:advice>
	
	<!-- 织入 -->
	<aop:config>
		<aop:pointcut expression="execution(* cn.itcast.serviceimpl.TranFerServiceImpl.tranfer(..))" id="pointcut"/>
		<!-- 针对事务的配置标签 -->
		<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/>
	</aop:config>

</beans>

注解配置: xml+注解(企业开发)

			   别人的 用xml

			   自己的 用注解
				<context:component-scan base-package="cn.itcast"></context:component-scan>

			   事务的注解2步:
					指定开启事务的注解 告诉spirng使用的事务方法是谁的方法
						<tx:annotation-driven transaction-manager="PlatformTransactionManager"/>

					在方法上或则是类上配置:
						@Transactional
<?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: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/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
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 别人的类 -->
<!-- spring加载src下的properties文件 -->
	<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <!-- c3p0 -->
    <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- jdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="c3p0"></property>
	</bean>
	
	<!-- 切面类 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="c3p0"></property>
	</bean>

<!-- 自己的类 -->
	
	<!-- 开启注解扫描器 -->
	<context:component-scan base-package="cn.itcast"></context:component-scan>

	<!-- 开启事务的注解配置 告诉使用的是哪个类下的事务 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
		
</beans>

在需要用到的类上配置

package cn.itcast.serviceimpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.itcast.dao.TranFerDao;
import cn.itcast.service.TranFerService;

@Service("tranFerService")
@Transactional
public class TranFerServiceImpl implements TranFerService
{
	@Autowired
	private TranFerDao tranFerDao;
	
	public void tranfer(String toUser,String inUser,double money) 
	{
		// 减钱
		tranFerDao.toMoney(toUser,money);
		int i=1/0;
		// 加钱
		tranFerDao.inMoney(inUser,money);
		
	}

	
}

junit测试

ps:junit报错,idea需要同事引入junit-4.12.jar+hamcrest-core-1.3.jar

package cn.itcast.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.itcast.service.TranFerService;

@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunit 
{
	@Autowired
	private TranFerService tranFerService;
	@Test
	public void test()
	{
		tranFerService.tranfer("jack", "rose", 500);
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章