Spring第三阶段

Spring

Spring的AOP的注解

AOP注解的入门

  1. 创建项目,引入jar包
  2. 创建接口跟实现类
  3. 将类的创建交给Spring

    1
    2
    3
    <!-- 配置目标类-->
            <bean id="customerDao" class="com.itheima.aop.demo1.CustomerDaoImpl">
            </bean>
  4. 编写切面类

  5. 开启AOP的注解 <aop:aspectj-autoproxy />
  6. 切面类的注解开发 @Aspect
  7. 在方法上加注解
    • 前置增强 @Before(value="execution(* com.spring...)")
    • 后置增强,可以添加返回值 @AfterReturning(value="execution(* com.spring...)",returning="obj")
    • 环绕增 @Around(value="execution(* com.spring...)")
    • 异常捕获,可以获得异常信息 @AfterThrowing(value="execution(* com.spring...)",throwing="ex")
    • 最终增强 @After(value="execution(* com.spring...)")
  • 可以把切入点注解提取出来,在最后加一个没有内容的方法,然后上面注解加这个,然后,上面的每一个方法上需要切入哪,只需要在value中加一个 类名.方法名 即可。
1
2
@Pointcut(value="execution(* com.spring...)")
private void pointCut01(){}

Spring的JDBC

Spring 的JDBC的模板

Spring是EE开发的一站式框架,一站式框架就有每层的解决方案(包括持久层)。

Spring的JDBC模板的入门

spring里面了很多对于持久层的解决方案。(JDBC,hibernate均有)

  1. 创建项目,引入Spring的需要的jar包,还有Spring核心包中的两个包jdbc,tx 还有连接数据库的包 connection,Spring的版本还需要引入AOP的包
  2. 使用JDBC的模板
1
2
3
4
5
6
7
8
9
10
11
//创建连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//设置连接数据库的相关的参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///数据库");
dataSource.setUsername(" ");
dataSource.setPassword(" ");
JdbcTemplate jdbctemplate = new JdbcTemplate();
JdbcTemplate.setDataSource(dataSource);
jdbctemplate.update("sql语句",null,"name","password");
  • 这种方法是不好的,因为每次使用的时候还需要创建连接池,所以把连接池交给Spring管理

把连接池交给Spring管理

  • 创建xml配置文件,引入beans的约束
  • 配置内置连接池
1
2
3
4
5
6
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="" />
  <property name="url" value="" />
  <property name="username" value="" />
  <property name="password" value="" />
</bean>
  • 把JDBC的模板交给Spring管理
1
2
3
4
<bean id="jdbcTemplate" class="jdbcTemplate的路劲" >
    <property name="dataSource" ref="dataSource" />
</bean>
//这里的name必须为dataSource,因为用的是JDBC的模板
  • 测试类:

用JUnit跟Springde整合

1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringJUnit4ClassRunner.class)
@contextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateDemo2{
    @Resource(name="jdbcTemplate")
    private JdbcTemplate jdbcTemplate;
    
    @Test
    public void demo01(){
         jdbcTemplate.update("insert into account values (?,?)","张三",100d),;
    }
}

引入外界连接池

dpcp连接池

  • 导包:依赖包中apache的commons中的dpcp跟pool,用之前的也行,跟这个一样
  • 配置DBCP连接池
1
2
3
4
5
6
7
//配置DBCP的连接池
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="com.mysql,jdbc.Driver" />
  <property name="url" value="jdbc:mysql:///数据库" />
  <property name="username" value="" />
  <property name="password" value="" />
</bean>
  • 测试跟默认的一样

c3p0的连接池

  • 导包,依赖包中c3p0的包
  • 配置连接池,注意:配置属性跟之前的不一样
1
2
3
4
5
6
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <property name="driverClass" value="com.mysql,jdbc.Driver" />
  <property name="jdbcUrl" value="jdbc:mysql:///数据库" />
  <property name="user" value="" />
  <property name="password" value="" />
</bean>

提取属性文件(连接数据库的信息)

即使用配置文件,如果需要把项目交给别人也要改配置文件,所以提取出一个属性文件,改的时候只改属性文件即可

  • 定义属性文件jdbc.properties

  • 在Spring中配置文件引入属性文件:

  1. 通过<bean>引入
    1
    2
    3
    <bean  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.prorerties">
    </bean>

在配置配置文件:

  1. 但不经常用这个,经常用context标签引入
    1
    2
    3
    4
    5
    6
    7
    8
    <context:property-placeholder location="classpath:jdbc.prorerties">
    <!--  配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <property name="driverClass" value="${jdbc.driverClass}" />
       <property name="jdbcUrl" value="${jdbc.url}" />
       <property name="user" value="${jdbc.user}" />
       <property name="password" value="${jdbc.password}" />
    </bean>

JDBC模板进行CURD操作

增删改

  • 增删改的方法是通用的:
    • update(sql语句,参数);

查询

  • 单个数 : T queryForObject(String sql,Class/<T/> requiredType,Object… args)
  • 某个对象 :T queryForObject(String sql,RowMapper/<T/> rowMapper ,Object… args);
  • List集合 :List/<T/> query(String sql,RowMapper/<T/> rowMapper,Object… args);
  • 查询属性

    1
    2
    //查询id为1的账号的名称
    String name=jdbcTemplate.queryForObject(sql语句,String.class,Object 参数);
  • 统计个数

    1
    Long count=jdbcTemplate.queryForObject(sql语句,Long.class,Object 参数);
  • 查询某个对象

    • RowMapper类似于DBUtils中的 ResultSetHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
Account account=jdbcTemplate.queryForObject(sql语句,new MyRowMapper(),参数);
//可以创建一个内部类来实现RowMapper<T>
class MyRowMapper implements RowMapper<User>{
   @override
   public Account mapRow(ResultSet rs,int rowNum){
       Account account = new Account();
       account.setId(rs.getInt("id"));
       account.setName(rs.getString("name"));
       account.setMoney(rs.getDouble("money"));
       return account;
   }
}
  • 查询多个对象
1
2
List<Account> account = query(String sql,new MyRowMapper(),Object... args);
//当然也需要创建一个RowMapper<T>接口的实现类,跟上边用一个就行

Spring的事务

Spring的事务管理

事务的回顾

  • 事务的概念:
    • 逻辑上一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败
  • 事务的特性:
    • 原子性
    • 一致性
    • 隔离性
    • 持久性
  • 如果不考虑隔离性引发安全问题
    • 读问题
      • 脏读
      • 不可重复读
      • 虚读
    • 写问题
      • 丢失更新
  • 解决读问题
    • 设置事务隔离级别
      • read uncommitted
      • read committed
      • repeatable read
      • serializable

Spring的事务管理的API

  • PlatformTransactionManager:平台事务管理器(Spring中真正管理事务的对象)
    • DataSourceTransactionManager :使用JDBC操作进行事务管理时候使用
    • HibernateTransactionManager :使用Hibernate框架进行事务管理时候使用
  • TransactionDefinition :事务的定义信息
    • 事务的隔离级别
    • 事务的传播行为
    • 事务是否只读
    • 事务超时信息
  • TransactionStatus :事务的状态对象
    • 是否已经完成
    • 是否有保存点
  • 三个对象的关系:
    • Spring通过TransactionDefinition对事务进行定义,使用PlatformTransactionManager根据定义信息进行事务的管理,在事务管理过程中产生一些状态,将状态存入到TransactionStatus中。

事务的传播行为的作用和含义

  • 事务传播行为的作用

    • 事务的传播行为:解决复杂的事务的操作,业务层之间代码的相互调用 propagation
  • 事务传播行为的取值:记标红的那个即可,主要是第一个

    根据上两幅图做出的解释:

Spring的事务管理的方式

  • 编程式事务管理: 手动编写代码实现事务管理
  • 声明式事务管理: 通过配置实现事务管理
    • xml的配置方式
    • 注解方式

Spring的事务管理实现:

搭建事务管理的基本环境

用转账的案例,先写出JDBC模板:

  • 编写Dao
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AccountDaoImpl implements AccountDao {
    
    private JdbcTemplate jdbcTemplate;
    
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Override
    public void outMoney(String from, Double money) {
        jdbcTemplate.update("update account set money = money - ? where name = ?", money,from);
    }
    @Override
    public void inMoney(String to, Double money) {
        jdbcTemplate.update("update account set money = money + ? where name = ?", money,to);
    }
}
  • 配置Dao
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 引入外部属性文件:方式二:通过context标签引入 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- 配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!-- 将JDBC的模板交给Spring管理 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 配置DAO -->
    <bean id="accountDao" class="com.itheima.tx.demo1.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
  • 编写Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;
    
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    @Override
    /**
     * from:转出账号
     * to:转入账号
     * money:转账金额
     */
    public void transfer(String from, String to, Double money) {
        accountDao.outMoney(from, money);
        accountDao.inMoney(to, money);
    }
}
  • 配置Service
1
2
3
4
<!-- 配置Service -->
    <bean id="accountService" class="com.itheima.tx.demo1.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
  • 编写测试类
1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class TransactionDemo1 {
    @Resource(name="accountService")
    private AccountService accountService;
    
    @Test
    public void demo1(){
        accountService.transfer("郝强勇", "郝如花", 1000d);
    }
}

编程式事务管理

  • 配置事务管理器: :事务管理器的名称必须是transactionManager
1
2
3
4
<!-- 配置事务管理器:Spring真正管理事务的类 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
  • 配置事务管理模板
1
2
3
//配置事务管理的模板
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">   <property name="transactionManager" ref="transactionManager" />
</bean>
  • 在业务层注入事务管理的模板
1
2
3
4
5
6
<!-- 配置Service -->
    <bean id="accountService" class="com.itheima.tx.demo1.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <!-- 事务管理模板的注入 -->
        <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
  • 改写业务层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;
    
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    
    // 提供事务管理模板注入:
    private TransactionTemplate transactionTemplate;
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
    @Override
    /**
     * from:转出账号
     * to:转入账号
     * money:转账金额
     */
    public void transfer(final String from, final String to, final Double money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                accountDao.outMoney(from, money);
                int d = 1/ 0;
                accountDao.inMoney(to, money);
            }
        });
    
    }
}

声明式事务管理(底层用的就是AOP)

XML方式
  • 引入Aop的jar包
  • 恢复一下转账的环境
  • 配置事务管理器

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!-- 配置事务的增强(规范) -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!-- <tx:method name="save*" propagation="REQUIRED" />
                <tx:method name="update*" propagation="REQUIRED" />
                <tx:method name="find*" read-only="true"/> -->
                <tx:method name="transfer" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
    //propagaion :传播行为
    isolation :隔离级别
    read-only :是否为只读
    rollback-for :发生哪些异常事务会回滚,默认情况下,任何异常都会回滚
    no-rollback-for :发生哪些异常事务不会回滚
  • AOP的配置

1
2
3
4
5
 <!-- AOP的配置-->
    <aop:config>
      <aop:pointcut expression="execution(* com.itheima.tx.demo2.AccountServiceImpl.transfer(..))"  id="pointcut1"/>
     <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
    </aop:config>
注解方式
  • 恢复开发环境
  • 配置事务管理器
  • 开启注解事务
1
<tx:annotation-driven transaction-manager="transactionManager" />
  • 在要加注解的类上加一个@Transactional
    • 要想加属性后边加一个(),按提示写
张冲 wechat
欢迎扫一扫上面的微信关注我,一起交流!
坚持原创技术分享,您的支持将鼓励我继续创,点击打赏!