typora-copy-images-to: img

Spring_03

学习目标

  • 能够掌握基于注解的AOP配置
  • 能够使用spring的jdbc的模板
  • 能够配置spring的连接池
  • 能够使用jdbc模板完成增删改查的操作
  • 能够应用声明式事务
  • 能够理解事务的传播行为

第一章-Spring中的AOP

知识点-基于XML的AOP配置

1.目标

  • 能够编写Spring的AOP中不同通知的代码

2.路径

  1. 前置通知
  2. 后置通知
  3. 环绕通知
  4. 异常通知
  5. 最终通知

3.讲解

3.1前置通知

需求: 在service的增删改查方法调用之前进行权限的校验

实现步骤:

  1. 导入坐标
  2. 定义Dao和增强的逻辑, 进行注册
  3. 配置AOP

    • 配置切入点
    • 配置切面(切入点和通知结合)

实现:

  • 导入坐标
  1. <dependencies>
  2. <!--Spring核心容器-->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>5.0.2.RELEASE</version>
  7. </dependency>
  8. <!--SpringAOP相关的坐标-->
  9. <dependency>
  10. <groupId>org.aspectj</groupId>
  11. <artifactId>aspectjweaver</artifactId>
  12. <version>1.8.7</version>
  13. </dependency>
  14. <!--Spring整合单元测试-->
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-test</artifactId>
  18. <version>5.0.2.RELEASE</version>
  19. </dependency>
  20. <!--单元测试-->
  21. <dependency>
  22. <groupId>junit</groupId>
  23. <artifactId>junit</artifactId>
  24. <version>4.12</version>
  25. <scope>test</scope>
  26. </dependency>
  27. </dependencies>
  • 导入约束
    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:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. http://www.springframework.org/schema/aop/spring-aop.xsd">
    9. </beans>
  • 定义被增强的业务逻辑类和切面类(增强的) ```java package com.itheima.service.impl;

import com.itheima.service.UserService;

/**

  • 包名:com.itheima.service.impl *
  • @author Leevi
  • 日期2020-08-12 08:36
  • 目标1:在执行增删改查方法之前,都做权限校验 前置通知: before
  • 目标2:在执行增删改查方法之后(没有出现异常), 都打印日志 后置通知: after-returning
  • 目标3:在执行增删改查方法出现异常之后,都进行友好的提示 异常通知: after-throwing
  • 目标4:在执行增删改查方法之后,无论出没出现异常,均打印一句”执行完毕” 最终通知: after
  • 目标5:计算update方法的执行时间 环绕通知: around */ public class UserServiceImpl implements UserService { @Override public void add() {

    1. System.out.println("执行添加...");
    2. int num = 10/0;

    }

    @Override public void delete() {

    1. System.out.println("执行删除...");

    }

    @Override public void update() {

    1. try {
    2. Thread.sleep(3000);
    3. } catch (InterruptedException e) {
    4. e.printStackTrace();
    5. }
    6. System.out.println("执行修改...");

    }

    @Override public void select() {

    1. System.out.println("执行查询...");

    } } ```

  1. package com.itheima.aspect;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. /**
  4. * 包名:com.itheima.aspect
  5. *
  6. * @author Leevi
  7. * 日期2020-08-12 08:39
  8. */
  9. public class PermissionAspect {
  10. public void checkPermission(){
  11. System.out.println("校验权限...");
  12. }
  13. public void printLog(){
  14. System.out.println("打印日志...");
  15. }
  16. public void showException(){
  17. System.out.println("出现异常了,请检查...");
  18. }
  19. public void showEnd(){
  20. System.out.println("执行完毕...");
  21. }
  22. //计算目标方法的执行时长
  23. public void showMillions(ProceedingJoinPoint joinPoint){
  24. //1. 记录当前时间
  25. long timeMillis1 = System.currentTimeMillis();
  26. //2. 执行目标方法
  27. try {
  28. joinPoint.proceed();
  29. } catch (Throwable throwable) {
  30. throwable.printStackTrace();
  31. }
  32. //3. 再记录当前时间
  33. long timeMillis2 = System.currentTimeMillis();
  34. //4. 将两次的时间相减,得到方法的执行时长
  35. System.out.println(timeMillis2 - timeMillis1);
  36. }
  37. }
  • applicationContext.xml配置文件中进行aop配置

    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:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. http://www.springframework.org/schema/aop/spring-aop.xsd">
    9. <!--全部采用纯配置文件方式-->
    10. <!--1. 对UserServiceImpl进行IOC配置-->
    11. <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"></bean>
    12. <!--2. 对切面类PermissionAspect进行IOC配置-->
    13. <bean id="permissionAspect" class="com.itheima.aspect.PermissionAspect"></bean>
    14. <!--
    15. 3. 配置AOP <aop:config>
    16. 1. 配置切入点 <aop:pointcut id="" expression=""/>
    17. id: 切入点的唯一标识
    18. expression: 切入点表达式
    19. 2. 配置通知
    20. 3. 配置切面关联通知和切入点
    21. -->
    22. <aop:config>
    23. <!--配置切入点-->
    24. <aop:pointcut id="pt1"
    25. expression="execution(* com.itheima.service.impl.UserServiceImpl.*(..))"/>
    26. <aop:pointcut id="pt2" expression="execution(* com.itheima.service.impl.UserServiceImpl.update(..))"/>
    27. <!--配置切面-->
    28. <aop:aspect id="aspect1" ref="permissionAspect">
    29. <!--配置前置通知-->
    30. <aop:before method="checkPermission" pointcut-ref="pt1"></aop:before>
    31. <!--配置后置通知-->
    32. <aop:after-returning method="printLog" pointcut-ref="pt1"></aop:after-returning>
    33. <!--配置异常通知-->
    34. <aop:after-throwing method="showException" pointcut-ref="pt1"></aop:after-throwing>
    35. <!--配置最终通知-->
    36. <aop:after method="showEnd" pointcut-ref="pt1"></aop:after>
    37. <!--配置环绕通知-->
    38. <aop:around method="showMillions" pointcut-ref="pt2"></aop:around>
    39. </aop:aspect>
    40. </aop:config>
    41. </beans>

知识点-基于注解的AOP配置

1.目标

  • 能够理解spring的AOP的注解

2.分析

2.1路径

  1. 前置通知
  2. 后置通知
  3. 环绕通知
  4. 异常通知
  5. 最终通知

2.2步骤

  1. 创建工程, 导入坐标
  2. 创建Dao和增强的类, 注册
  3. 开启AOP的注解支持
  4. 在增强类上面添加@Aspect
  5. 在增强类的增强方法上面添加

    • @Before()
    • @AfterReturning()
    • @Around()
    • @AfterThrowing()
    • @After()

3.讲解

3.1前置通知

  • 添加坐标
  1. <dependencies>
  2. <!--Spring核心容器-->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>5.0.2.RELEASE</version>
  7. </dependency>
  8. <!--SpringAOP相关的坐标-->
  9. <dependency>
  10. <groupId>org.aspectj</groupId>
  11. <artifactId>aspectjweaver</artifactId>
  12. <version>1.8.7</version>
  13. </dependency>
  14. <!--Spring整合单元测试-->
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-test</artifactId>
  18. <version>5.0.2.RELEASE</version>
  19. </dependency>
  20. <!--单元测试-->
  21. <dependency>
  22. <groupId>junit</groupId>
  23. <artifactId>junit</artifactId>
  24. <version>4.12</version>
  25. <scope>test</scope>
  26. </dependency>
  27. </dependencies>
  • 定义被增强的业务逻辑类 ```java package com.itheima.service.impl;

import com.itheima.service.UserService; import org.springframework.stereotype.Service;

/**

  • 包名:com.itheima.service.impl *
  • @author Leevi
  • 日期2020-08-12 08:36
  • 目标1:在执行增删改查方法之前,都做权限校验 前置通知: before
  • 目标2:在执行增删改查方法之后(没有出现异常), 都打印日志 后置通知: after-returning
  • 目标3:在执行增删改查方法出现异常之后,都进行友好的提示 异常通知: after-throwing
  • 目标4:在执行增删改查方法之后,无论出没出现异常,均打印一句”执行完毕” 最终通知: after
  • 目标5:计算update方法的执行时间 环绕通知: around */ @Service public class UserServiceImpl implements UserService { @Override public void add() {

    1. System.out.println("执行添加...");
    2. int num = 10/0;

    }

    @Override public void delete() {

    1. System.out.println("执行删除...");

    }

    @Override public void update() {

    1. try {
    2. Thread.sleep(3000);
    3. } catch (InterruptedException e) {
    4. e.printStackTrace();
    5. }
    6. System.out.println("执行修改...");

    }

    @Override public void select() {

    1. System.out.println("执行查询...");

    } } ```

  • 定义切面类,在切面增强类上面使用注解 @Aspect并且在切面类中定义切入点方法 ```java package com.itheima.aspect;

import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;

/**

  • 包名:com.itheima.aspect *
  • @author Leevi
  • 日期2020-08-12 08:39 *
    1. 注解方式配置切入点 在方法上添加Pointcut注解配置切入点,方法的名字就是切入点的唯一标识
    1. 配置通知
    1. 前置通知 Before注解
    1. 后置通知 AfterReturning注解
    1. 异常通知 AfterThrowing注解
    1. 最终通知 After注解
    1. 环绕通知 Around注解
    1. 配置切面:在切面类上添加Aspect注解 / @Component @Aspect public class PermissionAspect { @Pointcut(“execution( com.itheima.service.impl.UserServiceImpl.*(..))”) public void pt1(){

      }

      @Pointcut(“execution(* com.itheima.service.impl.UserServiceImpl.update(..))”) public void pt2(){

      }

      @Before(“pt1()”) public void checkPermission(){ System.out.println(“校验权限…”); }

      @AfterReturning(“pt1()”) public void printLog(){ System.out.println(“打印日志…”); }

      @AfterThrowing(“pt1()”) public void showException(){ System.out.println(“出现异常了,请检查…”); }

      @After(“pt1()”) public void showEnd(){ System.out.println(“执行完毕…”); }

      //计算目标方法的执行时长 @Around(“pt2()”) public void showMillions(ProceedingJoinPoint joinPoint){ //1. 记录当前时间 long timeMillis1 = System.currentTimeMillis(); //2. 执行目标方法 try {

      1. joinPoint.proceed();

      } catch (Throwable throwable) {

      1. throwable.printStackTrace();

      } //3. 再记录当前时间 long timeMillis2 = System.currentTimeMillis(); //4. 将两次的时间相减,得到方法的执行时长 System.out.println(timeMillis2 - timeMillis1); } } ```

  • 创建配置文件

    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:aop="http://www.springframework.org/schema/aop"
    5. xmlns:context="http://www.springframework.org/schema/context"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans
    7. http://www.springframework.org/schema/beans/spring-beans.xsd
    8. http://www.springframework.org/schema/aop
    9. http://www.springframework.org/schema/aop/spring-aop.xsd
    10. http://www.springframework.org/schema/context
    11. http://www.springframework.org/schema/context/spring-context.xsd">
    12. <!--1. 包扫描-->
    13. <context:component-scan base-package="com.itheima"/>
    14. <!--
    15. 2. 加载aop的注解驱动
    16. -->
    17. <aop:aspectj-autoproxy />
    18. </beans>

第二章 - Spring中的JdbcTemplate 【了解】

知识点-JdbcTemplate基本使用

1.目标

  • 能够使用JdbcTemplate

2.路径

  1. JdbcTemplate介绍
  2. JdbcTemplate入门
  3. 使用JdbcTemplate完成CRUD

3.讲解

3.1JdbcTemplate介绍

  1. Spring除了IOC AOP之外,还对Dao层的提供了支持。 就算没有框架,也对原生的JDBC提供了支持。它是spring框架中提供的一个对象,是对原始Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。
持久化技术 模版类
JDBC org.springframework.jdbc.core.JdbcTemplate
Hibrenate org.springframework.orm.hibernate5.HibernateTemplate
MyBatis org.mybatis.spring.SqlSessionTemplate

3.2JDBC模版入门案例

  • 创建Maven工程,导入坐标
  1. <dependencies>
  2. <!--Spring核心容器-->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>5.0.2.RELEASE</version>
  7. </dependency>
  8. <!--SpringJdbc-->
  9. <dependency>
  10. <groupId>org.springframework</groupId>
  11. <artifactId>spring-jdbc</artifactId>
  12. <version>5.0.2.RELEASE</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>mysql</groupId>
  16. <artifactId>mysql-connector-java</artifactId>
  17. <version>5.1.6</version>
  18. </dependency>
  19. <!--Spring整合单元测试-->
  20. <dependency>
  21. <groupId>org.springframework</groupId>
  22. <artifactId>spring-test</artifactId>
  23. <version>5.0.2.RELEASE</version>
  24. </dependency>
  25. <!--单元测试-->
  26. <dependency>
  27. <groupId>junit</groupId>
  28. <artifactId>junit</artifactId>
  29. <version>4.12</version>
  30. <scope>test</scope>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.projectlombok</groupId>
  34. <artifactId>lombok</artifactId>
  35. <version>1.18.12</version>
  36. </dependency>
  37. <!--druid连接池-->
  38. <dependency>
  39. <groupId>com.alibaba</groupId>
  40. <artifactId>druid</artifactId>
  41. <version>1.1.18</version>
  42. </dependency>
  43. </dependencies>
  • Account
  1. package com.itheima.pojo;
  2. import lombok.Data;
  3. /**
  4. * 包名:com.itheima.pojo
  5. *
  6. * @author Leevi
  7. * 日期2020-08-09 14:55
  8. */
  9. @Data
  10. public class Account {
  11. private String name;
  12. private Integer id;
  13. private Double money;
  14. }
  • 使用JDBC模版API
  1. //使用JDBC模版保存
  2. public void save(Account account) {
  3. //1. 创建数据源
  4. DriverManagerDataSource dataSource = new DriverManagerDataSource();
  5. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  6. dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day03");
  7. dataSource.setUsername("root");
  8. dataSource.setPassword("123456");
  9. //2. 创建JDBC模版
  10. JdbcTemplate jdbcTemplate = new JdbcTemplate();
  11. jdbcTemplate.setDataSource(dataSource);
  12. //3.操作数据库
  13. String sql = "insert into account values(?,?,?)";
  14. jdbcTemplate.update(sql, null,account.getName(),account.getMoney())
  15. }

3.3.使用JDBC模版完成CRUD

  1. 增加
    1. String sql = "insert into account values(?,?,?)";
    2. jdbcTemplate.update(sql, null,account.getName(),account.getMoney());
  1. 修改
    1. String sql ="update account set name = ? where id = ?";
    2. Object[] objects = {user.getName(), user.getId()};
    3. jdbcTemplate.update(sql,objects);
  1. 删除
    1. String sql = "delete from account where id=?";
    2. jdbcTemplate.update(sql, 6);
  1. 查询单个值
    1. String sql = "select count(*) from t_user";
    2. Long n = jdbcTemplate.queryForObject(sql, Long.class);
  1. String sql = "select name from t_user where id=?";
  2. String name = jdbcTemplate.queryForObject(sql, String.class, 4);
  3. System.out.println(name);
  1. 查询单个对象
    1. String sql = "select * from account where id = ?";
    2. User user = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(Account.class),id);
  1. 查询集合
    1. String sql = "select * from account";
    2. List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
    3. System.out.println(list);
  1. String sql = "select * from account";
  2. List<Account> list = List<User> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class));

4.小结

  1. JdbcTemplate是Spring里面的持久层一个工具包, 封装了Jdbc
  2. 使用步骤

    • 创建DataSource
    • 创建JDBCTemplate
    • 调用update(), query(), queryForObject()

知识点-在dao中使用JdbcTemplate

1.目标

  • 能够使用spring的jdbc的模板

2.路径

  1. 方式一在dao中定义JdbcTemplate
  2. 方式二dao继承JdbcDaoSupport

3.讲解

3.1方式一

  1. 这种方式我们采取在dao中定义JdbcTemplate
  • AccountDaoImpl.java
  1. public class AccountDaoImpl implements AccountDao {
  2. @Autowired
  3. private JdbcTemplate jdbcTemplate;
  4. @Override
  5. public Account findAccountById(Integer id) {
  6. List<Account> list = jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id);
  7. return list.isEmpty()?null:list.get(0);
  8. }
  9. @Override
  10. public Account findAccountByName(String name) {
  11. List<Account> list = jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name);
  12. if(list.isEmpty()){
  13. return null;
  14. }
  15. if(list.size()>1){
  16. throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
  17. }
  18. return list.get(0);
  19. }
  20. @Override
  21. public void updateAccount(Account account) {
  22. jdbcTemplate.update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
  23. }
  24. }
  • applicationContext.xml
  1. <!-- 配置一个dao -->
  2. <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
  3. <!-- 注入jdbcTemplate -->
  4. <property name="jdbcTemplate" ref="jdbcTemplate"></property>
  5. </bean>
  6. <!-- 配置一个数据库的操作模板:JdbcTemplate -->
  7. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  8. <property name="dataSource" ref="dataSource"></property>
  9. </bean>
  10. <!-- 配置数据源 -->
  11. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  12. <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
  13. <property name="url" value="jdbc:mysql:///spring_day04"></property>
  14. <property name="username" value="root"></property>
  15. <property name="password" value="123456"></property>
  16. </bean>

3.2方式二

  1. 这种方式我们采取让dao继承JdbcDaoSupport
  • AccountDaoImpl.java
  1. public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
  2. @Override
  3. public Account findAccountById(Integer id) {
  4. //getJdbcTemplate()方法是从父类上继承下来的。
  5. List<Account> list = getJdbcTemplate().query("select * from account where id = ? ",new AccountRowMapper(),id);
  6. return list.isEmpty()?null:list.get(0);
  7. }
  8. @Override
  9. public Account findAccountByName(String name) {
  10. //getJdbcTemplate()方法是从父类上继承下来的。
  11. List<Account> list = getJdbcTemplate().query("select * from account where name = ? ",new AccountRowMapper(),name);
  12. if(list.isEmpty()){
  13. return null;
  14. }
  15. if(list.size()>1){
  16. throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
  17. }
  18. return list.get(0);
  19. }
  20. @Override
  21. public void updateAccount(Account account) {
  22. //getJdbcTemplate()方法是从父类上继承下来的。
  23. getJdbcTemplate().update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
  24. }
  25. }
  • 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. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 配置dao2 -->
  7. <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
  8. <!-- 注入dataSource -->
  9. <property name="dataSource" ref="dataSource"></property>
  10. </bean>
  11. <!-- 配置数据源 -->
  12. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  13. <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
  14. <property name="url" value="jdbc:mysql:///spring_day04"></property>
  15. <property name="username" value="root"></property>
  16. <property name="password" value="123456"></property>
  17. </bean>
  18. </beans>

4.小结

  1. 方式一: 自己注册JDBCTemplate, 自己在Dao注入JDBCTemplate

  2. 方式二: 继承JdbcDaoSupport, 不需要自己注册JDBCTemplate, 也不需要自己注入JDBCTemplate
    需要注入DataSource

第三章-Spring配置第三方连接池

知识点-Spring配置第三方连接池

1.目标

  • 能够配置spring的连接池

2.路径

  1. Spring配置C3P0连接池
  2. Spring配置Druid连接池
  3. Spring配置HikariCP连接池【扩展】

3.讲解

3.1Spring配置C3P0连接池

官网:http://www.mchange.com/projects/c3p0/

步骤:

  1. 导入c3p0的坐标
  2. 注册连接池(修改DataSource的class以及四个基本项)

实现:

  • 导入坐标
  1. <dependency>
  2. <groupId>c3p0</groupId>
  3. <artifactId>c3p0</artifactId>
  4. <version>0.9.1.2</version>
  5. </dependency>
  • 配置数据源连接池
  1. <!-- 配置C3P0数据库连接池 -->
  2. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  3. <property name="jdbcUrl" value="jdbc:mysql:///spring_jdbc" />
  4. <property name="driverClass" value="com.mysql.jdbc.Driver" />
  5. <property name="user" value="root" />
  6. <property name="password" value="123456" />
  7. </bean>
  8. <!-- 管理JDBC模版 -->
  9. <bean id="jdbcTemplete" class="org.springframework.jdbc.core.JdbcTemplate">
  10. <property name="dataSource" ref="dataSource" />
  11. </bean>

核心类:`com.mchange.v2.c3p0.ComboPooledDataSource

3.2.Spring配置Druid连接池

官网:http://druid.io/

步骤:

  1. 导入Druid坐标
  2. 修改DataSource的class(四个基本项)

实现:

  • 导入坐标
    1. <dependency>
    2. <groupId>com.alibaba</groupId>
    3. <artifactId>druid</artifactId>
    4. <version>1.0.9</version>
    5. </dependency>
  • 配置数据源连接池
  1. <!--注册dataSource -->
  2. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  3. <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
  4. <property name="url" value="jdbc:mysql://localhost:3306/spring_day03"></property>
  5. <property name="username" value="root"></property>
  6. <property name="password" value="123456"></property>
  7. </bean>
  8. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  9. <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
  10. </bean>

3.3.Spring配置HikariCP连接池【扩展】

官网:https://github.com/brettwooldridge/HikariCP

步骤:

  1. 添加HikariCP坐标
  2. 修改DataSource的class(四个基本项)

实现:

  • 导入HikariCP坐标
    1. <dependency>
    2. <groupId>com.zaxxer</groupId>
    3. <artifactId>HikariCP</artifactId>
    4. <version>3.1.0</version>
    5. </dependency>
  • 配置数据源连接池

    1. <!-- 配置HikariCP数据库连接池 -->
    2. <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    3. <property name="jdbcUrl" value="jdbc:mysql:///spring_jdbc" />
    4. <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    5. <property name="username" value="root" />
    6. <property name="password" value="123456" />
    7. </bean>
    8. <!-- 管理JDBC模版 -->
    9. <bean id="jdbcTemplete" class="org.springframework.jdbc.core.JdbcTemplate">
    10. <property name="dataSource" ref="dataSource" />
    11. </bean>
  1. > 核心类:`com.zaxxer.hikari.HikariDataSource`
  2. + 为什么HikariCP为什么越来越火?
  3. + 效率高
  4. + 一直在维护
  5. + ==SpringBoot2.0 现在已经把HikariCP作为默认的连接池了==
  6. + 为什么HikariCP被号称为性能最好的Java数据库连接池?
  7. + 优化并精简字节码: HikariCP利用了一个第三方的Java字节码修改类库Javassist来生成委托实现动态代理
  8. + 优化代理和拦截器:减少代码,代码量越少。一般意味着运行效率越高、发生bug的可能性越低.
  9. ![1540557295765](img/1540557295765.png)
  10. + 自定义集合类型ConcurrentBagConcurrentBag的实现借鉴于C#中的同名类,是一个专门为连接池设计的lock-less集合,实现了比LinkedBlockingQueue、LinkedTransferQueue更好的并发性能。ConcurrentBag内部同时使用了ThreadLocal和CopyOnWriteArrayList来存储元素,其中CopyOnWriteArrayList是线程共享的。ConcurrentBag采用了queue-stealing的机制获取元素:首先尝试从ThreadLocal中获取属于当前线程的元素来避免锁竞争,如果没有可用元素则再次从共享的CopyOnWriteArrayList中获取。此外,ThreadLocal和CopyOnWriteArrayList在ConcurrentBag中都是成员变量,线程间不共享,避免了伪共享(false sharing)的发生。
  11. + 使用FastList替代ArrayList: FastList是一个List接口的精简实现,只实现了接口中必要的几个方法。JDK ArrayList每次调用get()方法时都会进行rangeCheck检查索引是否越界,FastList的实现中去除了这一检查,只要保证索引合法那么rangeCheck就成为了不必要的计算开销(当然开销极小)。
  12. ### 4.小结
  13. 1. 导入连接池坐标
  14. 2. DataSourceclass属性值, 配置属性名
  15. ## 知识点-Spring引入Properties配置文件
  16. ### 1.目标
  17. - [ ] 掌握Spring引入Properties配置文件
  18. ### 2.步骤
  19. 1. 定义jdbc.properties
  20. 2. jdbc.properties引入applicationContext.xml
  21. 3. 使用表达式根据key获得value
  22. ### 3.实现
  23. #### 3.1jdbc.properties
  24. ```properties
  25. jdbc.driver=com.mysql.jdbc.Driver
  26. jdbc.url=jdbc:mysql://localhost:3306/spring_day03
  27. jdbc.username=root
  28. jdbc.password=123456

3.2 引入外部properties文件

  • 引入配置文件方式一(不推荐使用)
  1. <!-- 引入properties配置文件:方式一 (繁琐不推荐使用) -->
  2. <bean id="properties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  3. <property name="location" value="classpath:jdbc.properties" />
  4. </bean>
  • 引入配置文件方式二【推荐使用】
  1. <!-- 引入properties配置文件:方式二 (简单推荐使用) -->
  2. <context:property-placeholder location="classpath:jdbc.properties" />

classpath表示的是类路径,对于配置文件而言也就是那个resources根目录

  • bean标签中引用配置文件内容
  1. <!-- hikariCP 连接池 -->
  2. <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
  3. <property name="jdbcUrl" value="${jdbc.url}" />
  4. <property name="driverClassName" value="${jdbc.driver}" />
  5. <property name="username" value="${jdbc.username}" />
  6. <property name="password" value="${jdbc.password}" />
  7. </bean>

注意:在使用<context:property-placeholder/>标签时,properties配置文件中的key一定要是带点分隔的。例如jdbc.url

4.小结

  1. 定义jdbc.properties
  2. 把jdbc.properties引入到applicationContext.xml
  3. 根据key读取value

第四章-Spring管理事务

知识点-Spring管理事务概述(了解即可)

1.目标

  • 知道Spring管理事务相关的API

2.路径

  1. 概述
  2. 相关的API

3.讲解

3.1概述

  1. 由于Spring对持久层的很多框架都有支持 Hibernate jdbc JdbcTemplate , MyBatis ,由于使用的框架不同,所以使用事务管理操作API 也不尽相同。 为了规范这些操作, Spring统一定义一个事务的规范 ,这其实是一个接口 。这个接口的名称 PlatformTrasactionManager.并且它对已经做好的框架都有支持.
  2. 如果dao层使用的是JDBC, JdbcTemplate 或者mybatis,那么 可以使用DataSourceTransactionManager 来处理事务
  3. 如果dao层使用的是 Hibernate, 那么可以使用HibernateTransactionManager 来处理事务

3.2相关的API

3.2.1PlatformTransactionManager
  1. 平台事务管理器是一个接口,实现类就是Spring真正管理事务的对象。
  2. 常用的实现类:
  3. **DataSourceTransactionManager** :JDBC开发的时候(JDBCTemplate,MyBatis),使用事务管理。
  4. HibernateTransactionManager :Hibernate开发的时候,使用事务管理。

3.2.2 TransactionDefinition
  1. 事务定义信息中定义了事务的隔离级别,传播行为,超时信息,只读。

3.2.3 TransactionStatus:事务的状态信息
  1. 事务状态信息中定义事务是否是新事务,是否有保存点。

4.小结

  1. Spring管理事务是通过事务管理器. 定义了一个接口PlatformTransactionManager

    • DataSourceTransactionManager JDBC,MyBatis,JDBCTemplate
    • HibernateTransactionManager Hibernate

知识点-编程式(通过代码)(硬编码)事务【了解】

1.目标

  • 了解Spring编程式事务

2.步骤

  1. 创建DataSource对象
  2. 创建JDBCTemplate对象
  3. 创建事务管理器, 传入DataSource. DataSourceTransactionManager
  4. 创建事务模版
  5. 通过事务模版进行事务处理
  6. 在事务里面操作数据库

3.实现

  • 添加依赖
  1. <dependencies>
  2. <!--依赖-->
  3. <!--1. spring的核心依赖-->
  4. <dependency>
  5. <groupId>org.springframework</groupId>
  6. <artifactId>spring-context</artifactId>
  7. <version>5.0.2.RELEASE</version>
  8. </dependency>
  9. <!--2. spring-jdbc的依赖-->
  10. <dependency>
  11. <groupId>org.springframework</groupId>
  12. <artifactId>spring-jdbc</artifactId>
  13. <version>5.0.2.RELEASE</version>
  14. </dependency>
  15. <!--3. spring-test-->
  16. <dependency>
  17. <groupId>org.springframework</groupId>
  18. <artifactId>spring-test</artifactId>
  19. <version>5.0.2.RELEASE</version>
  20. </dependency>
  21. <!--10. aop的依赖-->
  22. <dependency>
  23. <groupId>org.aspectj</groupId>
  24. <artifactId>aspectjweaver</artifactId>
  25. <version>1.8.7</version>
  26. </dependency>
  27. <!--4. mysql-->
  28. <dependency>
  29. <groupId>mysql</groupId>
  30. <artifactId>mysql-connector-java</artifactId>
  31. <version>5.1.6</version>
  32. </dependency>
  33. <!--5. mybatis-->
  34. <dependency>
  35. <groupId>org.mybatis</groupId>
  36. <artifactId>mybatis</artifactId>
  37. <version>3.5.3</version>
  38. </dependency>
  39. <!--6. mybatis-spring-->
  40. <dependency>
  41. <groupId>org.mybatis</groupId>
  42. <artifactId>mybatis-spring</artifactId>
  43. <version>1.3.0</version>
  44. </dependency>
  45. <!--7. Junit的依赖-->
  46. <dependency>
  47. <groupId>junit</groupId>
  48. <artifactId>junit</artifactId>
  49. <version>4.12</version>
  50. <scope>test</scope>
  51. </dependency>
  52. <!--8. lombok的依赖-->
  53. <dependency>
  54. <groupId>org.projectlombok</groupId>
  55. <artifactId>lombok</artifactId>
  56. <version>1.18.10</version>
  57. </dependency>
  58. <!--9. 日志的依赖-->
  59. <!-- log start -->
  60. <dependency>
  61. <groupId>log4j</groupId>
  62. <artifactId>log4j</artifactId>
  63. <version>1.2.12</version>
  64. </dependency>
  65. <dependency>
  66. <groupId>org.slf4j</groupId>
  67. <artifactId>slf4j-api</artifactId>
  68. <version>1.6.6</version>
  69. </dependency>
  70. <dependency>
  71. <groupId>org.slf4j</groupId>
  72. <artifactId>slf4j-log4j12</artifactId>
  73. <version>1.6.6</version>
  74. </dependency>
  75. <!-- log end -->
  76. </dependencies>
  • 代码
  1. package com.itheima.service.impl;
  2. import com.itheima.dao.AccountDao;
  3. import com.itheima.pojo.Account;
  4. import com.itheima.service.AccountService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  7. import org.springframework.stereotype.Service;
  8. import org.springframework.transaction.TransactionStatus;
  9. import org.springframework.transaction.support.TransactionCallback;
  10. import org.springframework.transaction.support.TransactionTemplate;
  11. import javax.sql.DataSource;
  12. /**
  13. * 包名:com.itheima.service.impl
  14. * @author Leevi
  15. * 日期2020-08-12 10:57
  16. * 持久层不同的框架有不同的事务控制方案:
  17. * 1. 原始的JDBC:
  18. * 1.1 开启事务: connection.setAutoCommit(false);
  19. * 1.2 提交事务: connection.commit();
  20. * 1.3 回滚事务: connection.rollback();
  21. *
  22. * 2. DBUtils框架: 和原始的JDBC是一样的
  23. * 3. mybatis框架: 底层也是使用的JDBC的事务
  24. * 3.1 开启事务: sqlSessionFactory.openSession(); 开启事务
  25. * 3.2 提交事务: sqlSession.commit();
  26. * 3.3 回滚事务: sqlSession.rollback();
  27. * 4. 只要某个持久层框架和spring整合了,那么事务相关的操作就都交给spring控制
  28. * 4.1 编程式事务(了解)
  29. * 4.2 声明式事务(重点掌握)
  30. */
  31. @Service
  32. public class AccountServiceImpl implements AccountService{
  33. @Autowired
  34. private AccountDao accountDao;
  35. @Autowired
  36. private DataSource dataSource;
  37. @Override
  38. public void transfer(String fromName, String toName, double money) {
  39. //创建事务管理者
  40. DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
  41. transactionManager.setDataSource(dataSource);
  42. //创建事务模板
  43. TransactionTemplate transactionTemplate = new TransactionTemplate();
  44. //给事务模板配置事务管理者
  45. transactionTemplate.setTransactionManager(transactionManager);
  46. transactionTemplate.execute(new TransactionCallback<Object>() {
  47. @Override
  48. public Object doInTransaction(TransactionStatus status) {
  49. //1. 转出账户扣款
  50. accountDao.updateAccount(new Account(null,fromName,-money));
  51. //出现异常
  52. int num = 10/0;
  53. //2. 转入账户收款
  54. accountDao.updateAccount(new Account(null,toName,money));
  55. return null;
  56. }
  57. });
  58. }
  59. }

4.小结

  1. 我们项目开发 一般不会使用编程式(硬编码)方式. 一般使用声明式(配置)事务

    • xml方式
    • 注解方式

知识点-Spring声明式事务-xml配置方式【重点】

Spring的声明式事务的作用是: 无论spring集成什么dao框架,事务代码都不需要我们再编写了

声明式的事务管理的思想就是AOP的思想。面向切面的方式完成事务的管理。声明式事务有两种,xml配置方式和注解方式.

1.目标

  • 使用xml方式配置事务

2.步骤

  1. 注册事务管理器, 配置数据源
  2. 配置事务建议(事务规则: 事务隔离级别, 遇到什么异常回滚,是否只读…)
  3. 配置AOP

    • 配置切入点
    • 配置切面

3.讲解

3.1实现

  1. <dependencies>
  2. <!--依赖-->
  3. <!--1. spring的核心依赖-->
  4. <dependency>
  5. <groupId>org.springframework</groupId>
  6. <artifactId>spring-context</artifactId>
  7. <version>5.0.2.RELEASE</version>
  8. </dependency>
  9. <!--2. spring-jdbc的依赖-->
  10. <dependency>
  11. <groupId>org.springframework</groupId>
  12. <artifactId>spring-jdbc</artifactId>
  13. <version>5.0.2.RELEASE</version>
  14. </dependency>
  15. <!--3. spring-test-->
  16. <dependency>
  17. <groupId>org.springframework</groupId>
  18. <artifactId>spring-test</artifactId>
  19. <version>5.0.2.RELEASE</version>
  20. </dependency>
  21. <!--10. aop的依赖-->
  22. <dependency>
  23. <groupId>org.aspectj</groupId>
  24. <artifactId>aspectjweaver</artifactId>
  25. <version>1.8.7</version>
  26. </dependency>
  27. <!--4. mysql-->
  28. <dependency>
  29. <groupId>mysql</groupId>
  30. <artifactId>mysql-connector-java</artifactId>
  31. <version>5.1.6</version>
  32. </dependency>
  33. <!--5. mybatis-->
  34. <dependency>
  35. <groupId>org.mybatis</groupId>
  36. <artifactId>mybatis</artifactId>
  37. <version>3.5.3</version>
  38. </dependency>
  39. <!--6. mybatis-spring-->
  40. <dependency>
  41. <groupId>org.mybatis</groupId>
  42. <artifactId>mybatis-spring</artifactId>
  43. <version>1.3.0</version>
  44. </dependency>
  45. <!--7. Junit的依赖-->
  46. <dependency>
  47. <groupId>junit</groupId>
  48. <artifactId>junit</artifactId>
  49. <version>4.12</version>
  50. <scope>test</scope>
  51. </dependency>
  52. <!--8. lombok的依赖-->
  53. <dependency>
  54. <groupId>org.projectlombok</groupId>
  55. <artifactId>lombok</artifactId>
  56. <version>1.18.10</version>
  57. </dependency>
  58. <!--9. 日志的依赖-->
  59. <!-- log start -->
  60. <dependency>
  61. <groupId>log4j</groupId>
  62. <artifactId>log4j</artifactId>
  63. <version>1.2.12</version>
  64. </dependency>
  65. <dependency>
  66. <groupId>org.slf4j</groupId>
  67. <artifactId>slf4j-api</artifactId>
  68. <version>1.6.6</version>
  69. </dependency>
  70. <dependency>
  71. <groupId>org.slf4j</groupId>
  72. <artifactId>slf4j-log4j12</artifactId>
  73. <version>1.6.6</version>
  74. </dependency>
  75. <!-- log end -->
  76. </dependencies>
  • 配置事务管理器
    1. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    2. <property name="dataSource" ref="dataSource"></property>
    3. </bean>
  • 配置事务建议(事务的规则)

    1. <!--配置事务规则-->
    2. <tx:advice id="transferAdvice" transaction-manager="transactionManager">
    3. <!--配置事务的属性-->
    4. <tx:attributes>
    5. <!--
    6. 哪个方法需要使用什么样的事务配置
    7. rollback-for="java.lang.Exception" 什么时候回滚:遇到所有的Exception都会回滚
    8. no-rollback-for="java.lang.NullPointerException" 什么时候不回滚:遇到NullPointerException不回滚
    9. timeout="-1" 事务的超时时间,默认不超时
    10. read-only="false" 是否是只读事务,默认不是只读事务,只读事务只会针对于查询方法,如果是增删改一定不能设置为只读
    11. isolation="" 事务的隔离级别: 目的是为了防止不同事务之间相互影响
    12. 1. Read Uncommitted 读取到未提交的事务,在这种隔离级别下,可能发生脏读、不可重复读、幻读
    13. 2. Read Committed(Oracle的默认隔离级别) 读取到已提交的事务,在这种隔离级别下,不可能发生脏读,但是可能发生不可重复读和幻读
    14. 3. Repeatable Read(mysql的默认隔离级别) 可重复读,在这种隔离级别下不会发生脏读、不可重复读,但是有可能发生幻读
    15. 4. Serializable 串行化的,在这种隔离级别下不会发生脏读、不可重复读、幻读
    16. propagation="" 事务的传播行为
    17. - PROPAGATION_REQUIRED:默认值,也是最常用的场景.
    18. 如果当前没有事务,就新建一个事务,
    19. 如果已经存在一个事务中,加入到这个事务中。
    20. - PROPAGATION_SUPPORTS:
    21. 如果当前没有事务,就以非事务方式执行。
    22. 如果已经存在一个事务中,加入到这个事务中。
    23. - PROPAGATION_MANDATORY
    24. 如果当前没有有事务,就抛出异常;
    25. 如果已经存在一个事务中,加入到这个事务中。
    26. 保证不在同一个事务里:
    27. - PROPAGATION_REQUIRES_NEW
    28. 如果当前有事务,把当前事务挂起,创建新的事务但独自执行
    29. - PROPAGATION_NOT_SUPPORTED
    30. 如果当前存在事务,就把当前事务挂起。不创建事务
    31. - PROPAGATION_NEVER
    32. 如果当前存在事务,抛出异常
    33. -->
    34. <tx:method name="transfer"
    35. rollback-for="java.lang.Exception"
    36. no-rollback-for="java.lang.NullPointerException"/>
    37. </tx:attributes>
    38. </tx:advice>
  • 配置事务的AOP
    1. <aop:config>
    2. <!--声明切入点-->
    3. <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.AccountServiceImpl.transfer(..))"/>
    4. <!--绑定切入点和事务-->
    5. <aop:advisor advice-ref="transferAdvice" pointcut-ref="pt1"></aop:advisor>
    6. </aop:config>

3.2事务的传播行为

3.2.1事务的传播行为的作用
  1. 我们一般都是将事务设置在Service层,那么当我们调用Service层的一个方法的时候, 它能够保证我们的这个方法中,执行的所有的对数据库的更新操作保持在一个事务中, 在事务层里面调用的这些方法要么全部成功,要么全部失败。
  2. 如果你的Service层的这个方法中,除了调用了Dao层的方法之外, 还调用了本类的其他的Service方法,那么在调用其他的Service方法的时候, 我必须保证两个service处在同一个事务中,确保事物的一致性。
  3. 事务的传播特性就是解决这个问题的。

3.2.2 事务的传播行为的取值

保证在同一个事务里面:

  • PROPAGATION_REQUIRED:默认值,也是最常用的场景.
    如果当前没有事务,就新建一个事务,
    如果已经存在一个事务中,加入到这个事务中。

  • PROPAGATION_SUPPORTS:
    如果当前没有事务,就以非事务方式执行。
    如果已经存在一个事务中,加入到这个事务中。

  • PROPAGATION_MANDATORY
    如果当前没有有事务,就抛出异常;
    如果已经存在一个事务中,加入到这个事务中。

保证不在同一个事物里:

  • PROPAGATION_REQUIRES_NEW
    如果当前有事务,把当前事务挂起,创建新的事务但独自执行

  • PROPAGATION_NOT_SUPPORTED
    如果当前存在事务,就把当前事务挂起。不创建事务

  • PROPAGATION_NEVER
    如果当前存在事务,抛出异常

4.小结

  1. 注册事务管理器, 需要注入DataSource
  2. 配置事务建议(规则: 隔离级别, 事务传播行为…)
  3. 配置AOP

    • 配置切入点
    • 配置切面

知识点-spring声明式事务-注解方式【重点】

1.目标

  • 使用注解方式配置事务

2.步骤

  1. 注册事务管理器

  2. 开启事务注解支持

  3. 在业务类上面添加@Transactional

3.实现

  • 在applicationContext里面打开注解驱动
    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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. http://www.springframework.org/schema/aop/spring-aop.xsd
    9. http://www.springframework.org/schema/tx
    10. http://www.springframework.org/schema/tx/spring-tx.xsd">
    11. <import resource="classpath:application-mybatis.xml"></import>
    12. <!--配置申明式事务-->
    13. <!--
    14. 注解方式配置声明式事务
    15. 1. 配置事务管理者
    16. 2. 加载事务注解驱动
    17. 3. 在代码中使用Transactional注解来标注,哪个方法需要使用事务
    18. -->
    19. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    20. <property name="dataSource" ref="dataSource"></property>
    21. </bean>
    22. <tx:annotation-driven transaction-manager="transactionManager"/>
    23. </beans>
  • 在业务逻辑类上面使用注解
    @Transactional : 如果在类上声明,那么标记着该类中的所有方法都使用事务管理。也可以作用于方法上, 那么这就表示只有具体的方法才会使用事务。

4.小结

4.1步骤

  1. 注册事务管理器
  2. 开启事务注解支持
  3. 在业务类上面添加@Transactional

4.2两种方式比较

  • xml方式

    • 优点: 只需要配一次, 全局生效, 容易维护
    • 缺点: 相对注解而言 要麻烦一点
  • 注解方式

    • 优点: 配置简单
    • 缺点: 写一个业务类就配置一次, 事务细节不好处理, 不好维护