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);
	}

}

 

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