zoukankan      html  css  js  c++  java
  • Spring笔记04_AOP注解开发_模板_事务

    1. Spring基于AspectJ的注解的AOP开发

    1. 1 SpringAOP的注解入门

    • 创建项目,导入jar包

      • 需要导入Spring基础包4+2

      • 需要导入AOP联盟包、AspectJ包、Spring整合Aspect包Spring-aop包

      • Spring整合单元测试包

    • 引入配置文件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: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.xsd
      	http://www.springframework.org/schema/context
      	http://www.springframework.org/schema/context/spring-context.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">
      	
      </beans>
      
    • 编写目标类并配置

      package com.itzhouq.spring.demo1;
      
      public class OrderDao {
      	public void save() {
      		System.out.println("保存订单。。。");
      	}
      	public void update() {
      		System.out.println("修改订单。。。");
      	}
      	public void find() {
      		System.out.println("查找订单。。。");
      	}
      	public String delete() {
      		System.out.println("删除订单。。。");
      		return "周杰伦";
      	}
      }
      
    • 配置目标类,将目标类OrderDao交给Spring管理

      • 在applicationContext.xml中添加
      <!-- 配置目标类 -->
      	<bean id="orderDao" class="com.itzhouq.spring.demo1.OrderDao"></bean>
      
    • 编写切面类并配置

      package com.itzhouq.spring.demo1;
      /*
       * 切面类:注解的切面类
       */
      public class MyAspectAnno {
      	
      	public void before() {
      		System.out.println("前置增强===============");
      	}
      }
      
      <!-- 配置切面类 -->
      	<bean id="myAspect" class="com.itzhouq.spring.demo1.MyAspectAnno"></bean>
      
    • 使用注解的AOP对目标类的方法进行增强

      • 首先在配置文件中打开注解的AOP开发

        <!-- 在配置文件总开启注解的AOP开发 -->
        	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        
      • 在切面类上使用注解

        /*
         * 切面类:注解的切面类
         */
        @Aspect	//标记该类为切面类
        public class MyAspectAnno {
        	
        	@Before(value="execution(* com.itzhouq.spring.demo1.OrderDao.save(..))")
        	public void before() {//这个注解用来标记目标类的哪个方法使用何种增强
        		System.out.println("前置增强===============");
        	}
        }
        
    • 测试

      package com.itzhouq.spring.demo1;
      
      import javax.annotation.Resource;
      
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      /*
       * Spring的AOP注解开发测试
       */
      
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext.xml")
      public class SpringDemo1 {
      	@Resource(name="orderDao")	//注入OrderDao
      	private OrderDao orderDao;
      	
      	@Test
      	public void test1() {
      		orderDao.save();
      		orderDao.update();
      		orderDao.find();
      		orderDao.delete();
      //		前置增强===============
      //		保存订单。。。
      //		修改订单。。。
      //		查找订单。。。
      //		删除订单。。。
      
      	}
      }
      

    1.2 Spring的AOP的注解通知类型

    1.2.1 @Before:前置通知

    1.2.2 @AfterReturning:后置通知

    • 在删除delete方法上使用后置通知

    • 在切面类中添加以下方法

      //后置通知
      	@AfterReturning("execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))")
      	public void afterReturning() {
      		System.out.println("后置增强==================");
      	}
      
    • 不用修改目标类直接测试就能实现效果

      前置增强===============
      保存订单。。。
      修改订单。。。
      查找订单。。。
      删除订单。。。
      后置增强==================
      
    • 后置通知还可以使用返回值

      //后置通知
      	@AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result")
      	public void afterReturning(Object result) {
      		System.out.println("后置增强=================="+result);
      	}
      
      前置增强===============
      保存订单。。。
      修改订单。。。
      查找订单。。。
      删除订单。。。
      后置增强==================周杰伦
      

    1.2.3 环绕通知

    • 在切面类中添加以下方法:

      //环绕通知
      	@Around(value="execution(* com.itzhouq.spring.demo1.OrderDao.update(..))")
      	public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
      		System.out.println("环绕前增强===========");
      		Object obj = joinPoint.proceed();
      		System.out.println("环绕前增强===========");
      		return obj;
      	}
      
    • 测试

      前置增强===============
      保存订单。。。
      环绕前增强===========
      修改订单。。。
      环绕前增强===========
      查找订单。。。
      删除订单。。。
      后置增强==================周杰伦
      

    1.2.4 异常抛出通知

    • 异常抛出通知可以获得异常信息

    • 在切面类中添加方法

      	//异常抛出通知
      	@AfterThrowing(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))",throwing="e")
      	public void afterThrowing(Throwable e) {
      		System.out.println("异常抛出通知============"+e);
      	}
      
    • 在find方法中模拟异常

      public void find() {
      		System.out.println("查找订单。。。");
      		int i = 1 / 0;
      	}
      
    • 测试

      前置增强===============
      保存订单。。。
      环绕前增强===========
      修改订单。。。
      环绕前增强===========
      查找订单。。。
      异常抛出通知============java.lang.ArithmeticException: / by zero
      

    1.2.5 最终通知‘

    • 在切面类中添加方法

      //最终通知
      	@After(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))")
      	public void after() {
      		System.out.println("最终增强============");
      	}
      
    • 测试

      前置增强===============
      保存订单。。。
      环绕前增强===========
      修改订单。。。
      环绕前增强===========
      查找订单。。。
      最终增强============
      异常抛出通知============java.lang.ArithmeticException: / by zero
      

    1.3 Spring的AOP的注解的切入点的注解

    • 修改切面类

      package com.itzhouq.spring.demo1;
      
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.After;
      import org.aspectj.lang.annotation.AfterReturning;
      import org.aspectj.lang.annotation.AfterThrowing;
      import org.aspectj.lang.annotation.Around;
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      import org.aspectj.lang.annotation.Pointcut;
      
      /*
       * 切面类:注解的切面类
       */
      @Aspect	//标记该类为切面类
      public class MyAspectAnno {
      	
      	@Before(value="MyAspectAnno.pointcut2()")
      	public void before() {//这个注解用来标记目标类的哪个方法使用何种增强
      		System.out.println("前置增强===============");
      	}
      	
      	//后置通知
      	@AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result")
      	public void afterReturning(Object result) {
      		System.out.println("后置增强=================="+result);
      	}
      	
      	//环绕通知
      	@Around(value="MyAspectAnno.pointcut3()")
      	public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
      		System.out.println("环绕前增强===========");
      		Object obj = joinPoint.proceed();
      		System.out.println("环绕前增强===========");
      		return obj;
      	}
      	
      	//异常抛出通知
      	@AfterThrowing(value="MyAspectAnno.pointcut4()",throwing="e")
      	public void afterThrowing(Throwable e) {
      		System.out.println("异常抛出通知============"+e);
      	}
      	
      	//最终通知
      	@After(value="MyAspectAnno.pointcut1()")
      	public void after() {
      		System.out.println("最终增强============");
      	}
      	
      	//切入点注解
      	@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))")
      	private void pointcut1() {}
      	@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.save(..))")
      	private void pointcut2() {}
      	@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.update(..))")
      	private void pointcut3() {}
      	@Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))")
      	private void pointcut4() {}
      }
      
      • 通过切入点的注解,可以简化注解的代码量
      • 注意:使用类名.pointcut1()时候不要忘记pointcut1()是一个方法,需要带上()才有效

    2. Spring的JDBC的模板的使用

    2.1 Spring的JDBC的模板

    • Spring的EE开发的一站式的框架,有EE开发中每一层的解决方案。Spring对持久层也提供了解决方案:ORM模块和JDBC的模块。

    • Spring提供了很多的模板用于简化开发。

    2.1.1 JDBC模板使用的入门

    • 创建项目,引入jar包

      • 引入基本的4+2包

      • 数据库驱动包

      • Spring的JDBC模板的jar包:事务管理tx和jdbc的包

      • 单元测试包

    • 创建数据库和表

      create database spring4_day03;
      use spring4_day03;
      create table account(
      	id int primary key auto_increment,
      	name varchar(20),
      	money double
      )
      
    • 使用JDBC模板:保存数据

      package com.itzhouq.spring.jdbc.demo1;
      
      import org.junit.Test;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.jdbc.datasource.DriverManagerDataSource;
      
      /*
       * JDBC的模板使用
       */
      public class JdbcDemo1 {
      	@Test	//JDBC的模板的使用类似于Dbutils
      	public void test1() {
      		//创建连接池	这里使用Spring默认的连接池
      		DriverManagerDataSource dataSource = new DriverManagerDataSource();
      		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
      		dataSource.setUrl("jdbc:mysql:///spring4_day03");
      		dataSource.setUsername("root");
      		dataSource.setPassword("2626");
      		
      		//创建jdbc模板
      		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
      		jdbcTemplate.update("insert into account values (null, ?,?)", "周杰伦",10000d);
      	}
      
      }
      
    • 将日志记录的配置文件jdbc.properties拷贝到src下

      jdbc.driver=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/spring4_day03
      jdbc.username=root
      jdbc.password=2626
      
    • 测试能插入数据

    2.1.2 将连接池和模板交给Spring管理

    • 引入aop的jar包

    • 引入Spring的配置文件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: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.xsd
      	http://www.springframework.org/schema/context
      	http://www.springframework.org/schema/context/spring-context.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">
      	
      	
      </beans>
      
    • 配置Spring的内置连接池,将连接池交给Spring管理

      <!-- 配置Spring的内置连接池 -->
      	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      		<!-- 属性注入 ===============-->
      		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
      		<property name="url" value="jdbc:mysql:///spring4_day03"></property>
      		<property name="username" value="root"></property>
      		<property name="password" value="2626"></property>
      	</bean>
      
    • 配置Spring的jdbc模板,将模板交给Spring管理

      <!-- 配置Spring的JDBC模板 =================-->
      	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      		<property name="dataSource" ref="dataSource"></property>
      	</bean>
      
    • 使用JDBC的模板

      package com.itzhouq.spring.jdbc.demo1;
      
      import javax.annotation.Resource;
      
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(value="classpath:applicationContext.xml")
      public class JdbcDemo2 {
      	@Resource(name="jdbcTemplate")
      	private JdbcTemplate jdbcTemplate;
      	
      	@Test
      	public void test1() {
      		jdbcTemplate.update("insert into account values (null, ?,?)", "赵雷",10000d);
      	}
      }
      
    • 测试能插入数据

    2.2 使用开源的数据库连接池

    2.2.1 C3P0的使用

    • 导入jar包

      • com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
    • 路径

      • ..spring-framework-3.0.2.RELEASE-dependenciescom.mchange.c3p0com.springsource.com.mchange.v2.c3p0
    • 配置C3P0连接池

      <!-- 配置C3P0连接池 -->
      	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      		<!-- 属性注入 =============== -->
      		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
      		<property name="jdbcUrl" value="jdbc:mysql:///spring4_day03"></property>
      		<property name="user" value="root"></property>
      		<property name="password" value="2626"></property>
      	</bean> 
      	<!-- 配置Spring的JDBC模板 =================-->
      	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      		<property name="dataSource" ref="dataSource"></property>
      	</bean>
      
      • 注意:C3P0连接池的核心类是:com.mchange.v2.c3p0.ComboPooledDataSource
      • 测试能插入数据

    2.2.2 DBCP的使用

    • 引入jar包

      • com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
      • com.springsource.org.apache.commons.pool-1.5.3.jar
    • 路径

      • ..spring-framework-3.0.2.RELEASE-dependenciesorg.apache.commonscom.springsource.org.apache.commons.dbcp
      • ..spring-framework-3.0.2.RELEASE-dependenciesorg.apache.commonscom.springsource.org.apache.commons.pool
    • 配置DBCP的连接池

      <!-- 配置DBCP连接池 -->
      	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
      		属性注入 ===============
      		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
      		<property name="url" value="jdbc:mysql:///spring4_day03"></property>
      		<property name="username" value="root"></property>
      		<property name="password" value="2626"></property>
      	</bean>
      	
      	<!-- 配置Spring的JDBC模板 =================-->
      	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      		<property name="dataSource" ref="dataSource"></property>
      	</bean>
      
    • 注意:DBCP的核心类为org.apache.commons.dbcp.BasicDataSource

    • 测试能插入数据

    2.3 抽取配置到属性文件

    • 在src下新建配置文件jdbc.properties

      jdbc.driverClass=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/spring4_day03
      jdbc.username=root
      jdbc.password=2626
      
    • 在Spring的配置文件中引入属性文件

      <!-- 引入连接数据的属性文件 -->
      	<context:property-placeholder location="classpath:jdbc.properties"/>
      	<!-- 配置C3P0连接池 -->
      	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      		<!-- 属性注入 =============== -->
      		<property name="driverClass" value="${jdbc.driverClass}"></property>
      		<property name="jdbcUrl" value="${jdbc.url}"></property>
      		<property name="user" value="${jdbc.username}"></property>
      		<property name="password" value="${jdbc.password}"></property>
      	</bean> 
      
    • 测试能插入数据

    2.4 使用JDBC模板进行CURD操作

    2.4.1 增

    package com.itzhouq.spring.jdbc.demo1;
    
    import javax.annotation.Resource;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(value="classpath:applicationContext.xml")
    public class JdbcDemo2 {
    	@Resource(name="jdbcTemplate")
    	private JdbcTemplate jdbcTemplate;
    	
    	@Test
    	public void test1() {
    		jdbcTemplate.update("insert into account values (null, ?,?)", "YYY",10000d);
    	}
    }
    

    2.4.2 删

    @Test
    	public void test3() {//删除
    		jdbcTemplate.update("delete from account where id = ?", 5);
    	}
    

    2.4.3 改

    @Test
    	public void test2() {//修改
    		jdbcTemplate.update("update account set name = ?, money =  ? where id = ?", "何巨涛",10000d, 6);
    	}
    

    2.4.4 查

    • 查询某个属性

      @Test
      	public void test4() {//查询某个属性
      		String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 6);
      		System.out.println(name);
      	}
      
    • 查询个数

      @Test
      	public void test5() {//查询个数
      		Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
      		System.out.println(count);
      	}
      
    • 返回的是对象

      • 首先要创建一个实体Account

        @Test
        	public void test6() {//封装到一个对象中
        		Account  account = jdbcTemplate.queryForObject("select * from account where id = ?", new MyRowMapper(), 4);
        		System.out.println(account);
        	}
        	
        	class MyRowMapper  implements RowMapper<Account>{
        
        		@Override
        		public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
        			Account account = new Account();
        			account.setId(rs.getInt("id"));
        			account.setName(rs.getString("name"));
        			account.setMoney(rs.getDouble("money"));
        			return account;
        		}
        	}
        
      • queryForObject的第二个参数需要实现一个接口RowMapper

    • 查询多条记录

      @Test
      	public void test7() {
      		List<Account> listAccount = jdbcTemplate.query("select * from account", new MyRowMapper());
      		for (Account account : listAccount) {
      			System.out.println(account);
      		}
      	}
      	
      	class MyRowMapper  implements RowMapper<Account>{
      
      		@Override
      		public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
      			Account account = new Account();
      			account.setId(rs.getInt("id"));
      			account.setName(rs.getString("name"));
      			account.setMoney(rs.getDouble("money"));
      			return account;
      		}
      	}
      

    3. Spring的事务管理

    3.1 事务的回顾

    3.1.1 什么是事务

    • 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。

    3.1.2 事务的特性

    • 原子性:事务不可分割
    • 一致性:事务执行前后数据完整性保持一致
    • 隔离性:一个事务的执行不应该受到其他事务的影响
    • 持久性:一旦事务结束,数据就持久化到数据库中

    3.1.3 不考虑事务的隔离性引发安全问题

    • 读问题
      • 脏读:一个事务读到另一个事务未提交的数据
      • 不可重复读:一个事务读取到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
      • 虚读、幻读:一个事务读到另一个事务已经提交的insert数据,导致一个事务中多次查询结果不一致
    • 写问题
      • 丢失更新

    3.1.4 解决读问题

    • 设置事务的隔离级别
      • read uncommited:未提交读,任何读问题都解决不了
      • Read commited:已提交读,解决脏读,但是不可重复读和虚读有可能发生
      • Repeatable read:重复读,解决脏读和不可重复读,但是虚读有可能发生
      • Serializable:解决所有读问题

    3.2 Spring的事务管理的API

    3.2. 1 PlatformTransactionManager:平台事务管理器

    • 平台事务管理器:接口,是Spring用于管理事务的真正的对象。
      • DataSourceTransactionManager:底层使用JDBC管理事务
      • HibernateTransactionManager:底层使用Hibernate管理事务

    3.2.2 TransactionDefinition:事务定义信息

    • 事务定义:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读

    3.2.3 TransactionStatus:事务的状态

    • l 事务状态:用于记录在事务管理过程中,事务的状态的对象。

    3.2.4 事务管理的API的关系

    • Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。

    3.3 事务的传播行为

    • Spring中提供了七种事务的传播行为

    3.3.1 保证多个操作在同一个事务中

    • PROPAGATION_REQUIRED:默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
    • PROPAGATION_SUPPORTS:支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
    • PROPAGATION_MANDATORY:如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

    3.3.2 保证多个操作不在同一个事务中

    • PROPAGATION_REQUIRES_NEW:如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
    • PROPAGATION_NOT_SUPPORTED:如果A中有事务,将A的事务挂起。不使用事务管理。
    • PROPAGATION_NEVER:如果A中有事务,报异常。

    3.3.3 嵌套式事务

    • PROPAGATION_NESTED:嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。

    3.4 事务的管理

    3.4.1 案例:转账

    • 创建AccountService接口

      package com.itzhouq.spring.tx.demo1;
      /*
       * 转账的业务层的接口
       */
      public interface AccountService {
      	public void transfer(String from, String to, Double money);
      }
      
    • 创建接口实现类AccountServiceImpl

      package com.itzhouq.spring.tx.demo1;
      /*
       * 转账的业务层的实现类
       */
      public class AccountServiceImpl implements AccountService {
      	
      	//注入DAO
      	private AccountDao accountDao;
      	public void setAccountDao(AccountDao accountDao) {
      		this.accountDao = accountDao;
      	}
      
      	/**
      	 * 	from:转出账户
      	 * 	to:转入账户
      	 * 	money:转账金额
      	 */
      	@Override
      	public void transfer(String from, String to, Double money) {
      		accountDao.outMoney(from, money);
      		int i = 1 / 0;
      		accountDao.inMoney(to, money);
      	}
      }
      
    • 创建AccountDao接口

      package com.itzhouq.spring.tx.demo1;
      /*
       * 转账的DAO的接口
       */
      public interface AccountDao {
      	public void outMoney(String from, Double money);
      	public void inMoney(String to, Double money);
      }
      
    • 创建AccountDao实现类AccountDaoImpl

      package com.itzhouq.spring.tx.demo1;
      
      import org.springframework.jdbc.core.support.JdbcDaoSupport;
      
      public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
      	
      	@Override
      	public void outMoney(String from, Double money) {
      		this.getJdbcTemplate().update("update account set money=money-? where name=?", money,from);
      	}
      
      	@Override
      	public void inMoney(String to, Double money) {
      		this.getJdbcTemplate().update("update account set money=money+? where name=?", money,to);
      	}
      }
      
    • 配置Service和Dao:交给Spring管理

      • 复制applicationContext.xml文件,新建配置文件tx.xml

        <!-- 配置Service -->
        	<bean id="accountService" class="com.itzhouq.spring.tx.demo1.AccountServiceImpl">
        		<property name="accountDao" ref="accountDao"></property>
        	</bean>
        	
        	<!-- 配置Dao -->
        	<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
        		
        	</bean>
        
    • 在Dao中编写扣钱和加钱

      • 配置连接池和JDBC的模板

        <!-- 引入连接数据的属性文件 -->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <!-- 配置C3P0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 属性注入 =============== -->
            <property name="driverClass" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.url}"></property>
            <property name="user" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean> 
        <!-- 配置Spring的JDBC模板 =================-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
      • 在Dao中注入jdbc的模板

        • 方法一:在Dao中直接注入

          package com.itzhouq.spring.tx.demo1;
          
          import org.springframework.jdbc.core.JdbcTemplate;
          
          public class AccountDaoImpl implements AccountDao {
          	
          	private JdbcTemplate jdbcTemplate;
          	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
          		this.jdbcTemplate = jdbcTemplate;
          	}
          
          	@Override
          	public void outMoney(String from, Double money) {
          		
          
          	}
          
          	@Override
          	public void inMoney(String to, Double money) {
          
          	}
          }
          
        • 方法二:AccountDaoImpl继承JdbcDaoSupport

          • JdbcDaoSupport类中提供了模板,也提供了set方法

            package com.itzhouq.spring.tx.demo1;
            
            import org.springframework.jdbc.core.support.JdbcDaoSupport;
            
            public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
            	
            	@Override
            	public void outMoney(String from, Double money) {
            
            	}
            
            	@Override
            	public void inMoney(String to, Double money) {
            
            	}
            }
            
          • 所以直接在xml文件中的dao注入模板

            <!-- 配置Dao -->
            	<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
            		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
            	</bean>
            
        • 方法三:继承JdbcDaoSupport类之后直接注入连接池,这样连接池可以自动创建模板

          • 不用配置模板,直接dao中注入连接池

            <!--可以省略的配置-->
            <!-- 配置Spring的JDBC模板 =================-->
            	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            		<property name="dataSource" ref="dataSource"></property>
            	</bean>
            
            <!-- 配置Dao -->
            	<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
            		<property name="dataSource" ref="dataSource"/>
            	</bean>
            
      • 配置文件

        <?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: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/context
        	http://www.springframework.org/schema/context/spring-context.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">
        	
        	<!-- 配置Service -->
        	<bean id="accountService" class="com.itzhouq.spring.tx.demo1.AccountServiceImpl">
        		<property name="accountDao" ref="accountDao"></property>
        	</bean>
        	
        	<!-- 配置Dao -->
        	<bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
        		<property name="dataSource" ref="dataSource"/>
        	</bean> 
        	
        	<!-- 引入连接数据的属性文件 -->
        	<context:property-placeholder location="classpath:jdbc.properties"/>
        	<!-- 配置C3P0连接池 -->
        	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        		<!-- 属性注入 =============== -->
        		<property name="driverClass" value="${jdbc.driverClass}"></property>
        		<property name="jdbcUrl" value="${jdbc.url}"></property>
        		<property name="user" value="${jdbc.username}"></property>
        		<property name="password" value="${jdbc.password}"></property>
        	</bean> 
        	<!-- 配置Spring的JDBC模板 =================-->
        	<!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        		<property name="dataSource" ref="dataSource"></property>
        	</bean> -->
        		
        </beans>
        
        
    • 测试

      package com.itzhouq.spring.tx.demo1;
      
      import javax.annotation.Resource;
      
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      /*
       * 测试转账
       */
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:tx.xml")
      public class SpringDemo1 {
      	@Resource(name="accountService")
      	private AccountService accountService;
      	
      	@Test
      	public void test1() {
      		accountService.transfer("周杰伦", "邓超", 1000d);
      	}
      }
      
      • 如果没有异常能够转账成功。但是没有事务控制,一旦转账过程中出现异常就会出现数据丢失的现象。

    3.4.2 Spring的事务管理

    • 方式一:编程式事务,需要手动编码【了解】
    • 方式二:声明式事务,通过配置实现---AOP

    3.4.3 声明式事务

    • XML方式的声明式的事务管理

      • 引入jar包

        • aop联盟包

        • aspectJ包

        • aop包

        • Spring整合aspectJ包

      • 配置事务管理器

        <!-- 配置事务管理器 -->
        	<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" isolation="DEFAULT"/>
        			<tx:method name="update*" propagation="REQUIRED"/>
        			<tx:method name="delete*" propagation="REQUIRED"/>
        			<tx:method name="find*" read-only="true"/> -->
        			<tx:method name="*" propagation="REQUIRED" read-only="false"/>
        		</tx:attributes>
        	</tx:advice>
        
      • AOP的配置

        <!-- aop的配置 -->
        	<aop:config>
        		<aop:pointcut expression="execution(* com.itzhouq.spring.tx.demo1.AccountServiceImpl.*(..))" id="pointcut1"/>
        		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
        	</aop:config>
        
        • 测试:如果转账出现异常,事务自动回滚
    • 注解方式声明事务

      • 引入aop的开发包

      • 配置事务管理

        <!-- 配置事务管理器=============================== -->
        	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        		<property name="dataSource" ref="dataSource"/>
        	</bean>
        
      • 开启注解事务

        <!-- 开启注解事务================================ -->
        	<tx:annotation-driven transaction-manager="transactionManager"/>
        
      • 在业务层添加注解

        @Transactional
        public class AccountServiceImpl implements AccountService {
        	
        
      • 测试:如果转账过程中出现异常,则自动回滚。

  • 相关阅读:
    springboot + websocket + qpid问题记录
    学习开源项目guns遇到的问题记录
    CSS选择器和jQuery选择器学习总结
    (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
    (深入.Net平台和C#编程)第九章.上机练习.20170417
    (深入.Net平台和C#编程)第八章.上机练习(网络电视精灵).20170415
    (深入.Net平台和C#编程)第十章.课程总复习.20170413
    (深入.Net平台和C#编程)第七章.上机练习.20170412
    (深入.Net平台和C#编程)第六章.简答题5.20170410
    (深入.Net平台和C#编程)第六章.简答题3.20170410
  • 原文地址:https://www.cnblogs.com/itzhouq/p/spring04.html
Copyright © 2011-2022 走看看