目录

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

1. 1 SpringAOP的注解入门

  • 创建项目,导入jar包

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

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

    • Spring整合单元测试包

  • 引入配置文件applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xmlns:tx="http://www.springframework.org/schema/tx"
    7. xsi:schemaLocation="http://www.springframework.org/schema/beans
    8. http://www.springframework.org/schema/beans/spring-beans.xsd
    9. http://www.springframework.org/schema/context
    10. http://www.springframework.org/schema/context/spring-context.xsd
    11. http://www.springframework.org/schema/aop
    12. http://www.springframework.org/schema/aop/spring-aop.xsd
    13. http://www.springframework.org/schema/tx
    14. http://www.springframework.org/schema/tx/spring-tx.xsd">
    15. </beans>
  • 编写目标类并配置

    1. package com.itzhouq.spring.demo1;
    2. public class OrderDao {
    3. public void save() {
    4. System.out.println("保存订单。。。");
    5. }
    6. public void update() {
    7. System.out.println("修改订单。。。");
    8. }
    9. public void find() {
    10. System.out.println("查找订单。。。");
    11. }
    12. public String delete() {
    13. System.out.println("删除订单。。。");
    14. return "周杰伦";
    15. }
    16. }
  • 配置目标类,将目标类OrderDao交给Spring管理

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

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

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

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

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

    1. package com.itzhouq.spring.demo1;
    2. import javax.annotation.Resource;
    3. import org.junit.Test;
    4. import org.junit.runner.RunWith;
    5. import org.springframework.test.context.ContextConfiguration;
    6. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    7. /*
    8. * Spring的AOP注解开发测试
    9. */
    10. @RunWith(SpringJUnit4ClassRunner.class)
    11. @ContextConfiguration("classpath:applicationContext.xml")
    12. public class SpringDemo1 {
    13. @Resource(name="orderDao") //注入OrderDao
    14. private OrderDao orderDao;
    15. @Test
    16. public void test1() {
    17. orderDao.save();
    18. orderDao.update();
    19. orderDao.find();
    20. orderDao.delete();
    21. // 前置增强===============
    22. // 保存订单。。。
    23. // 修改订单。。。
    24. // 查找订单。。。
    25. // 删除订单。。。
    26. }
    27. }

1.2 Spring的AOP的注解通知类型

1.2.1 @Before:前置通知

1.2.2 @AfterReturning:后置通知

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

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

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

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

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

1.2.3 环绕通知

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

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

    1. 前置增强===============
    2. 保存订单。。。
    3. 环绕前增强===========
    4. 修改订单。。。
    5. 环绕前增强===========
    6. 查找订单。。。
    7. 删除订单。。。
    8. 后置增强==================周杰伦

1.2.4 异常抛出通知

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

  • 在切面类中添加方法

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

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

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

1.2.5 最终通知‘

  • 在切面类中添加方法

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

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

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

  • 修改切面类

    1. package com.itzhouq.spring.demo1;
    2. import org.aspectj.lang.ProceedingJoinPoint;
    3. import org.aspectj.lang.annotation.After;
    4. import org.aspectj.lang.annotation.AfterReturning;
    5. import org.aspectj.lang.annotation.AfterThrowing;
    6. import org.aspectj.lang.annotation.Around;
    7. import org.aspectj.lang.annotation.Aspect;
    8. import org.aspectj.lang.annotation.Before;
    9. import org.aspectj.lang.annotation.Pointcut;
    10. /*
    11. * 切面类:注解的切面类
    12. */
    13. @Aspect //标记该类为切面类
    14. public class MyAspectAnno {
    15. @Before(value="MyAspectAnno.pointcut2()")
    16. public void before() {//这个注解用来标记目标类的哪个方法使用何种增强
    17. System.out.println("前置增强===============");
    18. }
    19. //后置通知
    20. @AfterReturning(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))", returning="result")
    21. public void afterReturning(Object result) {
    22. System.out.println("后置增强=================="+result);
    23. }
    24. //环绕通知
    25. @Around(value="MyAspectAnno.pointcut3()")
    26. public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
    27. System.out.println("环绕前增强===========");
    28. Object obj = joinPoint.proceed();
    29. System.out.println("环绕前增强===========");
    30. return obj;
    31. }
    32. //异常抛出通知
    33. @AfterThrowing(value="MyAspectAnno.pointcut4()",throwing="e")
    34. public void afterThrowing(Throwable e) {
    35. System.out.println("异常抛出通知============"+e);
    36. }
    37. //最终通知
    38. @After(value="MyAspectAnno.pointcut1()")
    39. public void after() {
    40. System.out.println("最终增强============");
    41. }
    42. //切入点注解
    43. @Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.find(..))")
    44. private void pointcut1() {}
    45. @Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.save(..))")
    46. private void pointcut2() {}
    47. @Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.update(..))")
    48. private void pointcut3() {}
    49. @Pointcut(value="execution(* com.itzhouq.spring.demo1.OrderDao.delete(..))")
    50. private void pointcut4() {}
    51. }
    • 通过切入点的注解,可以简化注解的代码量
    • 注意:使用类名.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的包

    • 单元测试包

  • 创建数据库和表

    1. create database spring4_day03;
    2. use spring4_day03;
    3. create table account(
    4. id int primary key auto_increment,
    5. name varchar(20),
    6. money double
    7. )
  • 使用JDBC模板:保存数据

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

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

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

  • 引入aop的jar包

  • 引入Spring的配置文件applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xmlns:tx="http://www.springframework.org/schema/tx"
    7. xsi:schemaLocation="http://www.springframework.org/schema/beans
    8. http://www.springframework.org/schema/beans/spring-beans.xsd
    9. http://www.springframework.org/schema/context
    10. http://www.springframework.org/schema/context/spring-context.xsd
    11. http://www.springframework.org/schema/aop
    12. http://www.springframework.org/schema/aop/spring-aop.xsd
    13. http://www.springframework.org/schema/tx
    14. http://www.springframework.org/schema/tx/spring-tx.xsd">
    15. </beans>
  • 配置Spring的内置连接池,将连接池交给Spring管理

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

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

    1. package com.itzhouq.spring.jdbc.demo1;
    2. import javax.annotation.Resource;
    3. import org.junit.Test;
    4. import org.junit.runner.RunWith;
    5. import org.springframework.jdbc.core.JdbcTemplate;
    6. import org.springframework.test.context.ContextConfiguration;
    7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    8. @RunWith(SpringJUnit4ClassRunner.class)
    9. @ContextConfiguration(value="classpath:applicationContext.xml")
    10. public class JdbcDemo2 {
    11. @Resource(name="jdbcTemplate")
    12. private JdbcTemplate jdbcTemplate;
    13. @Test
    14. public void test1() {
    15. jdbcTemplate.update("insert into account values (null, ?,?)", "赵雷",10000d);
    16. }
    17. }
  • 测试能插入数据

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

2.2.1 C3P0的使用

  • 导入jar包

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

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

    1. <!-- 配置C3P0连接池 -->
    2. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    3. <!-- 属性注入 =============== -->
    4. <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    5. <property name="jdbcUrl" value="jdbc:mysql:///spring4_day03"></property>
    6. <property name="user" value="root"></property>
    7. <property name="password" value="2626"></property>
    8. </bean>
    9. <!-- 配置Spring的JDBC模板 =================-->
    10. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    11. <property name="dataSource" ref="dataSource"></property>
    12. </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-dependencies\org.apache.commons\com.springsource.org.apache.commons.dbcp
    • ..\spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.pool
  • 配置DBCP的连接池

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

  • 测试能插入数据

2.3 抽取配置到属性文件

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

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

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

2.4 使用JDBC模板进行CURD操作

2.4.1 增

  1. package com.itzhouq.spring.jdbc.demo1;
  2. import javax.annotation.Resource;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.jdbc.core.JdbcTemplate;
  6. import org.springframework.test.context.ContextConfiguration;
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  8. @RunWith(SpringJUnit4ClassRunner.class)
  9. @ContextConfiguration(value="classpath:applicationContext.xml")
  10. public class JdbcDemo2 {
  11. @Resource(name="jdbcTemplate")
  12. private JdbcTemplate jdbcTemplate;
  13. @Test
  14. public void test1() {
  15. jdbcTemplate.update("insert into account values (null, ?,?)", "YYY",10000d);
  16. }
  17. }

2.4.2 删

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

2.4.3 改

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

2.4.4 查

  • 查询某个属性

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

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

    • 首先要创建一个实体Account

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

  • 查询多条记录

    1. @Test
    2. public void test7() {
    3. List<Account> listAccount = jdbcTemplate.query("select * from account", new MyRowMapper());
    4. for (Account account : listAccount) {
    5. System.out.println(account);
    6. }
    7. }
    8. class MyRowMapper implements RowMapper<Account>{
    9. @Override
    10. public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
    11. Account account = new Account();
    12. account.setId(rs.getInt("id"));
    13. account.setName(rs.getString("name"));
    14. account.setMoney(rs.getDouble("money"));
    15. return account;
    16. }
    17. }

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接口

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

    1. package com.itzhouq.spring.tx.demo1;
    2. /*
    3. * 转账的业务层的实现类
    4. */
    5. public class AccountServiceImpl implements AccountService {
    6. //注入DAO
    7. private AccountDao accountDao;
    8. public void setAccountDao(AccountDao accountDao) {
    9. this.accountDao = accountDao;
    10. }
    11. /**
    12. * from:转出账户
    13. * to:转入账户
    14. * money:转账金额
    15. */
    16. @Override
    17. public void transfer(String from, String to, Double money) {
    18. accountDao.outMoney(from, money);
    19. int i = 1 / 0;
    20. accountDao.inMoney(to, money);
    21. }
    22. }
  • 创建AccountDao接口

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

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

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

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

    • 配置连接池和JDBC的模板

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

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

        1. package com.itzhouq.spring.tx.demo1;
        2. import org.springframework.jdbc.core.JdbcTemplate;
        3. public class AccountDaoImpl implements AccountDao {
        4. private JdbcTemplate jdbcTemplate;
        5. public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        6. this.jdbcTemplate = jdbcTemplate;
        7. }
        8. @Override
        9. public void outMoney(String from, Double money) {
        10. }
        11. @Override
        12. public void inMoney(String to, Double money) {
        13. }
        14. }
      • 方法二:AccountDaoImpl继承JdbcDaoSupport

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

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

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

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

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

      1. <?xml version="1.0" encoding="UTF-8"?>
      2. <beans xmlns="http://www.springframework.org/schema/beans"
      3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4. xmlns:context="http://www.springframework.org/schema/context"
      5. xmlns:aop="http://www.springframework.org/schema/aop"
      6. xmlns:tx="http://www.springframework.org/schema/tx"
      7. xsi:schemaLocation="http://www.springframework.org/schema/beans
      8. http://www.springframework.org/schema/beans/spring-beans.xsd
      9. http://www.springframework.org/schema/context
      10. http://www.springframework.org/schema/context/spring-context.xsd
      11. http://www.springframework.org/schema/aop
      12. http://www.springframework.org/schema/aop/spring-aop.xsd
      13. http://www.springframework.org/schema/tx
      14. http://www.springframework.org/schema/tx/spring-tx.xsd">
      15. <!-- 配置Service -->
      16. <bean id="accountService" class="com.itzhouq.spring.tx.demo1.AccountServiceImpl">
      17. <property name="accountDao" ref="accountDao"></property>
      18. </bean>
      19. <!-- 配置Dao -->
      20. <bean id="accountDao" class="com.itzhouq.spring.tx.demo1.AccountDaoImpl">
      21. <property name="dataSource" ref="dataSource"/>
      22. </bean>
      23. <!-- 引入连接数据的属性文件 -->
      24. <context:property-placeholder location="classpath:jdbc.properties"/>
      25. <!-- 配置C3P0连接池 -->
      26. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      27. <!-- 属性注入 =============== -->
      28. <property name="driverClass" value="${jdbc.driverClass}"></property>
      29. <property name="jdbcUrl" value="${jdbc.url}"></property>
      30. <property name="user" value="${jdbc.username}"></property>
      31. <property name="password" value="${jdbc.password}"></property>
      32. </bean>
      33. <!-- 配置Spring的JDBC模板 =================-->
      34. <!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      35. <property name="dataSource" ref="dataSource"></property>
      36. </bean> -->
      37. </beans>
  • 测试

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

3.4.2 Spring的事务管理

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

3.4.3 声明式事务

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

    • 引入jar包

      • aop联盟包

      • aspectJ包

      • aop包

      • Spring整合aspectJ包

    • 配置事务管理器

      1. <!-- 配置事务管理器 -->
      2. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      3. <property name="dataSource" ref="dataSource"/>
      4. </bean>
    • 配置增强

      1. <!-- 配置事务的增强=============================== -->
      2. <tx:advice id="txAdvice" transaction-manager="transactionManager">
      3. <tx:attributes>
      4. <!-- 事务管理的规则 -->
      5. <!-- <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/>
      6. <tx:method name="update*" propagation="REQUIRED"/>
      7. <tx:method name="delete*" propagation="REQUIRED"/>
      8. <tx:method name="find*" read-only="true"/> -->
      9. <tx:method name="*" propagation="REQUIRED" read-only="false"/>
      10. </tx:attributes>
      11. </tx:advice>
    • AOP的配置

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

    • 引入aop的开发包

    • 配置事务管理

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

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

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

Spring笔记04_AOP注解开发_模板_事务的更多相关文章

  1. Spring笔记13--SSH--全注解开发

    SSH全注解开发: (1) 在Action类中添加注解,实现Struts2的注解开发(@NameSpace.@ParentPackage.@Action...) package com.tongji. ...

  2. spring boot纯注解开发模板

    简介 spring boot纯注解开发模板 创建项目 pom.xml导入所需依赖 点击查看源码 <dependencies> <dependency> <groupId& ...

  3. Spring---AOP注解开发&jdbc模板&Spring事务管理

    一.AOP注解开发 此处需要回忆一遍AOP的概念.简单的来说,AOP就是利用动态代理技术,做到不触动源代码但却扩展了功能.那么就需要一个被扩展的对象和一个“新的功能”,例如说给某类的saveUser方 ...

  4. Spring入门(三)— AOP注解、jdbc模板、事务

    一.AOP注解开发 导入jar包 aop联盟包. aspectJ实现包 . spring-aop-xxx.jar . spring-aspect-xxx.jar 导入约束 aop约束 托管扩展类和被扩 ...

  5. Spring笔记02_注解_IOC

    目录 Spring笔记02 1. Spring整合连接池 1.1 Spring整合C3P0 1.2 Spring整合DBCP 1.3 最终版 2. 基于注解的IOC配置 2.1 导包 2.2 配置文件 ...

  6. Spring的IOC注解开发入门1

    基本知识点如下: 引入注解约束,配置组件扫描 类上的注解: @Conponent  @Controller @Service @Repository 普通属性的注解   @value 对象属性的注解  ...

  7. Spring的IOC注解开发入门2

    注解方式设置属性的值 在我们IOC基于xml属性注入的方式中有(一般推荐set方法) 构造方法注入普通值:<constructor-arg>的使用 set方法注入普通值:<prope ...

  8. spring MVC之注解开发控制器(二)

    开发表单控制器 在传统的Spring MVC开发方法中,是通过扩展SimpleFormController类来创建简单的表单控制器.这样就定义了基本的表单处理流程,并允许通过覆盖几个生命周期方法来定制 ...

  9. spring笔记--通过注解(annotation)配置Bean

    Spring能够在classpath下自动扫描,侦测和实例化具有特定注解的组件,这在Spring中成为组件扫描(Component scanning). 特定组件的注解包括: @Component:基 ...

随机推荐

  1. python | Elasticsearch-dsl常用方法总结(join为案例)

    Elasticsearch DSL是一个高级库,其目的是帮助编写和运行针对Elasticsearch的查询.它建立在官方低级客户端(elasticsearch-py)之上. 它提供了一种更方便和习惯的 ...

  2. SEED实验——return-to-libc实验

    实验概述 本实验的学习目标是让学生获得缓冲区溢出攻击的一种有趣变体——return-to-libc攻击实验的亲身体验.这种攻击可以绕过目前在主要linux操作系统中实现的现有保护方案.利用缓冲区溢出漏 ...

  3. java 加解密

    import javax.crypto.*; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingExc ...

  4. HBuilder git合作-上传项目到Git Hub

    1.初始项目的创建 这里假设你已经在Git Hub上面建立好了代码的远程仓库,并已经邀请好了队员 在HBuidler中创建好初始的项目,然后右键,"Team"->" ...

  5. High Availability手册(2): 架构

    最底层是通信层corosync/openais 负责cluster中node之间的通信 上一层是Resource Allocation Layer,包含下面的组件: CRM Cluster Resou ...

  6. 选择 25k 的 996 还是 18k 的 965

    阅读本文大概需要 3.7 分钟. 文中部分内容来源:http://h5ip.cn/hSDk 最近的 996.ICU 话题持续在火爆,一般热点新闻的热度持续时间为一星期,这次是程序们的集体发声导致,戳中 ...

  7. ThreadLocal及InheritableThreadLocal的原理剖析

    我们知道,线程的不安全问题,主要是由于多线程并发读取一个变量而引起的,那么有没有一种办法可以让一个变量是线程独有的呢,这样不就可以解决线程安全问题了么.其实JDK已经为我们提供了ThreadLocal ...

  8. [Swift]LeetCode344. 反转字符串 | Reverse String

    Write a function that takes a string as input and returns the string reversed. Example 1: Input: &qu ...

  9. [Swift]LeetCode833. 字符串中的查找与替换 | Find And Replace in String

    To some string S, we will perform some replacement operations that replace groups of letters with ne ...

  10. [Swift]LeetCode873. 最长的斐波那契子序列的长度 | Length of Longest Fibonacci Subsequence

    A sequence X_1, X_2, ..., X_n is fibonacci-like if: n >= 3 X_i + X_{i+1} = X_{i+2} for all i + 2 ...